Skip to content

Commit 2c9444d

Browse files
committed
Fix Repl
1 parent 9bc7c98 commit 2c9444d

File tree

7 files changed

+68
-53
lines changed

7 files changed

+68
-53
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
Zep is a simple embeddable editor, with a rendering agnostic design and optional Vim mode. It is built as a shared modern-cmake library. The core library is dependency-free (the demo application requires an installed package), and it is possible just to copy the files into your project and build it. Out of the box Zep can draw to a Qt Widget or an an ImGui window - useful for embedding in a game engine. A simple syntax highlighting engine is provided, and can easily be extended. Basic theming support is included, and window tabs and vertical/horizontal splits are also available. Zep is 'opinionated' in how it does things, but is easy to modify and supports many common features. It is heavliy influenced by Vim, but has a good notepad-style editing mode too. A simple search feature (Ctrl+P) is a powerful way to find things, and a Repl mode is useful for implementing a console for game scripting. Intended to eventually sit inside a live-coding environment, Zep also has a minimal mode and several configuration options which can be set in a simple toml-format file.
1111

12+
## Video Overview
13+
[![Zep Overview](screenshots/video.png)](https://www.youtube.com/watch?v=5u2hjO-7z4M "Zep Overview")
14+
15+
## Screenshot
1216
![ImGui](screenshots/sample.png)
1317

1418
Zep supports the standard editing keystrokes you'll find in most editors, along with a reasonable subset of modal Vim editing as an option. The demo project lets you switch between the editing modes on the fly. Zep is not meant to replace Vim. I don't have a lifetime spare to write that, but it has most of the functionality I use day to day, and anything missing gets added over time. A keymapper enables configuration of Zep outside the standard modes offered.

extensions/repl/mode_repl.cpp

+31-52
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,13 @@ void ZepReplExCommand::Run(const std::vector<std::string>& tokens)
112112
}
113113

114114
// TODO: Modifiable but not saveable buffer
115-
m_pReplBuffer = GetEditor().GetEmptyBuffer("Repl.lisp");// , FileFlags::ReadOnly);
115+
m_pReplBuffer = GetEditor().GetEmptyBuffer("Repl.lisp"); // , FileFlags::ReadOnly);
116116
m_pReplBuffer->SetBufferType(BufferType::Repl);
117117
m_pReplBuffer->GetSyntax()->IgnoreLineHighlight();
118+
m_pReplBuffer->SetPostKeyNotifier([&](uint32_t key, uint32_t modifier)
119+
{
120+
return AddKeyPress(key, modifier);
121+
});
118122

119123
// Adding the window will make it active and begin the mode
120124
m_pReplWindow = GetEditor().GetActiveTabWindow()->AddWindow(m_pReplBuffer, nullptr, RegionLayoutType::VBox);
@@ -123,7 +127,7 @@ void ZepReplExCommand::Run(const std::vector<std::string>& tokens)
123127

