Continuing cleanup, ui.cpp
This commit is contained in:
@@ -1556,3 +1556,13 @@ void SaveBuffer(Buffer *buffer) {
|
||||
ReportWarningf("Failed to save file with name: %S", buffer->name);
|
||||
}
|
||||
}
|
||||
|
||||
String GetBufferDirectory(Buffer *buffer) {
|
||||
#if PLUGIN_DIRECTORY_NAVIGATION
|
||||
if (buffer->is_dir) {
|
||||
return buffer->name;
|
||||
}
|
||||
#endif
|
||||
String result = ChopLastSlash(buffer->name);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
String GetBufferDirectory(Buffer *buffer) {
|
||||
#if PLUGIN_DIRECTORY_NAVIGATION
|
||||
if (buffer->is_dir) {
|
||||
return buffer->name;
|
||||
}
|
||||
#endif
|
||||
String result = ChopLastSlash(buffer->name);
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetPrimaryDirectory() {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
return GetBufferDirectory(main.buffer);
|
||||
}
|
||||
|
||||
void JumpTempBuffer(BSet *set, String buffer_name) {
|
||||
if (buffer_name.len == 0) {
|
||||
buffer_name = GetUniqueBufferName(GetBufferDirectory(set->buffer), "temp");
|
||||
}
|
||||
set->view = WindowOpenBufferView(set->window, buffer_name);
|
||||
set->buffer = GetBuffer(set->view->active_buffer);
|
||||
set->buffer->temp = true;
|
||||
}
|
||||
|
||||
View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL) {
|
||||
View *view = NULL;
|
||||
if (is_active) {
|
||||
@@ -120,20 +96,6 @@ 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(PrimaryWindowID);
|
||||
JumpTempBuffer(&main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
RawAppendf(main.buffer, "\n %S\n :Close\n", string);
|
||||
main.view->carets[0] = FindNext(main.buffer, u":Close", MakeCaret(0));
|
||||
AddCommand(&main.view->commands, "Close", EnterOrEscapeKeySet, [](){
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Close(active.buffer->id);
|
||||
});
|
||||
}
|
||||
|
||||
void ReportErrorf(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
@@ -145,7 +107,7 @@ void ReportErrorf(const char *fmt, ...) {
|
||||
if (view) {
|
||||
Appendf(view, "%S\n", string);
|
||||
}
|
||||
UIMessagef("%S", string);
|
||||
ShowUIMessagef("%S", string);
|
||||
}
|
||||
|
||||
void ReportConsolef(const char *fmt, ...) {
|
||||
@@ -165,6 +127,13 @@ void ReportWarningf(const char *fmt, ...) {
|
||||
Appendf(null_view, "%S\n", string);
|
||||
}
|
||||
|
||||
void CMD_OpenLoadWord() {
|
||||
Scratch scratch;
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
String16 load_word = FetchLoadWord(active.view);
|
||||
Open(load_word);
|
||||
} RegisterCommand(CMD_OpenLoadWord, "ctrl-q | f12", "Open a link under the caret (file link, url, command) or open the selection");
|
||||
|
||||
void CMD_CenterView() {
|
||||
CenterView(PrimaryWindowID);
|
||||
} RegisterCommand(CMD_CenterView, "");
|
||||
@@ -269,226 +238,6 @@ void CMD_SaveAll() {
|
||||
}
|
||||
} RegisterCommand(CMD_SaveAll, "ctrl-shift-s");
|
||||
|
||||
void MouseLoadWord(Event event, ResolveOpenMeta meta = ResolveOpenMeta_Normal) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
if (mouse_in_document) {
|
||||
Int p = ScreenSpaceToBufferPosErrorOutOfBounds(active.window, active.view, active.buffer, mouse);
|
||||
if (p != -1) {
|
||||
Range enclose = EncloseLoadWord(active.buffer, p);
|
||||
if (InBounds(active.view->carets[0].range, p)) enclose = active.view->carets[0].range;
|
||||
String16 string = GetString(active.buffer, enclose);
|
||||
|
||||
active.view->carets.len = 1;
|
||||
active.view->carets[0] = MakeCaret(p);
|
||||
Open(string, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResolvedOpen ResolveOpen(Allocator alo, String path, ResolveOpenMeta meta) {
|
||||
ResolvedOpen result = {};
|
||||
path = Trim(path);
|
||||
|
||||
// Editor command
|
||||
if(!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, ":")) {
|
||||
#if PLUGIN_CONFIG
|
||||
if (StartsWith(path, ":Set ")) {
|
||||
result.kind = OpenKind_Set;
|
||||
result.path = Skip(path, 5);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
result.kind = OpenKind_Command;
|
||||
path = Skip(path, 1);
|
||||
result.path.data = path.data;
|
||||
for (Int i = 0; i < path.len; i += 1) {
|
||||
if (IsNonWord(path.data[i])) {
|
||||
break;
|
||||
}
|
||||
result.path.len += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Shell
|
||||
if (!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, "!!")) {
|
||||
result.kind = OpenKind_BackgroundExec;
|
||||
result.path = Skip(path, 2);
|
||||
return result;
|
||||
}
|
||||
if (StartsWith(path, "!")) {
|
||||
result.kind = OpenKind_Exec;
|
||||
result.path = Skip(path, 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Web
|
||||
if (!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, "https://") || StartsWith(path, "http://")) {
|
||||
result.path = Format(alo, "%S %S", InternetBrowser, path);
|
||||
result.kind = OpenKind_BackgroundExec;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit
|
||||
if (!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, "commit ")) {
|
||||
path = Skip(path, 7);
|
||||
result.path = Format(alo, "git --no-pager show %S", path);
|
||||
result.kind = OpenKind_Exec;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
String p = NormalizePath(alo, path);
|
||||
if (p.len == 2 && IsAlphabetic(ToLowerCase(At(p, 0))) && At(p, 1) == ':') {
|
||||
p = Format(alo, "%S/", p);
|
||||
}
|
||||
String pstart = p;
|
||||
|
||||
bool is_absolute = false;
|
||||
if (IsAlphabetic(ToLowerCase(At(p, 0))) && At(p, 1) == ':' && At(p, 2) == '/') {
|
||||
is_absolute = true;
|
||||
p = Skip(p, 3);
|
||||
} else if (At(p, 0) == '/') {
|
||||
is_absolute = true;
|
||||
p = Skip(p, 1);
|
||||
}
|
||||
|
||||
while (!IsOpenBoundary(At(p, 0))) {
|
||||
p = Skip(p, 1);
|
||||
}
|
||||
path = {pstart.data, (Int)(p.data - pstart.data)};
|
||||
|
||||
if (At(p, 0) == ':') {
|
||||
p = Skip(p, 1);
|
||||
result.line = SkipInt(&p);
|
||||
if (At(p, 0) == ':') {
|
||||
p = Skip(p, 1);
|
||||
Int b = SkipInt(&p);
|
||||
result.col = b;
|
||||
}
|
||||
} else if (At(p, 0) == '(') {
|
||||
p = Skip(p, 1);
|
||||
result.line = SkipInt(&p);
|
||||
if (At(p, 0) == ',') {
|
||||
p = Skip(p, 1);
|
||||
Int b = SkipInt(&p);
|
||||
result.col = b;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer *existing_buffer = GetBuffer(path, NULL);
|
||||
if (existing_buffer != NULL) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Goto;
|
||||
result.existing_buffer = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (is_absolute && FileExists(path)) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Goto;
|
||||
return result;
|
||||
} else {
|
||||
String rel_path = Format(alo, "%S/%S", GetPrimaryDirectory(), 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (meta & ResolveOpenMeta_DontError) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Skip;
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet Open(Window *window, String path, ResolveOpenMeta meta, bool set_active = true) {
|
||||
Scratch scratch;
|
||||
BSet set = GetBSet(window);
|
||||
ResolvedOpen o = ResolveOpen(scratch, path, meta);
|
||||
if (o.kind == OpenKind_Goto) {
|
||||
if (set_active) {
|
||||
NextActiveWindowID = set.window->id;
|
||||
}
|
||||
View *view = WindowOpenBufferView(set.window, o.path);
|
||||
if (IsDir(o.path)) {
|
||||
#if PLUGIN_DIRECTORY_NAVIGATION
|
||||
OpenDirectoryNavigation(view);
|
||||
#endif
|
||||
}
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
if (o.line != -1) {
|
||||
if (o.col == -1) o.col = 1;
|
||||
Int pos = XYToPos(buffer, {o.col - 1, o.line - 1});
|
||||
SelectRange(view, MakeCaret(pos));
|
||||
}
|
||||
CenterView(window->id);
|
||||
} else if (o.kind == OpenKind_Exec) {
|
||||
if (set_active) {
|
||||
NextActiveWindowID = set.window->id;
|
||||
}
|
||||
JumpTempBuffer(&set);
|
||||
Exec(set.view->id, false, o.path, GetPrimaryDirectory());
|
||||
} else if (o.kind == OpenKind_BackgroundExec) {
|
||||
// this shouldn't change the focus/window/view
|
||||
Exec(NullViewID, false, o.path, GetPrimaryDirectory());
|
||||
} else if (o.kind == OpenKind_Command) {
|
||||
EvalCommand(o.path);
|
||||
}
|
||||
#if PLUGIN_CONFIG
|
||||
else if (o.kind == OpenKind_Set) {
|
||||
Set(o.path);
|
||||
}
|
||||
#endif
|
||||
else if (o.kind == OpenKind_Skip) {
|
||||
return {};
|
||||
} else {
|
||||
ReportErrorf("Failed to open: %S", path);
|
||||
}
|
||||
|
||||
return GetBSet(window);
|
||||
}
|
||||
|
||||
BSet Open(String path, ResolveOpenMeta meta) {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
main = Open(main.window, path, meta);
|
||||
return main;
|
||||
}
|
||||
|
||||
BSet Open(String16 path, ResolveOpenMeta meta) {
|
||||
Scratch scratch;
|
||||
String string = ToString(scratch, path);
|
||||
return Open(string, meta);
|
||||
}
|
||||
|
||||
void CMD_OpenLoadWord() {
|
||||
Scratch scratch;
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
String16 load_word = FetchLoadWord(active.view);
|
||||
Open(load_word);
|
||||
} RegisterCommand(CMD_OpenLoadWord, "ctrl-q | f12", "Open a link under the caret (file link, url, command) or open the selection");
|
||||
|
||||
void CMD_Save() {
|
||||
BSet active = GetBSet(PrimaryWindowID);
|
||||
SaveBuffer(active.buffer);
|
||||
@@ -527,41 +276,7 @@ void CMD_KillProcess() {
|
||||
KillProcess(main.view);
|
||||
} RegisterCommand(CMD_KillProcess, "", "Kill process in the last active primary window");
|
||||
|
||||
void AddCommand(Array<Command> *arr, String name, Trigger *trigger, CMDFunction *function) {
|
||||
IterRemove(*arr) {
|
||||
IterRemovePrepare(*arr);
|
||||
if (it.name == name) {
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
Command cmd = {};
|
||||
cmd.name = name;
|
||||
cmd.function = function;
|
||||
cmd.trigger = trigger;
|
||||
cmd.docs = "Not listing commands attached to things anywhere currently, maybe should change?";
|
||||
Add(arr, cmd);
|
||||
}
|
||||
|
||||
UIAction WaitForUIAction(mco_coro *co, BSet main) {
|
||||
UIAction result = UIAction_Cancel;
|
||||
for (;;) {
|
||||
if (main.window->active_view != main.view->id || (main.window->id != PrimaryWindowID && main.window->id != ActiveWindowID) || main.window->close) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (main.view->ui_action != UIAction_Null) {
|
||||
result = main.view->ui_action;
|
||||
break;
|
||||
}
|
||||
|
||||
CoYield(co);
|
||||
}
|
||||
Close(main.buffer->id);
|
||||
return result;
|
||||
}
|
||||
#define AddUIAction(VIEW,NAME,TRIGGER,ACTION) AddCommand(&((VIEW)->commands),(NAME),(TRIGGER),[](){BSet active = GetBSet(ActiveWindowID); active.view->ui_action = (ACTION);})
|
||||
|
||||
void Coro_Rename(mco_coro *co) {
|
||||
void ShowRenameUI(mco_coro *co) {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
Buffer *original_buffer = main.buffer;
|
||||
JumpTempBuffer(&main);
|
||||
@@ -589,29 +304,12 @@ void Coro_Rename(mco_coro *co) {
|
||||
}
|
||||
|
||||
void CMD_Rename() {
|
||||
CoRemove("Coro_Rename");
|
||||
CoData *data = CoAdd(Coro_Rename);
|
||||
CoRemove("ShowRenameUI");
|
||||
CoData *data = CoAdd(ShowRenameUI);
|
||||
CoResume(data);
|
||||
} RegisterCommand(CMD_Rename, "", "Opens a UI asking for a new name of a buffer open in the last active primary window");
|
||||
|
||||
UIAction Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
|
||||
JumpTempBuffer(&main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
RawAppendf(main.buffer, R"==(
|
||||
%S
|
||||
|
||||
:Yes :No :Cancel
|
||||
)==", question);
|
||||
main.view->carets[0] = FindNext(main.buffer, u":Yes", MakeCaret(0));
|
||||
main.view->carets[0].range.min = main.view->carets[0].range.max;
|
||||
AddUIAction(main.view, "Yes", EnterKey, UIAction_Yes);
|
||||
AddUIAction(main.view, "No", NULL, UIAction_No);
|
||||
AddUIAction(main.view, "Cancel", EscapeKey, UIAction_Cancel);
|
||||
UIAction ui_action = WaitForUIAction(co, main);
|
||||
return ui_action;
|
||||
}
|
||||
|
||||
void Coro_Close(mco_coro *co) {
|
||||
void ShowCloseViewUI(mco_coro *co) {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
if (main.buffer->special || main.buffer->temp) {
|
||||
Close(main.view->id);
|
||||
@@ -640,7 +338,7 @@ void Coro_Close(mco_coro *co) {
|
||||
}
|
||||
|
||||
String question = Format(CoCurr->arena, "Do you want to save [%S] before closing?", main.buffer->name);
|
||||
UIAction ui_action = Coro_YesNoCancel(co, main, question);
|
||||
UIAction ui_action = ShowYesNoCancelUI(co, main, question);
|
||||
if (ui_action == UIAction_Yes) {
|
||||
SaveBuffer(main.buffer);
|
||||
Close(main.buffer->id);
|
||||
@@ -652,8 +350,8 @@ void Coro_Close(mco_coro *co) {
|
||||
}
|
||||
|
||||
void CMD_Close() {
|
||||
CoRemove("Coro_Close");
|
||||
CoData *data = CoAdd(Coro_Close);
|
||||
CoRemove("ShowCloseViewUI");
|
||||
CoData *data = CoAdd(ShowCloseViewUI);
|
||||
CoResume(data);
|
||||
} RegisterCommand(CMD_Close, "ctrl-w", "Close open view in the last active primary window");
|
||||
|
||||
@@ -668,7 +366,7 @@ void CMD_DeleteFile() {
|
||||
// 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) {
|
||||
UIAction ShowCloseAllUI(mco_coro *co) {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
Array<BufferID> buffers = {CoCurr->arena};
|
||||
For (Buffers) Add(&buffers, it->id);
|
||||
@@ -682,24 +380,24 @@ String Coro_CloseAllEx(mco_coro *co) {
|
||||
}
|
||||
|
||||
String question = Format(CoCurr->arena, "Do you want to save [%S] before closing?", it->name);
|
||||
UIAction ui_action = Coro_YesNoCancel(co, main, question);
|
||||
UIAction ui_action = ShowYesNoCancelUI(co, main, question);
|
||||
it = GetBuffer(id, NULL);
|
||||
if (it && ui_action == UIAction_Yes) {
|
||||
SaveBuffer(it);
|
||||
} else if (ui_action == UIAction_No) {
|
||||
} else if (ui_action == UIAction_Cancel) {
|
||||
return "Cancel";
|
||||
return UIAction_Cancel;
|
||||
} ElseInvalidCodepath();
|
||||
}
|
||||
|
||||
For(Buffers) {
|
||||
Close(it->id);
|
||||
}
|
||||
return "Yes";
|
||||
return UIAction_Yes;
|
||||
}
|
||||
|
||||
void Coro_CloseAll(mco_coro *co) {
|
||||
Coro_CloseAllEx(co);
|
||||
ShowCloseAllUI(co);
|
||||
}
|
||||
|
||||
void CMD_CloseAll() {
|
||||
@@ -720,7 +418,7 @@ void CMD_MakeFontSmaller() {
|
||||
}
|
||||
} RegisterCommand(CMD_MakeFontSmaller, "ctrl-minus", "Decrease the font size");
|
||||
|
||||
void Coro_ReplaceAll(mco_coro *co) {
|
||||
void ShowReplaceAllUI(mco_coro *co) {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
String16 string = FetchLoadWord(main.view);
|
||||
String string8 = ToString(CoCurr->arena, string);
|
||||
@@ -783,7 +481,7 @@ void Coro_ReplaceAll(mco_coro *co) {
|
||||
}
|
||||
|
||||
void CMD_ReplaceAll() {
|
||||
CoRemove("Coro_ReplaceAll");
|
||||
CoData *data = CoAdd(Coro_ReplaceAll);
|
||||
CoRemove("ShowReplaceAllUI");
|
||||
CoData *data = CoAdd(ShowReplaceAllUI);
|
||||
CoResume(data);
|
||||
} RegisterCommand(CMD_ReplaceAll, "ctrl-shift-r", "Search and replace over the entire project, you need to select a text with format like this 'FindAnd@>ReplaceWith' and executing the command will change all occurences of FindAnd to ReplaceWith");
|
||||
|
||||
@@ -48,39 +48,12 @@ void UpdateDebugWindow() {
|
||||
}
|
||||
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
RawReplaceText(set.buffer, GetRange(set.buffer), u"Active buffers and views:\n");
|
||||
|
||||
Scratch scratch;
|
||||
String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)main.window->id.id, (int)main.view->id.id, (int)main.buffer->id.id, (long long)FrameID);
|
||||
String16 string = ToString16(scratch, s);
|
||||
RawReplaceText(set.buffer, GetRange(set.buffer), string);
|
||||
|
||||
float xmouse, ymouse;
|
||||
SDL_GetMouseState(&xmouse, &ymouse);
|
||||
RawAppendf(set.buffer, "mouse: [%f, %f]\n", roundf(DPIScale * xmouse), roundf(DPIScale * ymouse));
|
||||
|
||||
RawAppendf(set.buffer, "BufferID id = %d\n", main.buffer->id.id);
|
||||
RawAppendf(set.buffer, "String name = %S\n", main.buffer->name);
|
||||
RawAppendf(set.buffer, "Int change_id = %lld\n", (long long)main.buffer->change_id);
|
||||
RawAppendf(set.buffer, "Int user_change_id = %lld\n", (long long)main.buffer->user_change_id);
|
||||
RawAppendf(set.buffer, "Int file_mod_time = %lld\n", (long long)main.buffer->file_mod_time);
|
||||
RawAppendf(set.buffer, "\n");
|
||||
|
||||
RawAppendf(set.buffer, "U16 *data = %zu\n", main.buffer->data);
|
||||
RawAppendf(set.buffer, "Int len = %lld\n", (long long)main.buffer->len);
|
||||
RawAppendf(set.buffer, "Int cap = %lld\n", (long long)main.buffer->cap);
|
||||
RawAppendf(set.buffer, "Array<Int> line_starts = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->line_starts.len, (long long)main.buffer->line_starts.cap, main.buffer->line_starts.data);
|
||||
RawAppendf(set.buffer, "\n");
|
||||
|
||||
RawAppendf(set.buffer, "Array<HistoryEntry> undo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->undo_stack.len, (long long)main.buffer->undo_stack.cap, main.buffer->undo_stack.data);
|
||||
RawAppendf(set.buffer, "Array<HistoryEntry> redo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->redo_stack.len, (long long)main.buffer->redo_stack.cap, main.buffer->redo_stack.data);
|
||||
RawAppendf(set.buffer, "int edit_phase = %d", main.buffer->edit_phase);
|
||||
RawAppendf(set.buffer, "\n");
|
||||
|
||||
RawAppendf(set.buffer, "int no_history = %d\n", main.buffer->no_history);
|
||||
RawAppendf(set.buffer, "int no_line_starts = %d\n", main.buffer->no_line_starts);
|
||||
RawAppendf(set.buffer, "int dirty = %d\n", main.buffer->dirty);
|
||||
RawAppendf(set.buffer, "int changed_on_disk = %d\n", main.buffer->changed_on_disk);
|
||||
RawAppendf(set.buffer, "int temp = %d\n", main.buffer->temp);
|
||||
For (Views) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
RawAppendf(set.buffer, "view->id:%lld, buffer->id:%lld, buffer->name:%S\n", (long long)it->id.id, (long long)buffer->id.id, buffer->name);
|
||||
}
|
||||
}
|
||||
|
||||
void CMD_ToggleDebug() {
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "process.cpp"
|
||||
#include "event.cpp"
|
||||
#include "config.cpp"
|
||||
#include "ui.cpp"
|
||||
#include "commands.cpp"
|
||||
#include "commands_clipboard.cpp"
|
||||
#include "scratch.cpp"
|
||||
@@ -159,16 +160,16 @@ void CMD_QuitWithoutSaving() {
|
||||
AppIsRunning = false;
|
||||
} RegisterCommand(CMD_QuitWithoutSaving, "", "Self explanatory");
|
||||
|
||||
void Coro_Quit(mco_coro *co) {
|
||||
String res = Coro_CloseAllEx(co);
|
||||
if (res != "Cancel") {
|
||||
void ShowQuitAppUI(mco_coro *co) {
|
||||
UIAction res = ShowCloseAllUI(co);
|
||||
if (res != UIAction_Cancel) {
|
||||
CMD_QuitWithoutSaving();
|
||||
}
|
||||
}
|
||||
|
||||
void CMD_Quit() {
|
||||
CoRemove("Coro_Quit");
|
||||
CoData *data = CoAdd(Coro_Quit);
|
||||
CoRemove("ShowQuitAppUI");
|
||||
CoData *data = CoAdd(ShowQuitAppUI);
|
||||
CoResume(data);
|
||||
} RegisterCommand(CMD_Quit, "", "Ask user which files he would like to save and exit");
|
||||
|
||||
|
||||
291
src/text_editor/ui.cpp
Normal file
291
src/text_editor/ui.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
void JumpTempBuffer(BSet *set, String buffer_name) {
|
||||
if (buffer_name.len == 0) {
|
||||
buffer_name = GetUniqueBufferName(GetBufferDirectory(set->buffer), "temp");
|
||||
}
|
||||
set->view = WindowOpenBufferView(set->window, buffer_name);
|
||||
set->buffer = GetBuffer(set->view->active_buffer);
|
||||
set->buffer->temp = true;
|
||||
}
|
||||
|
||||
void AddCommand(Array<Command> *arr, String name, Trigger *trigger, CMDFunction *function) {
|
||||
IterRemove(*arr) {
|
||||
IterRemovePrepare(*arr);
|
||||
if (it.name == name) {
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
Command cmd = {};
|
||||
cmd.name = name;
|
||||
cmd.function = function;
|
||||
cmd.trigger = trigger;
|
||||
cmd.docs = "Not listing commands attached to things anywhere currently, maybe should change?";
|
||||
Add(arr, cmd);
|
||||
}
|
||||
|
||||
#define AddUIAction(VIEW,NAME,TRIGGER,ACTION) AddCommand(&((VIEW)->commands),(NAME),(TRIGGER),[](){BSet active = GetBSet(ActiveWindowID); active.view->ui_action = (ACTION);})
|
||||
UIAction WaitForUIAction(mco_coro *co, BSet main) {
|
||||
UIAction result = UIAction_Cancel;
|
||||
for (;;) {
|
||||
if (main.window->active_view != main.view->id || (main.window->id != PrimaryWindowID && main.window->id != ActiveWindowID) || main.window->close) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (main.view->ui_action != UIAction_Null) {
|
||||
result = main.view->ui_action;
|
||||
break;
|
||||
}
|
||||
|
||||
CoYield(co);
|
||||
}
|
||||
Close(main.buffer->id);
|
||||
return result;
|
||||
}
|
||||
|
||||
UIAction ShowYesNoCancelUI(mco_coro *co, BSet main, String question) {
|
||||
JumpTempBuffer(&main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
RawAppendf(main.buffer, R"==(
|
||||
%S
|
||||
|
||||
:Yes :No :Cancel
|
||||
)==", question);
|
||||
main.view->carets[0] = FindNext(main.buffer, u":Yes", MakeCaret(0));
|
||||
main.view->carets[0].range.min = main.view->carets[0].range.max;
|
||||
AddUIAction(main.view, "Yes", EnterKey, UIAction_Yes);
|
||||
AddUIAction(main.view, "No", NULL, UIAction_No);
|
||||
AddUIAction(main.view, "Cancel", EscapeKey, UIAction_Cancel);
|
||||
UIAction ui_action = WaitForUIAction(co, main);
|
||||
return ui_action;
|
||||
}
|
||||
|
||||
void ShowUIMessagef(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
JumpTempBuffer(&main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
RawAppendf(main.buffer, "\n %S\n :Close\n", string);
|
||||
main.view->carets[0] = FindNext(main.buffer, u":Close", MakeCaret(0));
|
||||
AddCommand(&main.view->commands, "Close", EnterOrEscapeKeySet, [](){
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Close(active.buffer->id);
|
||||
});
|
||||
}
|
||||
|
||||
String GetPrimaryDirectory() {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
return GetBufferDirectory(main.buffer);
|
||||
}
|
||||
|
||||
void MouseLoadWord(Event event, ResolveOpenMeta meta = ResolveOpenMeta_Normal) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
if (mouse_in_document) {
|
||||
Int p = ScreenSpaceToBufferPosErrorOutOfBounds(active.window, active.view, active.buffer, mouse);
|
||||
if (p != -1) {
|
||||
Range enclose = EncloseLoadWord(active.buffer, p);
|
||||
if (InBounds(active.view->carets[0].range, p)) enclose = active.view->carets[0].range;
|
||||
String16 string = GetString(active.buffer, enclose);
|
||||
|
||||
active.view->carets.len = 1;
|
||||
active.view->carets[0] = MakeCaret(p);
|
||||
Open(string, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResolvedOpen ResolveOpen(Allocator alo, String path, ResolveOpenMeta meta) {
|
||||
ResolvedOpen result = {};
|
||||
path = Trim(path);
|
||||
|
||||
// Editor command
|
||||
if(!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, ":")) {
|
||||
#if PLUGIN_CONFIG
|
||||
if (StartsWith(path, ":Set ")) {
|
||||
result.kind = OpenKind_Set;
|
||||
result.path = Skip(path, 5);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
result.kind = OpenKind_Command;
|
||||
path = Skip(path, 1);
|
||||
result.path.data = path.data;
|
||||
for (Int i = 0; i < path.len; i += 1) {
|
||||
if (IsNonWord(path.data[i])) {
|
||||
break;
|
||||
}
|
||||
result.path.len += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Shell
|
||||
if (!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, "!!")) {
|
||||
result.kind = OpenKind_BackgroundExec;
|
||||
result.path = Skip(path, 2);
|
||||
return result;
|
||||
}
|
||||
if (StartsWith(path, "!")) {
|
||||
result.kind = OpenKind_Exec;
|
||||
result.path = Skip(path, 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Web
|
||||
if (!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, "https://") || StartsWith(path, "http://")) {
|
||||
result.path = Format(alo, "%S %S", InternetBrowser, path);
|
||||
result.kind = OpenKind_BackgroundExec;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit
|
||||
if (!(ResolveOpenMeta_DontExec & meta)) {
|
||||
if (StartsWith(path, "commit ")) {
|
||||
path = Skip(path, 7);
|
||||
result.path = Format(alo, "git --no-pager show %S", path);
|
||||
result.kind = OpenKind_Exec;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
String p = NormalizePath(alo, path);
|
||||
if (p.len == 2 && IsAlphabetic(ToLowerCase(At(p, 0))) && At(p, 1) == ':') {
|
||||
p = Format(alo, "%S/", p);
|
||||
}
|
||||
String pstart = p;
|
||||
|
||||
bool is_absolute = false;
|
||||
if (IsAlphabetic(ToLowerCase(At(p, 0))) && At(p, 1) == ':' && At(p, 2) == '/') {
|
||||
is_absolute = true;
|
||||
p = Skip(p, 3);
|
||||
} else if (At(p, 0) == '/') {
|
||||
is_absolute = true;
|
||||
p = Skip(p, 1);
|
||||
}
|
||||
|
||||
while (!IsOpenBoundary(At(p, 0))) {
|
||||
p = Skip(p, 1);
|
||||
}
|
||||
path = {pstart.data, (Int)(p.data - pstart.data)};
|
||||
|
||||
if (At(p, 0) == ':') {
|
||||
p = Skip(p, 1);
|
||||
result.line = SkipInt(&p);
|
||||
if (At(p, 0) == ':') {
|
||||
p = Skip(p, 1);
|
||||
Int b = SkipInt(&p);
|
||||
result.col = b;
|
||||
}
|
||||
} else if (At(p, 0) == '(') {
|
||||
p = Skip(p, 1);
|
||||
result.line = SkipInt(&p);
|
||||
if (At(p, 0) == ',') {
|
||||
p = Skip(p, 1);
|
||||
Int b = SkipInt(&p);
|
||||
result.col = b;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer *existing_buffer = GetBuffer(path, NULL);
|
||||
if (existing_buffer != NULL) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Goto;
|
||||
result.existing_buffer = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (is_absolute && FileExists(path)) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Goto;
|
||||
return result;
|
||||
} else {
|
||||
String rel_path = Format(alo, "%S/%S", GetPrimaryDirectory(), 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (meta & ResolveOpenMeta_DontError) {
|
||||
result.path = path;
|
||||
result.kind = OpenKind_Skip;
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet Open(Window *window, String path, ResolveOpenMeta meta, bool set_active = true) {
|
||||
Scratch scratch;
|
||||
BSet set = GetBSet(window);
|
||||
ResolvedOpen o = ResolveOpen(scratch, path, meta);
|
||||
if (o.kind == OpenKind_Goto) {
|
||||
if (set_active) {
|
||||
NextActiveWindowID = set.window->id;
|
||||
}
|
||||
View *view = WindowOpenBufferView(set.window, o.path);
|
||||
if (IsDir(o.path)) {
|
||||
#if PLUGIN_DIRECTORY_NAVIGATION
|
||||
OpenDirectoryNavigation(view);
|
||||
#endif
|
||||
}
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
if (o.line != -1) {
|
||||
if (o.col == -1) o.col = 1;
|
||||
Int pos = XYToPos(buffer, {o.col - 1, o.line - 1});
|
||||
SelectRange(view, MakeCaret(pos));
|
||||
}
|
||||
CenterView(window->id);
|
||||
} else if (o.kind == OpenKind_Exec) {
|
||||
if (set_active) {
|
||||
NextActiveWindowID = set.window->id;
|
||||
}
|
||||
JumpTempBuffer(&set);
|
||||
Exec(set.view->id, false, o.path, GetPrimaryDirectory());
|
||||
} else if (o.kind == OpenKind_BackgroundExec) {
|
||||
// this shouldn't change the focus/window/view
|
||||
Exec(NullViewID, false, o.path, GetPrimaryDirectory());
|
||||
} else if (o.kind == OpenKind_Command) {
|
||||
EvalCommand(o.path);
|
||||
}
|
||||
#if PLUGIN_CONFIG
|
||||
else if (o.kind == OpenKind_Set) {
|
||||
Set(o.path);
|
||||
}
|
||||
#endif
|
||||
else if (o.kind == OpenKind_Skip) {
|
||||
return {};
|
||||
} else {
|
||||
ReportErrorf("Failed to open: %S", path);
|
||||
}
|
||||
|
||||
return GetBSet(window);
|
||||
}
|
||||
|
||||
BSet Open(String path, ResolveOpenMeta meta) {
|
||||
BSet main = GetBSet(PrimaryWindowID);
|
||||
main = Open(main.window, path, meta);
|
||||
return main;
|
||||
}
|
||||
|
||||
BSet Open(String16 path, ResolveOpenMeta meta) {
|
||||
Scratch scratch;
|
||||
String string = ToString(scratch, path);
|
||||
return Open(string, meta);
|
||||
}
|
||||
Reference in New Issue
Block a user