Skip to content

Commit c8a60c3

Browse files
committed
refactor(cli): organize commands by resource
Replace the ad-hoc top-level verbs (/cb scripts, /cb tasks, /cb list, /cb ping) with a resource-based tree: /cb script list | show <name> [group] | enable <name> | disable <name> /cb task list | clear <id> /cb client list | ping [id] | players <id> /cb config show [section] | reload /cb script show <name> renders an overview (kvs + clickable group list); /cb script show <name> <group> drills into one group rendered through DebugPrinter's YAML card so chat and console share the same shape. /cb config show mirrors this: leaves as Summary, nested records as a clickable Sections list, deep view via DebugPrinter. Drop redundant show variants: /cb task show and /cb client show printed the same information their list views already convey. Drop the [Enable]/[Disable] action button on /cb script show — there is a dedicated subcommand for it. Strip the trailing [show] click from task and client list items since there is no longer a per-item detail page. ScriptManager gains setEnabled(name, target) which regex-edits the `enabled:` line of the matching YAML file in place (preserving comments and formatting) and triggers a reload. ScheduleManager gains findById/removeById; clearByPlayer is dropped (now unused). Every argument-taking subcommand wires replaceSuggestions to a live source (scripts, tasks, clients, config keys, script groups).
1 parent 0e1dfb2 commit c8a60c3

13 files changed

Lines changed: 1089 additions & 970 deletions

File tree

velocity/src/main/java/dev/objz/commandbridge/velocity/Main.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ public void onProxyInitialization(ProxyInitializeEvent e) {
234234
cfg,
235235
dataDir,
236236
commandEntry,
237-
userCache);
237+
userCache,
238+
playerTracker);
238239
command.register();
239240

240241
CommandBridgeProvider.register(api);

velocity/src/main/java/dev/objz/commandbridge/velocity/ScriptManager.java

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,30 @@
88
import dev.objz.commandbridge.scripting.platform.PlatformFeatures;
99

1010
import java.io.IOException;
11+
import java.nio.charset.StandardCharsets;
1112
import java.nio.file.Files;
1213
import java.nio.file.Path;
1314
import java.util.ArrayList;
15+
import java.util.HashMap;
1416
import java.util.List;
1517
import java.util.Locale;
18+
import java.util.Map;
19+
import java.util.Optional;
20+
import java.util.regex.Matcher;
21+
import java.util.regex.Pattern;
1622
import java.util.stream.Stream;
1723