124128
void ZepReplExCommand::Prompt()
125129
{
126-
// TODO: Repl broken, but when not, need to consider undo
130+
// TODO: Repl broken, but when not, need to consider undo
127131
ChangeRecord changeRecord;
128132
m_pReplBuffer->Insert(m_pReplBuffer->End(), PromptString, changeRecord);
129133
MoveToEnd();
@@ -132,39 +136,24 @@ void ZepReplExCommand::Prompt()
132136
void ZepReplExCommand::MoveToEnd()
133137
{
134138
m_pReplWindow->SetBufferCursor(m_pReplBuffer->End());
135-
//m_startLocation = m_pCurrentWindow->GetBufferCursor();
139+
m_startLocation = m_pReplWindow->GetBufferCursor();
136140
}
137141

138-
void ZepReplExCommand::Notify(std::shared_ptr<ZepMessage> message)
139-
{
140142

141-
if (message->messageId == Msg::Buffer)
143+
bool ZepReplExCommand::AddKeyPress(uint32_t key, uint32_t modifiers)
144+
{
145+
(void)&modifiers;
146+
if (key == ExtKeys::RETURN)
142147
{
143-
auto spBufferMsg = std::static_pointer_cast<BufferMessage>(message);
144-
if (spBufferMsg->pBuffer == m_pReplBuffer)
148+
ChangeRecord record;
149+
auto& buffer = m_pReplWindow->GetBuffer();
150+
std::string str = std::string(buffer.GetGapBuffer().begin() + m_startLocation.Index(), buffer.GetGapBuffer().end());
151+
if (str.size() <= 1)
145152
{
146-
// TODO: Reimplement the Repl here. It used to be a mode, but this way is easier.
147-
// Just parse the buffer changes an update the repl; don't need to handle keyboard input.
148-
// The code commented below is from the original repl
149-
// Note that we know the window, the buffer and the mode. But we are assuming a single repl.
150-
ZLOG(DBG, "Buffer Message");
153+
MoveToEnd();
154+
buffer.GetMode()->SwitchMode(EditorMode::Insert);
155+
return false;
151156
}
152-
}
153-
}
154-
155-
// TODO: Same keystroke command to close repl?
156-
157-
/*
158-
void ZepMode_Repl::AddKeyPress(uint32_t key, uint32_t modifiers)
159-
{
160-
// Set the cursor to the end of the buffer while inserting text
161-
GetCurrentWindow()->SetBufferCursor(MaxCursorMove);
162-
163-
else if (key == ExtKeys::RETURN)
164-
{
165-
auto& buffer = GetCurrentWindow()->GetBuffer();
166-
std::string str = std::string(buffer.GetGapBuffer().begin() + m_startLocation, buffer.GetGapBuffer().end());
167-
buffer.Insert(buffer.EndLocation(), "\n");
168157

169158
auto stripLineStarts = [](std::string& str) {
170159
bool newline = true;
@@ -193,36 +182,36 @@ void ZepMode_Repl::AddKeyPress(uint32_t key, uint32_t modifiers)
193182
stripLineStarts(str);
194183

195184
std::string ret;
196-
if (m_pRepl)
185+
if (m_pProvider)
197186
{
198187
int indent = 0;
199-
bool complete = m_pRepl->ReplIsFormComplete(str, indent);
188+
bool complete = m_pProvider->ReplIsFormComplete(str, indent);
200189
if (!complete)
201190
{
202191
// If the indent is < 0, we completed too much of the expression, so don't let the user hit return until they
203192
// fix it. Example in lisp: (+ 2 2)) This expression has 'too many' close brackets.
204193
if (indent < 0)
205194
{
206-
buffer.Delete(buffer.EndLocation() - 1, buffer.EndLocation());
207-
GetCurrentWindow()->SetBufferCursor(MaxCursorMove);
208-
return;
195+
buffer.Delete(buffer.End() - 1, buffer.End(), record);
196+
m_pReplWindow->SetBufferCursor(buffer.End());
197+
return true;
209198
}
210199

211200
// New line continuation symbol
212-
buffer.Insert(buffer.EndLocation(), ContinuationString);
201+
buffer.Insert(buffer.End(), ContinuationString, record);
213202

214203
// Indent by how far the repl suggests
215204
if (indent > 0)
216205
{
217206
for (int i = 0; i < indent; i++)
218207
{
219-
buffer.Insert(buffer.EndLocation(), " ");
208+
buffer.Insert(buffer.End(), " ", record);
220209
}
221210
}
222-
GetCurrentWindow()->SetBufferCursor(MaxCursorMove);
223-
return;
211+
m_pReplWindow->SetBufferCursor(buffer.End());
212+
return true;
224213
}
225-
ret = m_pRepl->ReplParse(str);
214+
ret = m_pProvider->ReplParse(str);
226215
}
227216
else
228217
{
@@ -232,24 +221,14 @@ void ZepMode_Repl::AddKeyPress(uint32_t key, uint32_t modifiers)
232221
if (!ret.empty() && ret[0] != 0)
233222
{
234223
ret.push_back('\n');
235-
buffer.Insert(buffer.EndLocation(), ret);
224+
buffer.Insert(buffer.End(), ret, record);
236225
}
237226

238227
Prompt();
239-
return;
240-
}
241-
else if (key == ExtKeys::BACKSPACE)
242-
{
243-
auto cursor = GetCurrentWindow()->GetBufferCursor() - 1;
244-
if (cursor >= m_startLocation)
245-
{
246-
GetCurrentWindow()->GetBuffer().Delete(GetCurrentWindow()->GetBufferCursor() - 1, GetCurrentWindow()->GetBufferCursor());
247-
}
228+
return true;
248229
}
249230

250-
return;
231+
return false;
251232
}
252233

253-
*/
254-
255234
} // namespace Zep

extensions/repl/mode_repl.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ class ZepReplExCommand : public ZepExCommand
5050

5151
static void Register(ZepEditor& editor, IZepReplProvider* pProvider);
5252

53-
virtual void Notify(std::shared_ptr<ZepMessage> message) override;
5453
virtual void Run(const std::vector<std::string>& args) override;
5554
virtual const char* ExCommandName() const override { return "ZRepl"; }
5655
virtual const KeyMap* GetKeyMappings(ZepMode&) const override { return &m_keymap; }
5756

57+
virtual bool AddKeyPress(uint32_t key, uint32_t modifiers);
58+
5859
private:
5960
void Prompt();
6061
void MoveToEnd();
@@ -64,6 +65,8 @@ class ZepReplExCommand : public ZepExCommand
6465
ZepBuffer* m_pReplBuffer = nullptr;
6566
ZepWindow* m_pReplWindow = nullptr;
6667
KeyMap m_keymap;
68+
GlyphIterator m_startLocation;
69+
bool m_ignoreMessages = false;
6770
};
6871

