Overview
The REPL mode provides interactive code evaluation capabilities within the Zep editor. It allows users to evaluate expressions, sub-expressions, and entire buffers in supported programming languages through a pluggable provider interface.
REPL mode requires implementing the IZepReplProvider interface for your specific language or environment.
REPL Provider Interface
IZepReplProvider
Interface for implementing language-specific REPL functionality.
ReplParse (Buffer-based)
virtual std::string ReplParse(
ZepBuffer& text,
const GlyphIterator& cursorOffset,
ReplParseType type
)
Parses and evaluates code from a buffer.
The buffer containing the code to evaluate
cursorOffset
const GlyphIterator&
required
Current cursor position in the buffer
Type of parsing to perform (SubExpression, OuterExpression, Line, All)
Returns: String containing the evaluation result
ReplParse (String-based)
virtual std::string ReplParse(const std::string& text)
Parses and evaluates a code string.
text
const std::string&
required
The code string to evaluate
Returns: String containing the evaluation result
virtual bool ReplIsFormComplete(const std::string& input, int& depth)
Checks if the input represents a complete expression.
input
const std::string&
required
The input string to check
Output parameter for nesting depth (e.g., unclosed parentheses count)
Returns: true if the expression is complete, false if more input is needed
This method is useful for multi-line input, determining when to evaluate versus waiting for more input.
Parse Types
enum class ReplParseType
{
SubExpression, // Evaluate the innermost expression at cursor
OuterExpression, // Evaluate the outermost expression containing cursor
Line, // Evaluate the current line
All // Evaluate the entire buffer
}
REPL Commands
The REPL system provides several Ex commands for evaluation:
ZepReplExCommand
class ZepReplExCommand : public ZepExCommand
Main REPL command that opens an interactive REPL window.
Constructor
ZepReplExCommand(ZepEditor& editor, IZepReplProvider* pProvider)
Reference to the editor instance
pProvider
IZepReplProvider*
required
Pointer to the REPL provider implementation
Register
static void Register(ZepEditor& editor, IZepReplProvider* pProvider)
Registers the REPL command with the editor.
ExCommandName
virtual const char* ExCommandName() const override
Returns: "ZRepl" - Use :ZRepl in Ex mode to open the REPL
ZepReplEvaluateCommand
class ZepReplEvaluateCommand : public ZepExCommand
Evaluates the current line or selection.
Ex Command: :ZReplEval
ZepReplEvaluateInnerCommand
class ZepReplEvaluateInnerCommand : public ZepExCommand
Evaluates the innermost expression at the cursor position.
Ex Command: :ZReplEvalInner
ZepReplEvaluateOuterCommand
class ZepReplEvaluateOuterCommand : public ZepExCommand
Evaluates the outermost expression containing the cursor.
Ex Command: :ZReplEvalOuter
Usage Example
Implementing a Python REPL Provider
#include <zep/mode_repl.h>
#include <Python.h>
class PythonReplProvider : public IZepReplProvider
{
public:
std::string ReplParse(const std::string& code) override
{
// Initialize Python if needed
if (!Py_IsInitialized()) {
Py_Initialize();
}
// Evaluate Python code
PyObject* result = PyRun_String(
code.c_str(),
Py_eval_input,
m_globals,
m_locals
);
if (result) {
PyObject* str = PyObject_Str(result);
const char* cstr = PyUnicode_AsUTF8(str);
std::string output(cstr);
Py_DECREF(str);
Py_DECREF(result);
return output;
}
// Handle errors
PyErr_Print();
return "Error evaluating expression";
}
std::string ReplParse(
ZepBuffer& buffer,
const GlyphIterator& cursor,
ReplParseType type
) override
{
// Extract relevant code based on type
std::string code;
switch (type) {
case ReplParseType::Line:
code = GetLineAtCursor(buffer, cursor);
break;
case ReplParseType::All:
code = buffer.GetText();
break;
// Handle other types...
}
return ReplParse(code);
}
bool ReplIsFormComplete(const std::string& input, int& depth) override
{
depth = 0;
// Count open brackets/parens
for (char c : input) {
if (c == '(' || c == '[' || c == '{') depth++;
if (c == ')' || c == ']' || c == '}') depth--;
}
return depth == 0;
}
private:
PyObject* m_globals = PyDict_New();
PyObject* m_locals = PyDict_New();
std::string GetLineAtCursor(ZepBuffer& buffer, const GlyphIterator& cursor)
{
// Implementation to extract line
return "";
}
};
Registering and Using the REPL
#include <zep/editor.h>
#include <zep/mode_repl.h>
int main()
{
// Create editor
auto editor = std::make_unique<ZepEditor>(display);
// Create REPL provider
auto pythonRepl = std::make_unique<PythonReplProvider>();
// Register REPL commands
ZepReplExCommand::Register(*editor, pythonRepl.get());
ZepReplEvaluateCommand::Register(*editor, pythonRepl.get());
ZepReplEvaluateInnerCommand::Register(*editor, pythonRepl.get());
ZepReplEvaluateOuterCommand::Register(*editor, pythonRepl.get());
// Now users can use REPL commands:
// :ZRepl - Open interactive REPL
// :ZReplEval - Evaluate current line
// :ZReplEvalInner - Evaluate inner expression
// :ZReplEvalOuter - Evaluate outer expression
return 0;
}
Interactive REPL Session
# In the editor, type Python code:
x = 10
y = 20
# Execute :ZReplEval to evaluate
# Result appears in REPL buffer:
# >>> x = 10
# >>> y = 20
# Evaluate expressions:
x + y
# Execute :ZReplEval
# >>> x + y
# 30
# Or open full REPL with :ZRepl
# >>> _
Lisp/Scheme Example
class SchemeReplProvider : public IZepReplProvider
{
public:
std::string ReplParse(const std::string& code) override
{
// Integrate with Scheme interpreter
return m_interpreter.Eval(code);
}
bool ReplIsFormComplete(const std::string& input, int& depth) override
{
depth = 0;
bool inString = false;
for (size_t i = 0; i < input.length(); i++) {
char c = input[i];
// Handle string literals
if (c == '"' && (i == 0 || input[i-1] != '\\')) {
inString = !inString;
continue;
}
if (!inString) {
if (c == '(') depth++;
if (c == ')') depth--;
}
}
// Complete if all parens are balanced
return depth == 0 && !inString;
}
private:
SchemeInterpreter m_interpreter;
};
Key Bindings Example
// Add custom key bindings for REPL evaluation
void SetupReplKeyBindings(ZepMode& mode)
{
// Ctrl+Enter to evaluate current line
mode.GetKeyMap(EditorMode::Insert).AddKeyMap(
ExtKeys::RETURN,
ModifierKey::Ctrl,
StringId("ZReplEval")
);
// Ctrl+Shift+Enter to evaluate outer expression
mode.GetKeyMap(EditorMode::Insert).AddKeyMap(
ExtKeys::RETURN,
ModifierKey::Ctrl | ModifierKey::Shift,
StringId("ZReplEvalOuter")
);
}
The REPL system is designed for live coding environments where immediate feedback is valuable, such as game development, data analysis, or interactive programming tutorials.
See Also