mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-04 08:30:39 +00:00
feat(backend): Add tab completion to server console command arguments
A command can optionally define a `completer(args)` function. It takes an array of strings for the current arguments, and returns an array of completion results for the last argument. Includes a few completers: - alarm:info/clear/inspect completes the first argument as an alarm id or short_id - script:run completes the first argument as a script name - params:get/set completes the first argument as a parameter name
This commit is contained in:
@@ -37,6 +37,13 @@ class Command {
|
||||
log.error(err.stack);
|
||||
}
|
||||
}
|
||||
|
||||
completeArgument(args) {
|
||||
const completer = this.spec_.completer;
|
||||
if ( completer )
|
||||
return completer(args);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class CommandService extends BaseService {
|
||||
@@ -87,6 +94,10 @@ class CommandService extends BaseService {
|
||||
get commandNames() {
|
||||
return this.commands_.map(command => command.id);
|
||||
}
|
||||
|
||||
getCommand(id) {
|
||||
return this.commands_.find(command => command.id === id);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -132,9 +132,13 @@ class DevConsoleService extends BaseService {
|
||||
prompt: 'puter> ',
|
||||
terminal: true,
|
||||
completer: line => {
|
||||
// We only complete service and command names
|
||||
if ( line.includes(' ') )
|
||||
return;
|
||||
if ( line.includes(' ') ) {
|
||||
const [ commandName, ...args ] = line.split(/\s+/);
|
||||
const command = commands.getCommand(commandName);
|
||||
if (!command)
|
||||
return;
|
||||
return [ command.completeArgument(args), args[args.length - 1] ];
|
||||
}
|
||||
|
||||
const results = commands.commandNames
|
||||
.filter(name => name.startsWith(line))
|
||||
|
||||
@@ -68,6 +68,17 @@ class ParameterService extends BaseService {
|
||||
}
|
||||
|
||||
_registerCommands (commands) {
|
||||
const completeParameterName = (args) => {
|
||||
// The parameter name is the first argument, so return no results if we're on the second or later.
|
||||
if (args.length > 1)
|
||||
return;
|
||||
const lastArg = args[args.length - 1];
|
||||
|
||||
return this.parameters_
|
||||
.map(parameter => parameter.spec_.id)
|
||||
.filter(parameterName => parameterName.startsWith(lastArg));
|
||||
};
|
||||
|
||||
commands.registerCommands('params', [
|
||||
{
|
||||
id: 'get',
|
||||
@@ -76,7 +87,8 @@ class ParameterService extends BaseService {
|
||||
const [name] = args;
|
||||
const value = await this.get(name);
|
||||
log.log(value);
|
||||
}
|
||||
},
|
||||
completer: completeParameterName,
|
||||
},
|
||||
{
|
||||
id: 'set',
|
||||
@@ -86,7 +98,8 @@ class ParameterService extends BaseService {
|
||||
const parameter = this._get_param(name);
|
||||
parameter.set(value);
|
||||
log.log(value);
|
||||
}
|
||||
},
|
||||
completer: completeParameterName,
|
||||
},
|
||||
{
|
||||
id: 'list',
|
||||
|
||||
@@ -31,6 +31,16 @@ class ScriptService extends BaseService {
|
||||
return;
|
||||
}
|
||||
await script.run(ctx, args);
|
||||
},
|
||||
completer: (args) => {
|
||||
// The script name is the first argument, so return no results if we're on the second or later.
|
||||
if (args.length > 1)
|
||||
return;
|
||||
const scriptName = args[args.length - 1];
|
||||
|
||||
return this.scripts
|
||||
.filter(script => scriptName.startsWith(scriptName))
|
||||
.map(script => script.name);
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -308,6 +308,24 @@ class AlarmService extends BaseService {
|
||||
}
|
||||
|
||||
_register_commands (commands) {
|
||||
const completeAlarmID = (args) => {
|
||||
// The alarm ID is the first argument, so return no results if we're on the second or later.
|
||||
if (args.length > 1)
|
||||
return;
|
||||
const lastArg = args[args.length - 1];
|
||||
|
||||
const results = [];
|
||||
for ( const alarm of Object.values(this.alarms) ) {
|
||||
if ( alarm.id.startsWith(lastArg) ) {
|
||||
results.push(alarm.id);
|
||||
}
|
||||
if ( alarm.short_id?.startsWith(lastArg) ) {
|
||||
results.push(alarm.short_id);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
commands.registerCommands('alarm', [
|
||||
{
|
||||
id: 'list',
|
||||
@@ -341,7 +359,8 @@ class AlarmService extends BaseService {
|
||||
for ( const [key, value] of Object.entries(alarm.fields) ) {
|
||||
log.log(`- ${key}: ${util.inspect(value)}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
completer: completeAlarmID,
|
||||
},
|
||||
{
|
||||
id: 'clear',
|
||||
@@ -356,7 +375,8 @@ class AlarmService extends BaseService {
|
||||
);
|
||||
}
|
||||
this.clear(id);
|
||||
}
|
||||
},
|
||||
completer: completeAlarmID,
|
||||
},
|
||||
{
|
||||
id: 'clear-all',
|
||||
@@ -397,7 +417,8 @@ class AlarmService extends BaseService {
|
||||
log.log("┃ " + stringify_log_entry(lg));
|
||||
}
|
||||
log.log(`┗━━ Logs before: ${alarm.id_string} ━━━━`);
|
||||
}
|
||||
},
|
||||
completer: completeAlarmID,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user