diff --git a/src/main/java/de/prob2/jupyter/commands/AssertCommand.java b/src/main/java/de/prob2/jupyter/commands/AssertCommand.java
index b77cb0c194c6d1f2be33ea9155944630e0a94b0f..68a7588b1915b8e5421e35a0712748616797ce96 100644
--- a/src/main/java/de/prob2/jupyter/commands/AssertCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/AssertCommand.java
@@ -14,6 +14,7 @@ import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 import io.github.spencerpark.jupyter.kernel.display.mime.MIMEType;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class AssertCommand implements Command {
 	private final @NotNull AnimationSelector animationSelector;
@@ -58,6 +59,11 @@ public final class AssertCommand implements Command {
 		throw new UserErrorException("Assertion is not true: " + displayData.getData(MIMEType.TEXT_PLAIN));
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/CommandUtils.java b/src/main/java/de/prob2/jupyter/commands/CommandUtils.java
index 0dbdbf1f83b19a6035ee5d6a65bbd405818057f0..fce3cd2c445011e05a6afa6012c14ba78da37630 100644
--- a/src/main/java/de/prob2/jupyter/commands/CommandUtils.java
+++ b/src/main/java/de/prob2/jupyter/commands/CommandUtils.java
@@ -41,8 +41,14 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class CommandUtils {
+	@FunctionalInterface
+	public interface Inspector {
+		public abstract @Nullable DisplayData inspect(final @NotNull String argString, final int at);
+	}
+	
+	@FunctionalInterface
 	public interface Completer {
-		public abstract @Nullable ReplacementOptions complete(final @NotNull String argString, final int offset);
+		public abstract @Nullable ReplacementOptions complete(final @NotNull String argString, final int at);
 	}
 	
 	private static final @NotNull Logger LOGGER = LoggerFactory.getLogger(CommandUtils.class);
@@ -227,6 +233,22 @@ public final class CommandUtils {
 		);
 	}
 	
+	public static @Nullable DisplayData inspectArgs(final @NotNull String argString, final int at, final @NotNull Inspector @NotNull... inspectors) {
+		final Matcher argSplitMatcher = ARG_SPLIT_PATTERN.matcher(argString);
+		int argStart = 0;
+		int argEnd = argString.length();
+		int i = 0;
+		while (argSplitMatcher.find() && i < inspectors.length) {
+			if (argSplitMatcher.end() > at) {
+				argEnd = argSplitMatcher.start();
+				break;
+			}
+			argStart = argSplitMatcher.end();
+			i++;
+		}
+		return inspectors[i].inspect(argString.substring(argStart, argEnd), at - argStart);
+	}
+	
 	public static @Nullable ReplacementOptions completeArgs(final @NotNull String argString, final int at, final @NotNull Completer @NotNull... completers) {
 		final Matcher argSplitMatcher = ARG_SPLIT_PATTERN.matcher(argString);
 		int argStart = 0;
@@ -298,6 +320,10 @@ public final class CommandUtils {
 		return result;
 	}
 	
+	public static @NotNull Inspector bExpressionInspector(final @NotNull Trace trace) {
+		return (code, at) -> inspectInBExpression(trace, code, at);
+	}
+	
 	public static @NotNull ReplacementOptions completeInBExpression(final @NotNull Trace trace, final @NotNull String code, final int at) {
 		final Matcher identifierMatcher = matchBIdentifierAt(code, at);
 		// Try to find the identifier that the cursor is in.
diff --git a/src/main/java/de/prob2/jupyter/commands/ConstantsCommand.java b/src/main/java/de/prob2/jupyter/commands/ConstantsCommand.java
index 8dbbacca5ed7c2988114b122c32f478b1eeee8ea..9532f6443f4560f02051fb8c1747259f55e9fcee 100644
--- a/src/main/java/de/prob2/jupyter/commands/ConstantsCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/ConstantsCommand.java
@@ -14,6 +14,7 @@ import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class ConstantsCommand implements Command {
 	private final @NotNull AnimationSelector animationSelector;
@@ -52,6 +53,11 @@ public final class ConstantsCommand implements Command {
 		return new DisplayData(String.format("Machine constants set up using operation %s: %s", op.getId(), op.getRep()));
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/DotCommand.java b/src/main/java/de/prob2/jupyter/commands/DotCommand.java
index 6b2aecafcc9125c520d0e20ec806c8a4e57f1aa3..989ccf9522b5e900db0b5b497037fd2ccaf7e7a9 100644
--- a/src/main/java/de/prob2/jupyter/commands/DotCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/DotCommand.java
@@ -117,6 +117,15 @@ public final class DotCommand implements Command {
 		return result;
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectArgs(
+			argString, at,
+			(commandName, at0) -> null, // TODO
+			CommandUtils.bExpressionInspector(this.animationSelector.getCurrentTrace())
+		);
+	}
+	
 	@Override
 	public @Nullable ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeArgs(
diff --git a/src/main/java/de/prob2/jupyter/commands/ExecCommand.java b/src/main/java/de/prob2/jupyter/commands/ExecCommand.java
index ed7f52fe5bc96e23b4459a9e224f174f90ac195f..9ebd093da728f00624e6fb7a73dafb9222a3613d 100644
--- a/src/main/java/de/prob2/jupyter/commands/ExecCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/ExecCommand.java
@@ -59,6 +59,15 @@ public final class ExecCommand implements Command {
 		return new DisplayData(String.format("Executed operation: %s", op.getRep()));
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectArgs(
+			argString, at,
+			(operation, at0) -> null, // TODO
+			CommandUtils.bExpressionInspector(this.animationSelector.getCurrentTrace())
+		);
+	}
+	
 	@Override
 	public @Nullable ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeArgs(
diff --git a/src/main/java/de/prob2/jupyter/commands/FindCommand.java b/src/main/java/de/prob2/jupyter/commands/FindCommand.java
index 03cbfd3f52f6bc39468bcac97908673ebae55e9f..09e0bb8a4d72d1b379a19a93d74360ff8a84969a 100644
--- a/src/main/java/de/prob2/jupyter/commands/FindCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/FindCommand.java
@@ -11,6 +11,7 @@ import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class FindCommand implements Command {
 	private final @NotNull AnimationSelector animationSelector;
@@ -48,6 +49,11 @@ public final class FindCommand implements Command {
 		return new DisplayData("Found a matching state and made it current state");
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/InitialiseCommand.java b/src/main/java/de/prob2/jupyter/commands/InitialiseCommand.java
index 33c1f55694853de909e1dea442b830f99c2b0b2b..3ec63d9c39bb0cf42d31406823859db82f615af6 100644
--- a/src/main/java/de/prob2/jupyter/commands/InitialiseCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/InitialiseCommand.java
@@ -14,6 +14,7 @@ import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class InitialiseCommand implements Command {
 	private final @NotNull AnimationSelector animationSelector;
@@ -52,6 +53,11 @@ public final class InitialiseCommand implements Command {
 		return new DisplayData(String.format("Machine initialised using operation %s: %s", op.getId(), op.getRep()));
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java b/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java
index 921374446155c61016862f2a67f9fb295fded30a..0727356199b529763371d5842c4bcb2369776678 100644
--- a/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java
@@ -62,6 +62,18 @@ public final class LoadCellCommand implements Command {
 		return new DisplayData("Loaded machine: " + this.animationSelector.getCurrentTrace().getStateSpace().getMainComponent());
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		final int newlinePos = argString.indexOf('\n');
+		if (newlinePos == -1 || at < newlinePos) {
+			// Cursor is on the first line, provide preference inspections.
+			return null; // TODO
+		} else {
+			// Cursor is in the body, provide B inspections.
+			return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+		}
+	}
+	
 	@Override
 	public @Nullable ReplacementOptions complete(final @NotNull String argString, final int at) {
 		final int newlinePos = argString.indexOf('\n');
diff --git a/src/main/java/de/prob2/jupyter/commands/PrettyPrintCommand.java b/src/main/java/de/prob2/jupyter/commands/PrettyPrintCommand.java
index 33c2a2df90f0e0722f680c041009489d812d7f39..118eed3c5da9c34c9a4555e69475adb391489108 100644
--- a/src/main/java/de/prob2/jupyter/commands/PrettyPrintCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/PrettyPrintCommand.java
@@ -11,6 +11,7 @@ import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class PrettyPrintCommand implements Command {
 	private final AnimationSelector animationSelector;
@@ -53,6 +54,11 @@ public final class PrettyPrintCommand implements Command {
 		return ret;
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/SolveCommand.java b/src/main/java/de/prob2/jupyter/commands/SolveCommand.java
index da3e5852044cb9e488933197d1a68aad548f5e68..b12b289e3695daca70fd0c656b8ebaae9c2a1b4e 100644
--- a/src/main/java/de/prob2/jupyter/commands/SolveCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/SolveCommand.java
@@ -75,6 +75,15 @@ public final class SolveCommand implements Command {
 		return CommandUtils.displayDataForEvalResult(cmd.getValue());
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectArgs(
+			argString, at,
+			(solverName, at0) -> null, // TODO
+			CommandUtils.bExpressionInspector(this.animationSelector.getCurrentTrace())
+		);
+	}
+	
 	@Override
 	public @Nullable ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeArgs(
diff --git a/src/main/java/de/prob2/jupyter/commands/TableCommand.java b/src/main/java/de/prob2/jupyter/commands/TableCommand.java
index 494fe0538b770e56bac67f4e388a80507182ab8f..1043cf3d1c780f98549501f6fe82bbf605f35598 100644
--- a/src/main/java/de/prob2/jupyter/commands/TableCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/TableCommand.java
@@ -20,6 +20,7 @@ import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class TableCommand implements Command {
 	private final @NotNull AnimationSelector animationSelector;
@@ -87,6 +88,11 @@ public final class TableCommand implements Command {
 		return res;
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/TimeCommand.java b/src/main/java/de/prob2/jupyter/commands/TimeCommand.java
index 7ce190214037788c65fd4ecf43ba97594a6fd0f9..2bff95befed87024d304f6ff3f918aec6a5a0f7b 100644
--- a/src/main/java/de/prob2/jupyter/commands/TimeCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/TimeCommand.java
@@ -53,6 +53,11 @@ public final class TimeCommand implements Command {
 		return result;
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return this.injector.getInstance(ProBKernel.class).inspect(argString, at, false);
+	}
+	
 	@Override
 	public @Nullable ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return this.injector.getInstance(ProBKernel.class).complete(argString, at);
diff --git a/src/main/java/de/prob2/jupyter/commands/TypeCommand.java b/src/main/java/de/prob2/jupyter/commands/TypeCommand.java
index fcb3d264474a381f898a6ff1b190b92bd062badc..6474646c49311f72e0c49fa6fff915a1851c58cb 100644
--- a/src/main/java/de/prob2/jupyter/commands/TypeCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/TypeCommand.java
@@ -13,6 +13,7 @@ import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public final class TypeCommand implements Command {
 	private final @NotNull AnimationSelector animationSelector;
@@ -51,6 +52,11 @@ public final class TypeCommand implements Command {
 		}
 	}
 	
+	@Override
+	public @Nullable DisplayData inspect(final @NotNull String argString, final int at) {
+		return CommandUtils.inspectInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
+	
 	@Override
 	public @NotNull ReplacementOptions complete(final @NotNull String argString, final int at) {
 		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);