Skip to content
Snippets Groups Projects
Commit 137889eb authored by dgelessus's avatar dgelessus
Browse files

Add initial support for inspection (Shift-Tab in Jupyter Notebook)

parent 82412e5c
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
`:help` can be used to list all commands, or get help for a specific command. `:help` can be used to list all commands, or get help for a specific command.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help :help
``` ```
%% Output %% Output
Type a valid B expression, or one of the following commands: Type a valid B expression, or one of the following commands:
* `::load` Load the machine source code given in the cell body. * `::load` Load the machine source code given in the cell body.
* `::render` Render some content with the specified MIME type. * `::render` Render some content with the specified MIME type.
* `:assert` Ensure that the predicate is true, and show an error otherwise. * `:assert` Ensure that the predicate is true, and show an error otherwise.
* `:browse` Show information about the current state. * `:browse` Show information about the current state.
* `:check` Check the machine's properties, invariant, or assertions in the current state.
* `:constants` Set up the current machine's constants. * `:constants` Set up the current machine's constants.
* `:dot` Execute and show a dot visualisation. * `:dot` Execute and show a dot visualisation.
* `:eval` Evaluate a formula and display the result. * `:eval` Evaluate a formula and display the result.
* `:exec` Execute an operation with the specified predicate, or by its ID. * `:exec` Execute an operation.
* `:find` Try to find a state for which the given predicate is true (in addition to the machine's invariant).
* `:goto` Go to the state with the specified index in the current trace.
* `:groovy` Evaluate the given Groovy expression. * `:groovy` Evaluate the given Groovy expression.
* `:help` Display help for a specific command, or general help about the REPL. * `:help` Display help for a specific command, or general help about the REPL.
* `:init` Initialise the current machine with the specified predicate * `:init` Initialise the current machine with the specified predicate
* `:load` Load the machine from the given path. * `:load` Load the machine from the given path.
* `:pref` View or change the value of one or more preferences. * `:pref` View or change the value of one or more preferences.
* `:prettyprint` Pretty-print a predicate. * `:prettyprint` Pretty-print a predicate.
* `:show` Show the machine's animation function visualisation for the current state. * `:show` Show the machine's animation function visualisation for the current state.
* `:solve` Solve a predicate with the specified solver. * `:solve` Solve a predicate with the specified solver.
* `:stats` Show statistics about the state space.
* `:table` Display an expression as a table. * `:table` Display an expression as a table.
* `:time` Execute the given command and measure how long it takes to execute. * `:time` Execute the given command and measure how long it takes to execute.
* `:trace` Display all states and transitions in the current trace.
* `:type` Display the type of a formula. * `:type` Display the type of a formula.
* `:version` Display version info about the ProB CLI and ProB 2. * `:version` Display version info about the ProB CLI and ProB 2.
Type a valid B expression, or one of the following commands: Type a valid B expression, or one of the following commands:
::load Load the machine source code given in the cell body. ::load Load the machine source code given in the cell body.
::render Render some content with the specified MIME type. ::render Render some content with the specified MIME type.
:assert Ensure that the predicate is true, and show an error otherwise. :assert Ensure that the predicate is true, and show an error otherwise.
:browse Show information about the current state. :browse Show information about the current state.
:check Check the machine's properties, invariant, or assertions in the current state.
:constants Set up the current machine's constants. :constants Set up the current machine's constants.
:dot Execute and show a dot visualisation. :dot Execute and show a dot visualisation.
:eval Evaluate a formula and display the result. :eval Evaluate a formula and display the result.
:exec Execute an operation with the specified predicate, or by its ID. :exec Execute an operation.
:find Try to find a state for which the given predicate is true (in addition to the machine's invariant).
:goto Go to the state with the specified index in the current trace.
:groovy Evaluate the given Groovy expression. :groovy Evaluate the given Groovy expression.
:help Display help for a specific command, or general help about the REPL. :help Display help for a specific command, or general help about the REPL.
:init Initialise the current machine with the specified predicate :init Initialise the current machine with the specified predicate
:load Load the machine from the given path. :load Load the machine from the given path.
:pref View or change the value of one or more preferences. :pref View or change the value of one or more preferences.
:prettyprint Pretty-print a predicate. :prettyprint Pretty-print a predicate.
:show Show the machine's animation function visualisation for the current state. :show Show the machine's animation function visualisation for the current state.
:solve Solve a predicate with the specified solver. :solve Solve a predicate with the specified solver.
:stats Show statistics about the state space.
:table Display an expression as a table. :table Display an expression as a table.
:time Execute the given command and measure how long it takes to execute. :time Execute the given command and measure how long it takes to execute.
:trace Display all states and transitions in the current trace.
:type Display the type of a formula. :type Display the type of a formula.
:version Display version info about the ProB CLI and ProB 2. :version Display version info about the ProB CLI and ProB 2.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help :help :help :help
``` ```
%% Output %% Output
``` ```
:help [COMMAND] :help [COMMAND]
``` ```
Display help for a specific command, or general help about the REPL. Display help for a specific command, or general help about the REPL.
``` ```
:help [COMMAND] :help [COMMAND]
``` ```
Display help for a specific command, or general help about the REPL. Display help for a specific command, or general help about the REPL.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help :load :help :load
``` ```
%% Output %% Output
``` ```
:load FILENAME [PREF=VALUE ...] :load FILENAME [PREF=VALUE ...]
``` ```
Load the machine from the given path. Load the machine from the given path.
The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located). The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located).
Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded. Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded.
``` ```
:load FILENAME [PREF=VALUE ...] :load FILENAME [PREF=VALUE ...]
``` ```
Load the machine from the given path. Load the machine from the given path.
The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located). The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located).
Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded. Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help ::load :help ::load
``` ```
%% Output %% Output
``` ```
::load [PREF=VALUE ...] ::load [PREF=VALUE ...]
MACHINE MACHINE
... ...
END END
``` ```
Load the machine source code given in the cell body. Load the machine source code given in the cell body.
There must be a newline between the `::load` command name and the machine code. There must be a newline between the `::load` command name and the machine code.
Any number of preference assignments may be included after `::load` (only on the first line). Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded. Any number of preference assignments may be included after `::load` (only on the first line). Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded.
``` ```
::load [PREF=VALUE ...] ::load [PREF=VALUE ...]
MACHINE MACHINE
... ...
END END
``` ```
Load the machine source code given in the cell body. Load the machine source code given in the cell body.
There must be a newline between the `::load` command name and the machine code. There must be a newline between the `::load` command name and the machine code.
Any number of preference assignments may be included after `::load` (only on the first line). Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded. Any number of preference assignments may be included after `::load` (only on the first line). Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
When looking up help for a command, the `:` or `::` can be left off of the command name. When looking up help for a command, the `:` or `::` can be left off of the command name.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help help :help help
``` ```
%% Output %% Output
``` ```
:help [COMMAND] :help [COMMAND]
``` ```
Display help for a specific command, or general help about the REPL. Display help for a specific command, or general help about the REPL.
``` ```
:help [COMMAND] :help [COMMAND]
``` ```
Display help for a specific command, or general help about the REPL. Display help for a specific command, or general help about the REPL.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help load :help load
``` ```
%% Output %% Output
``` ```
:load FILENAME [PREF=VALUE ...] :load FILENAME [PREF=VALUE ...]
``` ```
Load the machine from the given path. Load the machine from the given path.
The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located). The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located).
Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded. Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded.
``` ```
:load FILENAME [PREF=VALUE ...] :load FILENAME [PREF=VALUE ...]
``` ```
Load the machine from the given path. Load the machine from the given path.
The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located). The path is relative to the kernel's current directory (i. e. the directory in which the notebook is located).
Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded. Any number of preference assignments may be included after the file path. Preferences can also be changed on a loaded machine using the `:pref` command, however certain preferences do not take full effect when set using `:pref` and must be set when the machine is loaded.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
But it's not possible to use the wrong number of colons. But it's not possible to use the wrong number of colons.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help ::help :help ::help
``` ```
%% Output %% Output
:help: Cannot display help for unknown command "::help" :help: Cannot display help for unknown command "::help"
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Unknown commands cannot be looked up. Unknown commands cannot be looked up.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help wrong :help wrong
``` ```
%% Output %% Output
:help: Cannot display help for unknown command "wrong" :help: Cannot display help for unknown command "wrong"
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` prob ``` prob
:help :wrong :help :wrong
``` ```
%% Output %% Output
:help: Cannot display help for unknown command ":wrong" :help: Cannot display help for unknown command ":wrong"
......
...@@ -254,6 +254,38 @@ public final class ProBKernel extends BaseKernel { ...@@ -254,6 +254,38 @@ public final class ProBKernel extends BaseKernel {
return this.executeCommand(":eval", expr); return this.executeCommand(":eval", expr);
} }
@Override
public @Nullable DisplayData inspect(final @NotNull String code, final int at, final boolean extraDetail) {
// Note: We ignore the extraDetail parameter, because in practice it is always false. This is because the inspect_request messages sent by Jupyter Notebook always have their detail_level set to 0.
final Matcher commandMatcher = COMMAND_PATTERN.matcher(code);
if (commandMatcher.matches()) {
// The code is a valid command.
final int argOffset = commandMatcher.start(2);
final String name = commandMatcher.group(1);
if (this.getCommands().containsKey(name)) {
final Command command = this.getCommands().get(name);
if (at <= commandMatcher.end(1)) {
// The cursor is somewhere in the command name, show help text for the command.
return command.renderHelp();
} else if (at < commandMatcher.start(2)) {
// The cursor is in the whitespace between the command name and arguments, don't show anything.
return null;
} else {
// The cursor is somewhere in the command arguments, ask the command to inspect.
assert name != null;
final String argString = commandMatcher.group(2) == null ? "" : commandMatcher.group(2);
return command.inspect(argString, at - argOffset);
}
} else {
// Invalid command, can't inspect.
return null;
}
} else {
// The code is not a valid command, ask :eval to inspect.
return this.getCommands().get(":eval").inspect(code, at);
}
}
@Override @Override
public @Nullable ReplacementOptions complete(final @NotNull String code, final int at) { public @Nullable ReplacementOptions complete(final @NotNull String code, final int at) {
final Matcher commandMatcher = COMMAND_PATTERN.matcher(code); final Matcher commandMatcher = COMMAND_PATTERN.matcher(code);
......
...@@ -13,7 +13,35 @@ public interface Command { ...@@ -13,7 +13,35 @@ public interface Command {
public abstract @NotNull String getHelpBody(); public abstract @NotNull String getHelpBody();
public default @NotNull DisplayData renderHelp() {
final StringBuilder sbPlain = new StringBuilder();
final StringBuilder sbMarkdown = new StringBuilder();
sbPlain.append(this.getSyntax());
sbPlain.append('\n');
sbMarkdown.append("```\n");
sbMarkdown.append(this.getSyntax());
sbMarkdown.append("\n```\n\n");
final String shortHelp = this.getShortHelp();
sbPlain.append(shortHelp);
sbMarkdown.append(shortHelp);
final String helpBody = this.getHelpBody();
if (!helpBody.isEmpty()) {
sbPlain.append("\n\n");
sbPlain.append(helpBody);
sbMarkdown.append("\n\n");
sbMarkdown.append(helpBody);
}
final DisplayData result = new DisplayData(sbPlain.toString());
result.putMarkdown(sbMarkdown.toString());
return result;
}
public abstract @Nullable DisplayData run(final @NotNull String argString); public abstract @Nullable DisplayData run(final @NotNull String argString);
public default @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
return null;
}
public abstract @Nullable ReplacementOptions complete(final @NotNull String argString, final int at); public abstract @Nullable ReplacementOptions complete(final @NotNull String argString, final int at);
} }
...@@ -77,19 +77,7 @@ public final class HelpCommand implements Command { ...@@ -77,19 +77,7 @@ public final class HelpCommand implements Command {
if (command == null) { if (command == null) {
throw new UserErrorException(String.format("Cannot display help for unknown command \"%s\"", commandName)); throw new UserErrorException(String.format("Cannot display help for unknown command \"%s\"", commandName));
} }
final StringBuilder sb = new StringBuilder(); return command.renderHelp();
sb.append("```\n");
sb.append(command.getSyntax());
sb.append("\n```\n\n");
sb.append(command.getShortHelp());
final String helpBody = command.getHelpBody();
if (!helpBody.isEmpty()) {
sb.append("\n\n");
sb.append(helpBody);
}
final DisplayData result = new DisplayData(sb.toString());
result.putMarkdown(sb.toString());
return result;
} else { } else {
throw new UserErrorException("Expected at most 1 argument, got " + args.size()); throw new UserErrorException("Expected at most 1 argument, got " + args.size());
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment