diff --git a/src/main/java/de/prob2/jupyter/commands/CommandUtils.java b/src/main/java/de/prob2/jupyter/commands/CommandUtils.java
index d991774764bd61b577e235d0da77b8d0e5e2317e..ab57f2059bb07d98db9a8e43dd9c0d224e4eddc8 100644
--- a/src/main/java/de/prob2/jupyter/commands/CommandUtils.java
+++ b/src/main/java/de/prob2/jupyter/commands/CommandUtils.java
@@ -1,20 +1,28 @@
 package de.prob2.jupyter.commands;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import de.prob.animator.command.CompleteIdentifierCommand;
 import de.prob.animator.domainobjects.AbstractEvalResult;
 import de.prob.animator.domainobjects.ComputationNotCompletedResult;
 import de.prob.animator.domainobjects.EnumerationWarning;
 import de.prob.animator.domainobjects.EvalResult;
 import de.prob.animator.domainobjects.EvaluationErrorResult;
+import de.prob.statespace.Trace;
 import de.prob.unicode.UnicodeTranslator;
 
 import de.prob2.jupyter.UserErrorException;
 
+import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
@@ -23,7 +31,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class CommandUtils {
-	private static final Logger LOGGER = LoggerFactory.getLogger(CommandUtils.class);
+	private static final @NotNull Logger LOGGER = LoggerFactory.getLogger(CommandUtils.class);
+	
+	private static final @NotNull Pattern B_IDENTIFIER_PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9_]*");
+	
+	private CommandUtils() {
+		super();
+		
+		throw new AssertionError("Utility class");
+	}
 	
 	public static @NotNull List<@NotNull String> splitArgs(final @NotNull String args, final int limit) {
 		final String[] split = args.split("\\h+", limit);
@@ -110,4 +126,35 @@ public final class CommandUtils {
 			return result;
 		}
 	}
+	
+	public static @NotNull ReplacementOptions completeInBExpression(final @NotNull Trace trace, final @NotNull String code, final int at) {
+		final Matcher identifierMatcher = B_IDENTIFIER_PATTERN.matcher(code);
+		String identifier = "";
+		int start = at;
+		int end = at;
+		// Try to find the identifier that the cursor is in.
+		// If the cursor is not on an identifier, default to empty string, i. e. show all possible completions.
+		while (identifierMatcher.find() && identifierMatcher.start() < at) {
+			if (identifierMatcher.end() >= at) {
+				identifier = code.substring(identifierMatcher.start(), at);
+				start = identifierMatcher.start();
+				end = identifierMatcher.end();
+				break;
+			}
+		}
+		
+		final CompleteIdentifierCommand cmdExact = new CompleteIdentifierCommand(identifier);
+		cmdExact.setIncludeKeywords(true);
+		trace.getStateSpace().execute(cmdExact);
+		// Use LinkedHashSet to remove duplicates while maintaining order.
+		final Set<String> completions = new LinkedHashSet<>(cmdExact.getCompletions());
+		
+		final CompleteIdentifierCommand cmdIgnoreCase = new CompleteIdentifierCommand(identifier);
+		cmdIgnoreCase.setIgnoreCase(true);
+		cmdIgnoreCase.setIncludeKeywords(true);
+		trace.getStateSpace().execute(cmdIgnoreCase);
+		completions.addAll(cmdIgnoreCase.getCompletions());
+		
+		return new ReplacementOptions(new ArrayList<>(completions), start, end);
+	}
 }
diff --git a/src/main/java/de/prob2/jupyter/commands/EvalCommand.java b/src/main/java/de/prob2/jupyter/commands/EvalCommand.java
index 6b98fec5e1dc743e3b2b6a9aa08b1bec75269759..4b915f5dc7e82634e67bed9adb35d9116774e1a0 100644
--- a/src/main/java/de/prob2/jupyter/commands/EvalCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/EvalCommand.java
@@ -7,6 +7,7 @@ import de.prob.statespace.AnimationSelector;
 
 import de.prob2.jupyter.ProBKernel;
 
+import io.github.spencerpark.jupyter.kernel.ReplacementOptions;
 import io.github.spencerpark.jupyter.kernel.display.DisplayData;
 
 import org.jetbrains.annotations.NotNull;
@@ -35,4 +36,9 @@ public final class EvalCommand implements Command {
 	public @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String argString) {
 		return CommandUtils.displayDataForEvalResult(this.animationSelector.getCurrentTrace().evalCurrent(argString, FormulaExpand.EXPAND));
 	}
+	
+	@Override
+	public @NotNull ReplacementOptions complete(final @NotNull ProBKernel kernel, final @NotNull String argString, final int at) {
+		return CommandUtils.completeInBExpression(this.animationSelector.getCurrentTrace(), argString, at);
+	}
 }