1824
public final class ScriptManager {
25+
26+
private static final Pattern ENABLED_LINE = Pattern.compile(
27+
"(?m)^enabled:[ \\t]*(true|false)([ \\t]*(#.*)?)$");
28+
private static final Pattern VERSION_LINE = Pattern.compile("(?m)^version:[ \\t]*.*$");
29+
1930
private final Path scriptsDir;
2031
private final PlatformFeatures platformFeatures;
2132

33+
private final Map<String, Path> filesByName = new HashMap<>();
34+
2235
private volatile List<Script> loaded = List.of();
2336
private volatile List<Script> enabled = List.of();
2437
private volatile List<Script> disabled = List.of();
@@ -39,6 +52,7 @@ public void loadAll(boolean logSummary) {
3952
List<Script> newLoaded = new ArrayList<>();
4053
List<Script> newEnabled = new ArrayList<>();
4154
List<Script> newDisabled = new ArrayList<>();
55+
Map<String, Path> newFiles = new HashMap<>();
4256
long newErrors = 0;
4357

4458
try {
@@ -65,6 +79,9 @@ public void loadAll(boolean logSummary) {
6579
Log.debug("Loaded script '{}' from '{}' (enabled={}, commands={})",
6680
res.value.name(), p.getFileName(), res.value.enabled(),
6781
res.value.commands() != null ? res.value.commands().size() : 0);
82+
if (res.value.name() != null) {
83+
newFiles.put(res.value.name(), p);
84+
}
6885
if (res.value.enabled())
6986
newEnabled.add(res.value);
7087
else
@@ -84,6 +101,10 @@ public void loadAll(boolean logSummary) {
84101
this.loaded = List.copyOf(newLoaded);
85102
this.enabled = List.copyOf(newEnabled);
86103
this.disabled = List.copyOf(newDisabled);
104+
synchronized (filesByName) {
105+
filesByName.clear();
106+
filesByName.putAll(newFiles);
107+
}
87108
this.errors = newErrors;
88109

89110
if (logSummary) {
@@ -111,6 +132,100 @@ public Path scriptsDir() {
111132
return scriptsDir;
112133
}
113134

135+
public Optional<Script> findByName(String name) {
136+
if (name == null || name.isBlank()) {
137+
return Optional.empty();
138+
}
139+
for (Script s : loaded) {
140+
if (s != null && name.equalsIgnoreCase(s.name())) {
141+
return Optional.of(s);
142+
}
143+
}
144+
return Optional.empty();
145+
}
146+
147+
public Optional<Path> filePathOf(String name) {
148+
if (name == null) {
149+
return Optional.empty();
150+
}
151+
synchronized (filesByName) {
152+
return Optional.ofNullable(filesByName.get(name));
153+
}
154+
}
155+
156+
public ToggleResult setEnabled(String name, boolean target) {
157+
Optional<Path> pathOpt = filePathOf(name);
158+
if (pathOpt.isEmpty()) {
159+
return ToggleResult.notFound();
160+
}
161+
Path file = pathOpt.get();
162+
163+
String original;
164+
try {
165+
original = Files.readString(file, StandardCharsets.UTF_8);
166+
} catch (IOException e) {
167+
Log.error(e, "Failed to read script file '{}': {}", file, e.getMessage());
168+
return ToggleResult.ioError(e.getMessage());
169+
}
170+
171+
String desired = String.valueOf(target);
172+
Matcher m = ENABLED_LINE.matcher(original);
173+
String updated;
174+
if (m.find()) {
175+
if (desired.equals(m.group(1))) {
176+
return ToggleResult.unchanged();
177+
}
178+
String trailing = m.group(2) != null ? m.group(2) : "";
179+
String replacement = "enabled: " + desired + trailing;
180+
updated = original.substring(0, m.start())
181+
+ replacement
182+
+ original.substring(m.end());
183+
} else {
184+
Matcher v = VERSION_LINE.matcher(original);
185+
String insertion = "enabled: " + desired + System.lineSeparator();
186+
if (v.find()) {
187+
int insertAt = v.end();
188+
String after = original.substring(insertAt);
189+
String prefix = after.startsWith("\n") || after.startsWith("\r") ? "" : System.lineSeparator();
190+
updated = original.substring(0, insertAt) + prefix + insertion + after;
191+
} else {
192+
updated = insertion + original;
193+
}
194+
}
195+
196+
try {
197+
Files.writeString(file, updated, StandardCharsets.UTF_8);
198+
} catch (IOException e) {
199+
Log.error(e, "Failed to write script file '{}': {}", file, e.getMessage());
200+
return ToggleResult.ioError(e.getMessage());
201+
}
202+
203+
loadAll(false);
204+
return ToggleResult.changed();
205+
}
206+
207+
public enum ToggleStatus {
208+
CHANGED, UNCHANGED, NOT_FOUND, IO_ERROR
209+
}
210+
211+
public record ToggleResult(ToggleStatus status, String error) {
212+
public static ToggleResult changed() {
213+
return new ToggleResult(ToggleStatus.CHANGED, null);
214+
}
215+
216+
public static ToggleResult unchanged() {
217+
return new ToggleResult(ToggleStatus.UNCHANGED, null);
218+
}
219+
220+
public static ToggleResult notFound() {
221+
return new ToggleResult(ToggleStatus.NOT_FOUND, null);
222+
}
223+
224+
public static ToggleResult ioError(String message) {
225+
return new ToggleResult(ToggleStatus.IO_ERROR, message);
226+
}
227+
}
228+
114229
private static boolean isYaml(Path p) {
115230
if (!Files.isRegularFile(p))
116231
return false;

0 commit comments

Comments
 (0)