6972
class ZepReplEvaluateOuterCommand : public ZepExCommand

include/zep/buffer.h

+6
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ struct ChangeRecord
201201
}
202202
};
203203

204+
using fnKeyNotifier = std::function<bool(uint32_t key, uint32_t modifier)>;
204205
class ZepBuffer : public ZepComponent
205206
{
206207
public:
@@ -347,6 +348,10 @@ class ZepBuffer : public ZepComponent
347348
void ToggleFileFlag(uint32_t flags);
348349

349350
NVec2i GetExpression(ExpressionType type, const GlyphIterator location, const std::vector<char>& beginExpression, const std::vector<char>& endExpression) const;
351+
std::string GetBufferText(const GlyphIterator& start, const GlyphIterator& end) const;
352+
353+
void SetPostKeyNotifier(fnKeyNotifier notifier);
354+
fnKeyNotifier GetPostKeyNotifier() const;
350355

351356
private:
352357
void ClearRangeMarker(std::shared_ptr<RangeMarker> spMarker);
@@ -381,6 +386,7 @@ class ZepBuffer : public ZepComponent
381386

382387
// Modes
383388
std::shared_ptr<ZepMode> m_spMode;
389+
fnKeyNotifier m_postKeyNotifier;
384390
};
385391

386392
// Notification payload

screenshots/video.png

559 KB
Loading

src/buffer.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,12 @@ void ZepBuffer::UpdateForDelete(const GlyphIterator& startItr, const GlyphIterat
983983
});
984984
}
985985

986+
std::string ZepBuffer::GetBufferText(const GlyphIterator& start, const GlyphIterator& end) const
987+
{
988+
989+
return std::string(m_gapBuffer.begin() + start.Index(), m_gapBuffer.begin() + end.Index());
990+
}
991+
986992
void ZepBuffer::UpdateForInsert(const GlyphIterator& startItr, const GlyphIterator& endItr, ChangeRecord& changeRecord)
987993
{
988994
ForEachMarker(RangeMarkerType::All, Direction::Forward, startItr, End(), [&](const std::shared_ptr<RangeMarker>& marker) {
@@ -1593,4 +1599,14 @@ GlyphIterator ZepBuffer::Begin() const
15931599
return GlyphIterator(this);
15941600
}
15951601

1602+
void ZepBuffer::SetPostKeyNotifier(fnKeyNotifier notifier)
1603+
{
1604+
m_postKeyNotifier = notifier;
1605+
}
1606+
1607+
fnKeyNotifier ZepBuffer::GetPostKeyNotifier() const
1608+
{
1609+
return m_postKeyNotifier;
1610+
}
1611+
15961612
} // namespace Zep

src/mode.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,12 @@ void ZepMode::AddKeyPress(uint32_t key, uint32_t modifierKeys)
389389
// We convert CTRL + f to a string: "<C-f>"
390390
HandleMappedInput(ConvertInputToMapString(key, modifierKeys));
391391

392+
auto notifier = m_pCurrentWindow->GetBuffer().GetPostKeyNotifier();
393+
if (notifier != nullptr)
394+
{
395+
notifier(key, modifierKeys);
396+
}
397+
392398
timer_restart(m_lastKeyPressTimer);
393399
}
394400

@@ -1987,6 +1993,7 @@ bool ZepMode::HandleExCommand(std::string strCommand)
19871993
{
19881994
std::string displayText = reg.second.text;
19891995
displayText = string_replace(displayText, "\n", "^J");
1996+
displayText = string_replace(displayText, "\r", "");
19901997
str << "\"" << reg.first << " " << displayText << '\n';
19911998
}
19921999
}

0 commit comments

Comments
 (0)