Compare commits
3 Commits
10fb5d77a1
...
0f03f248c7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f03f248c7 | ||
|
|
35d68bda61 | ||
|
|
1ae20a46b2 |
@@ -1,13 +1,13 @@
|
||||
- What precise workflow do I need for me to be viable to use this?
|
||||
- From a user (novice) point of view, how does it look like?
|
||||
|
||||
Debug session:
|
||||
- Report errorf - use coroutine dialogs
|
||||
- Replace in render layer also
|
||||
|
||||
Use session 1:
|
||||
- OpenCommand in command window freezes the app
|
||||
- SDL popups are not working on linux ...
|
||||
- CloseAll idea: should create a buffer interface with list of buffers, user would be able to select which buffers to save and which not, then button UICloseAll
|
||||
- Creating files more efficiently, renaming
|
||||
- Dialog popup on save? Or ctrl-shift-s?
|
||||
- Maybe rename in bar and do :Rename
|
||||
- :Rename command that will ask
|
||||
|
||||
New UI Session
|
||||
- Cleanup String16/String with Open and EvalCommands after lua refactor
|
||||
@@ -20,6 +20,7 @@ New UI Session
|
||||
- Database idea: use special buffers to store information
|
||||
- Editing the buffer doesn't seem to be the slow part rather, accessing the data and putting it into the buffer (potentially hitting many different memory locations) I have a crazy idea to use buffers in order to store the names in a serialized format
|
||||
- non editable buffers (raw ops ok, non-raw no op)
|
||||
- DBBuffer
|
||||
- Guide on the first page for new users with links to configs, tutorials
|
||||
|
||||
- Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required?
|
||||
|
||||
@@ -427,6 +427,14 @@ API String16 SkipWhitespace(String16 *string) {
|
||||
return begin;
|
||||
}
|
||||
|
||||
API bool Chop(String16 *string, String16 ending) {
|
||||
if (EndsWith(*string, ending)) {
|
||||
*string = Chop(*string, ending.len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// chop this - 324
|
||||
API String16 ChopNumberEx(String16 *string) {
|
||||
String16 col = {};
|
||||
|
||||
@@ -158,15 +158,24 @@ void Appendf(View *view, const char *fmt, ...) {
|
||||
Append(view, string, true);
|
||||
}
|
||||
|
||||
void UIMessagef(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
JumpGarbageBuffer(&main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
RawAppendf(main.buffer, "\n %S\n", string);
|
||||
}
|
||||
|
||||
void ReportErrorf(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error!", string.data, NULL);
|
||||
View *view = GetView(NullViewID);
|
||||
if (view) {
|
||||
Appendf(view, "%S\n", string);
|
||||
NextActiveWindowID = NullWindowID;
|
||||
}
|
||||
UIMessagef("%S", string);
|
||||
}
|
||||
|
||||
void ReportConsolef(const char *fmt, ...) {
|
||||
@@ -412,21 +421,6 @@ void Command_GotoPrevInList() {
|
||||
GotoNextInList(main.window, -1);
|
||||
} RegisterCommand(Command_GotoPrevInList, "alt-e");
|
||||
|
||||
enum OpenKind {
|
||||
OpenKind_Invalid,
|
||||
OpenKind_Skip,
|
||||
OpenKind_Exec,
|
||||
OpenKind_BackgroundExec,
|
||||
OpenKind_Goto,
|
||||
OpenKind_Command,
|
||||
};
|
||||
|
||||
struct ResolvedOpen {
|
||||
OpenKind kind;
|
||||
String path;
|
||||
Int line, col;
|
||||
};
|
||||
|
||||
bool IsOpenBoundary(char c) {
|
||||
bool result = c == 0 || IsParen(c) || IsBrace(c) || c == ':' || c == '\t' || c == '\n' || c == '"' || c == '\'';
|
||||
return result;
|
||||
@@ -434,6 +428,7 @@ bool IsOpenBoundary(char c) {
|
||||
|
||||
ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) {
|
||||
ResolvedOpen result = {};
|
||||
path = Trim(path);
|
||||
|
||||
// Editor command
|
||||
{
|
||||
@@ -512,6 +507,7 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) {
|
||||
if (existing_buffer != NULL) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Goto;
|
||||
result.existing_buffer = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -521,14 +517,18 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) {
|
||||
return result;
|
||||
} else {
|
||||
String workspace_path = Format(scratch, "%S/%S", WorkDir, path);
|
||||
if (GetBuffer(workspace_path, NULL) || FileExists(workspace_path)) {
|
||||
bool existing_buffer = GetBuffer(workspace_path, NULL);
|
||||
if (existing_buffer || FileExists(workspace_path)) {
|
||||
result.existing_buffer = existing_buffer;
|
||||
result.path = workspace_path;
|
||||
result.kind = OpenKind_Goto;
|
||||
return result;
|
||||
}
|
||||
|
||||
String rel_path = Format(scratch, "%S/%S", GetMainDir(), path);
|
||||
if (GetBuffer(rel_path, NULL) || FileExists(rel_path)) {
|
||||
existing_buffer = GetBuffer(rel_path, NULL);
|
||||
if (existing_buffer || FileExists(rel_path)) {
|
||||
result.existing_buffer = existing_buffer;
|
||||
result.path = rel_path;
|
||||
result.kind = OpenKind_Goto;
|
||||
return result;
|
||||
@@ -538,6 +538,7 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) {
|
||||
}
|
||||
|
||||
if (meta == "dont_error") {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Skip;
|
||||
return result;
|
||||
}
|
||||
@@ -548,7 +549,6 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) {
|
||||
BSet Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
Scratch scratch;
|
||||
BSet set = GetBSet(window);
|
||||
path = Trim(path);
|
||||
ResolvedOpen o = ResolveOpen(scratch, path, meta);
|
||||
if (o.kind == OpenKind_Goto) {
|
||||
if (set_active) {
|
||||
@@ -586,7 +586,7 @@ BSet Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
} else if (o.kind == OpenKind_Skip) {
|
||||
return {};
|
||||
} else {
|
||||
ReportWarningf("Failed to open: %S", path);
|
||||
ReportErrorf("Failed to open: %S", path);
|
||||
}
|
||||
|
||||
return GetBSet(window);
|
||||
@@ -654,12 +654,11 @@ String CodeSkipPatterns[] = {".git/", ".obj", ".o", ".pdb", ".exe"};
|
||||
String Coro_OpenCodeDir;
|
||||
|
||||
void Coro_OpenCode(mco_coro *co) {
|
||||
BlockArena arena = {};
|
||||
Array<String> dirs = {arena};
|
||||
Array<String> dirs = {CoCurr->arena};
|
||||
Add(&dirs, Coro_OpenCodeDir);
|
||||
int i = 0;
|
||||
for (int diri = 0; diri < dirs.len; diri += 1) {
|
||||
for (FileIter it = IterateFiles(arena, dirs[diri]); IsValid(it); Advance(&it)) {
|
||||
for (FileIter it = IterateFiles(CoCurr->arena, dirs[diri]); IsValid(it); Advance(&it)) {
|
||||
bool match = false;
|
||||
for (int endings_i = 0; endings_i < Lengthof(CodeSkipPatterns); endings_i += 1) {
|
||||
String ending = CodeSkipPatterns[endings_i];
|
||||
@@ -680,7 +679,6 @@ void Coro_OpenCode(mco_coro *co) {
|
||||
CoYield(co);
|
||||
}
|
||||
}
|
||||
Release(&arena);
|
||||
}
|
||||
|
||||
void OpenCode(String dir) {
|
||||
@@ -702,6 +700,12 @@ void Command_CloseWindow() {
|
||||
Close(LastActiveLayoutWindowID);
|
||||
} RegisterCommand(Command_CloseWindow, "");
|
||||
|
||||
void AddHook(Array<CommandData> *arr, String name, String binding, Function *function) {
|
||||
CommandData n = {name, binding, function, ParseKeyCached(binding)};
|
||||
Add(arr, n);
|
||||
}
|
||||
|
||||
// @todo: rename to temp buffer? but there is already a thing like that...
|
||||
String Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
|
||||
JumpGarbageBuffer(&main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
@@ -713,9 +717,9 @@ String Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
|
||||
)==", question);
|
||||
main.view->carets[0] = FindNext(main.buffer, u":Yes", MakeCaret(0));
|
||||
main.view->carets[0].range.min = main.view->carets[0].range.max;
|
||||
Add(&main.view->hooks, {"Yes", "enter", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Yes";}, ParseKeyCached("enter")});
|
||||
Add(&main.view->hooks, {"No", "", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "No";}, ParseKeyCached("")});
|
||||
Add(&main.view->hooks, {"Cancel", "escape", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Cancel";}, ParseKeyCached("escape")});
|
||||
AddHook(&main.view->hooks, "Yes", "enter", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Yes";});
|
||||
AddHook(&main.view->hooks, "No", "", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "No";});
|
||||
AddHook(&main.view->hooks, "Cancel", "escape", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Cancel";});
|
||||
String result = "Cancel";
|
||||
for (;;) {
|
||||
if (main.window->active_view != main.view->id || main.window->close) {
|
||||
@@ -761,8 +765,7 @@ void Coro_Close(mco_coro *co) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
String question = Format(scratch, "Do you want to save [%S] before closing?", main.buffer->name);
|
||||
String question = Format(CoCurr->arena, "Do you want to save [%S] before closing?", main.buffer->name);
|
||||
String result = Coro_YesNoCancel(co, main, question);
|
||||
if (result == "Yes") {
|
||||
SaveBuffer(main.buffer);
|
||||
@@ -781,10 +784,10 @@ void Command_Close() {
|
||||
// Considerations with coroutines:
|
||||
// 1. Does scratch memory leak across Yield boundary? Or interacts badly with Yield stuff in any way?
|
||||
// 2. Are pointers and globals correct over time? Or might they get deleted etc.
|
||||
// 3. Imagine a scenario where the coroutine gets deleted before completion, will the memory leak?
|
||||
String Coro_CloseAllEx(mco_coro *co) {
|
||||
Scratch scratch;
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
Array<BufferID> buffers = {scratch};
|
||||
Array<BufferID> buffers = {CoCurr->arena};
|
||||
For (Buffers) Add(&buffers, it->id);
|
||||
ForItem (id, buffers) {
|
||||
Buffer *it = GetBuffer(id);
|
||||
@@ -795,7 +798,7 @@ String Coro_CloseAllEx(mco_coro *co) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String question = Format(scratch, "Do you want to save [%S] before closing?", it->name);
|
||||
String question = Format(CoCurr->arena, "Do you want to save [%S] before closing?", it->name);
|
||||
String result = Coro_YesNoCancel(co, main, question);
|
||||
it = GetBuffer(id, NULL);
|
||||
if (it && result == "Yes") {
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
typedef void CoroutineProc(mco_coro *co);
|
||||
CoData *CoCurr = NULL;
|
||||
|
||||
void CoDestroy(CoData *n) {
|
||||
mco_destroy(n->co);
|
||||
Release(&n->arena);
|
||||
}
|
||||
|
||||
void CoRemove(String name) {
|
||||
IterRemove(ActiveCoroutines) {
|
||||
IterRemovePrepare(ActiveCoroutines);
|
||||
if (it.name == name) {
|
||||
mco_destroy(it.co);
|
||||
Release(&it.arena);
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
@@ -15,15 +22,19 @@ CoData *CoAddEx(CoroutineProc *proc, String name) {
|
||||
CoRemove(name);
|
||||
mco_desc desc = mco_desc_init(proc, 0);
|
||||
|
||||
mco_coro *coro = NULL;
|
||||
mco_result ok = mco_create(&coro, &desc);
|
||||
mco_coro *coro = NULL;
|
||||
mco_result ok = mco_create(&coro, &desc);
|
||||
if (ok != MCO_SUCCESS) {
|
||||
ReportWarningf("failed to create coroutine %d", ok);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mco_resume(coro);
|
||||
Add(&ActiveCoroutines, {coro, name});
|
||||
CoData *prev_curr = CoCurr;
|
||||
CoCurr = GetLast(ActiveCoroutines);
|
||||
ok = mco_resume(coro);
|
||||
Assert(ok == MCO_SUCCESS);
|
||||
CoCurr = prev_curr;
|
||||
return GetLast(ActiveCoroutines);
|
||||
}
|
||||
|
||||
@@ -37,14 +48,15 @@ void CoUpdate(Event *event) {
|
||||
|
||||
mco_state status = mco_status(it.co);
|
||||
if (status == MCO_DEAD) {
|
||||
mco_destroy(it.co);
|
||||
CoDestroy(&it);
|
||||
remove_item = true;
|
||||
} else {
|
||||
mco_push(it.co, &event, sizeof(Event *));
|
||||
CoCurr = ⁢
|
||||
mco_result ok = mco_resume(it.co);
|
||||
if (ok != MCO_SUCCESS) {
|
||||
ReportWarningf("failed to resume coroutine %d", ok);
|
||||
mco_destroy(it.co);
|
||||
CoDestroy(&it);
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ Array<Variable> Variables;
|
||||
Array<Process> ActiveProcesses = {};
|
||||
Array<String> ProcessEnviroment = {};
|
||||
|
||||
struct CoData { mco_coro *co; String name; bool dont_wait_until_resolved; };
|
||||
struct CoData { mco_coro *co; String name; BlockArena arena; bool dont_wait_until_resolved; void *user_ctx; };
|
||||
Array<CoData> ActiveCoroutines;
|
||||
|
||||
|
||||
|
||||
@@ -368,13 +368,13 @@ void OnCommand(Event event) {
|
||||
if (mouse_in_scrollbar) {
|
||||
ScrollbarSelected = it->id;
|
||||
|
||||
View *view = GetView(it->active_view);
|
||||
Vec2 mouse_vec2 = MouseVec2();
|
||||
Scroller s = ComputeScrollerRect(it);
|
||||
double size_y = (double)GetSize(it->scrollbar_rect).y;
|
||||
double p = mouse_vec2.y - it->scrollbar_rect.min.y;
|
||||
View *view = GetView(it->active_view);
|
||||
Vec2 mouse_vec2 = MouseVec2();
|
||||
Scroller s = ComputeScrollerRect(it);
|
||||
double size_y = (double)GetSize(it->scrollbar_rect).y;
|
||||
double p = mouse_vec2.y - it->scrollbar_rect.min.y;
|
||||
if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) {
|
||||
view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing);
|
||||
view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing);
|
||||
it->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y;
|
||||
} else {
|
||||
it->mouse_scroller_offset = (s.rect.min.y - p) / size_y;
|
||||
|
||||
@@ -176,3 +176,22 @@ struct Register_Variable {
|
||||
type name = __VA_ARGS__; \
|
||||
Register_Variable var_##name(&Variables, VariableType_##type, #name, &name)
|
||||
|
||||
void AddHook(Array<CommandData> *arr, String name, String binding, Function *function);
|
||||
|
||||
|
||||
enum OpenKind {
|
||||
OpenKind_Invalid,
|
||||
OpenKind_Skip,
|
||||
OpenKind_Exec,
|
||||
OpenKind_BackgroundExec,
|
||||
OpenKind_Goto,
|
||||
OpenKind_Command,
|
||||
};
|
||||
|
||||
struct ResolvedOpen {
|
||||
OpenKind kind;
|
||||
String path;
|
||||
Int line, col;
|
||||
bool existing_buffer;
|
||||
};
|
||||
ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta);
|
||||
|
||||
@@ -14,6 +14,28 @@ void StatusWindowInit() {
|
||||
window->layout = false;
|
||||
window->jump_history = false;
|
||||
window->lose_focus_on_escape = true;
|
||||
|
||||
AddHook(&view->hooks, "Rename", "ctrl-r", [](){
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
BSet last = GetBSet(LastActiveLayoutWindowID);
|
||||
String16 buffer_string = GetString(active.buffer);
|
||||
Range replace_range = {0, active.buffer->len};
|
||||
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
|
||||
if (!found_separator) {
|
||||
ReportErrorf("Failed to :Rename, didn't find '|' separator");
|
||||
return;
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
String16 buffer_name = GetString(active.buffer, replace_range);
|
||||
String buffer_name8 = ToString(scratch, buffer_name);
|
||||
ResolvedOpen o = ResolveOpen(scratch, buffer_name8, "dont_error");
|
||||
if (o.kind != OpenKind_Skip) {
|
||||
ReportErrorf("%S already exists, either on disk as file or as buffer", buffer_name8);
|
||||
return;
|
||||
}
|
||||
last.buffer->name = Intern(&GlobalInternTable, o.path);
|
||||
});
|
||||
}
|
||||
|
||||
void StatusWindowLayout(Rect2I *rect, Int wx, Int wy) {
|
||||
@@ -52,17 +74,18 @@ void StatusWindowUpdate() {
|
||||
return;
|
||||
}
|
||||
String16 buffer_name = GetString(title.buffer, replace_range);
|
||||
buffer_name = Skip(buffer_name, 1);
|
||||
buffer_name = Trim(buffer_name);
|
||||
|
||||
Int column = ChopNumber(&buffer_name);
|
||||
if (column == -1) return;
|
||||
|
||||
Chop(&buffer_name, u":");
|
||||
Int line = ChopNumber(&buffer_name);
|
||||
if (line == -1) {
|
||||
line = column;
|
||||
column = 0;
|
||||
}
|
||||
Chop(&buffer_name, u":");
|
||||
|
||||
Int buffer_pos = XYToPos(main.buffer, {column, line});
|
||||
Caret &caret = main.view->carets[0];
|
||||
@@ -78,14 +101,14 @@ void StatusWindowUpdate() {
|
||||
// add separator at the end of buffer
|
||||
if (!found_separator) {
|
||||
SelectRange(title.view, GetBufferEndAsRange(title.buffer));
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, u" |");
|
||||
ReplaceEx(scratch, title.view, u" | :Rename");
|
||||
}
|
||||
|
||||
// replace data up to separator with filename and stuff
|
||||
const char *reopen = main.buffer->changed_on_disk ? " :Reopen" : "";
|
||||
const char *case_sens = SearchCaseSensitive ? " C" : "";
|
||||
const char *word_bound = SearchWordBoundary ? " W" : "";
|
||||
String s = Format(scratch, "# %S:%lld:%lld%s%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, case_sens, word_bound, reopen);
|
||||
String s = Format(scratch, " %S:%lld:%lld%s%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, case_sens, word_bound, reopen);
|
||||
For (ActiveProcesses) {
|
||||
if (it.view_id == main.view->id.id) {
|
||||
s = Format(scratch, "%S %lld :KillProcess", s, (long long)it.id);
|
||||
|
||||
Reference in New Issue
Block a user