Terminal loop, virtual buffers, yank bound
- kte refuses to start when stdin is not a terminal: piped bytes were executed as editor commands (C-k s plus a path writes a file), and after EOF the loop spun at full CPU with no way to quit. - The terminal frontend handles all pending input before drawing (a paste used to cost a frame and a full redraw per character) and redraws only after input, a resize or deferred opens, else once a second. The renderer caches, per row and buffer version, where the horizontally scrolled part of a line starts and the cursor's render column, instead of rescanning the line every frame. Idle CPU with the cursor at the end of a 20 MB line: one full core -> ~1%. - Buffers with a virtual name (+HELP+) are not journaled and saving one asks for a file name; it used to write ./+HELP+ and journal under that path. - Yank with a repeat count is capped at 256 MiB in total instead of reserving count x size bytes (C-u 1000000 C-y of a large kill). - Remove an overload clang reports as unused (-Werror on macOS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
+12
-10
@@ -108,13 +108,6 @@ utf8_next_len(std::string_view line, std::size_t x)
|
||||
}
|
||||
|
||||
|
||||
static inline std::string_view
|
||||
line_view(const Buffer::Line &l)
|
||||
{
|
||||
return std::string_view(l.Data(), l.Size());
|
||||
}
|
||||
|
||||
|
||||
static inline std::string_view
|
||||
line_view(const std::string &l)
|
||||
{
|
||||
@@ -937,7 +930,8 @@ cmd_save(CommandContext &ctx)
|
||||
// Allow saving directly to a filename if buffer was opened with a
|
||||
// non-existent path (not yet file-backed but has a filename).
|
||||
if (!buf->IsFileBacked()) {
|
||||
if (!buf->Filename().empty()) {
|
||||
// A virtual buffer's name (e.g. +HELP+) is not a path: ask for one.
|
||||
if (!buf->Filename().empty() && !buf->IsVirtual()) {
|
||||
// If first-time save to an existing path, confirm overwrite
|
||||
if (fs_exists(buf->Filename())) {
|
||||
ctx.editor.StartPrompt(Editor::PromptKind::Confirm, "Overwrite", "");
|
||||
@@ -1130,7 +1124,7 @@ cmd_save_and_quit(CommandContext &ctx)
|
||||
ctx.editor.SetStatus(err);
|
||||
return false;
|
||||
}
|
||||
} else if (!buf->Filename().empty()) {
|
||||
} else if (!buf->Filename().empty() && !buf->IsVirtual()) {
|
||||
if (buf->SaveAs(buf->Filename(), err)) {
|
||||
buf->SetDirty(false);
|
||||
if (auto *sm = ctx.editor.Swap())
|
||||
@@ -3162,7 +3156,7 @@ cmd_newline(CommandContext &ctx)
|
||||
if (auto *u = buf->Undo())
|
||||
u->mark_saved();
|
||||
}
|
||||
} else if (!buf->Filename().empty()) {
|
||||
} else if (!buf->Filename().empty() && !buf->IsVirtual()) {
|
||||
if (!buf->SaveAs(buf->Filename(), err)) {
|
||||
ctx.editor.SetStatus(err);
|
||||
proceed_to_close = false;
|
||||
@@ -3974,6 +3968,14 @@ cmd_yank(CommandContext &ctx)
|
||||
}
|
||||
ensure_at_least_one_line(*buf);
|
||||
int repeat = ctx.count > 0 ? ctx.count : 1;
|
||||
// Bound the total: C-u 1000000 C-y of a large kill would allocate
|
||||
// gigabytes (and bad_alloc or the OOM killer end the session).
|
||||
constexpr std::size_t kMaxYankBytes = std::size_t{256} << 20;
|
||||
if (text.size() * static_cast<std::size_t>(repeat) > kMaxYankBytes) {
|
||||
ctx.editor.SetStatus("Yank too large (" + std::to_string(repeat) + " x " + std::to_string(text.size()) +
|
||||
" bytes)");
|
||||
return false;
|
||||
}
|
||||
std::string ins;
|
||||
if (repeat == 1) {
|
||||
ins = text;
|
||||
|
||||
Reference in New Issue
Block a user