Compare commits
2 Commits
6c200f7764
...
ca3d087aa3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca3d087aa3 | ||
|
|
d2be40a282 |
@@ -306,6 +306,11 @@ API Int GetWordEnd(Buffer *buffer, Int pos) {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsOpenBoundary(char c) {
|
||||||
|
bool result = c == 0 || IsParen(c) || IsBrace(c) || c == ':' || c == '\t' || c == '\n' || c == '"' || c == '\'';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
API bool IsLoadWord(char16_t w) {
|
API bool IsLoadWord(char16_t w) {
|
||||||
bool result = w == u'-' || w == u'/' || w == u'\\' || w == u':' || w == u'$' || w == u'_' || w == u'.' || w == u'!' || w == u'@';
|
bool result = w == u'-' || w == u'/' || w == u'\\' || w == u':' || w == u'$' || w == u'_' || w == u'.' || w == u'!' || w == u'@';
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -1503,8 +1508,10 @@ Buffer *BufferOpenFile(String path) {
|
|||||||
buffer = CreateBuffer(sys_allocator, path);
|
buffer = CreateBuffer(sys_allocator, path);
|
||||||
} else if (IsDir(path)) {
|
} else if (IsDir(path)) {
|
||||||
buffer = CreateBuffer(sys_allocator, path);
|
buffer = CreateBuffer(sys_allocator, path);
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
buffer->is_dir = true;
|
buffer->is_dir = true;
|
||||||
buffer->temp = true;
|
buffer->temp = true;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
String string = ReadFile(scratch, path);
|
String string = ReadFile(scratch, path);
|
||||||
buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096);
|
buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096);
|
||||||
@@ -1530,13 +1537,10 @@ bool BufferIsReferenced(BufferID buffer_id) {
|
|||||||
|
|
||||||
void ReopenBuffer(Buffer *buffer) {
|
void ReopenBuffer(Buffer *buffer) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
if (buffer->is_dir) {
|
|
||||||
ResetBuffer(buffer);
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
for (FileIter it = IterateFiles(scratch, buffer->name); IsValid(it); Advance(&it)) {
|
if (buffer->is_dir) { InsertDirectoryNavigation(buffer); return; }
|
||||||
RawAppendf(buffer, "%S\n", it.filename);
|
#endif
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String string = ReadFile(scratch, buffer->name);
|
String string = ReadFile(scratch, buffer->name);
|
||||||
if (string.len == 0) {
|
if (string.len == 0) {
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ BSet GetConsoleSet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String GetDir(Buffer *buffer) {
|
String GetDir(Buffer *buffer) {
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
if (buffer->is_dir) {
|
if (buffer->is_dir) {
|
||||||
return buffer->name;
|
return buffer->name;
|
||||||
} else {
|
|
||||||
String result = ChopLastSlash(buffer->name);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
String result = ChopLastSlash(buffer->name);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GetMainDir() {
|
String GetMainDir() {
|
||||||
@@ -445,101 +446,6 @@ void CMD_GotoPrevInList() {
|
|||||||
GotoNextInList(main.window, -1);
|
GotoNextInList(main.window, -1);
|
||||||
} RegisterCommand(CMD_GotoPrevInList, "alt-e", "For example: when jumping from build panel to build error, a jump point is setup, user can click this button to go over to the previous compiler error");
|
} RegisterCommand(CMD_GotoPrevInList, "alt-e", "For example: when jumping from build panel to build error, a jump point is setup, user can click this button to go over to the previous compiler error");
|
||||||
|
|
||||||
bool IsOpenBoundary(char c) {
|
|
||||||
bool result = c == 0 || IsParen(c) || IsBrace(c) || c == ':' || c == '\t' || c == '\n' || c == '"' || c == '\'';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ExpectP(x, ...) \
|
|
||||||
if (!(x)) { \
|
|
||||||
ReportErrorf("Failed to parse '" __FUNCTION__ "' command, " __VA_ARGS__); \
|
|
||||||
return; \
|
|
||||||
}
|
|
||||||
|
|
||||||
void Set(String string) {
|
|
||||||
String name = SkipIdent(&string);
|
|
||||||
ExpectP(name.len != 0, "expected a variable name, instead got '%S'", string);
|
|
||||||
|
|
||||||
Variable *var = NULL;
|
|
||||||
For (Variables) {
|
|
||||||
if (name == it.name) {
|
|
||||||
var = ⁢
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (var) {
|
|
||||||
SkipWhitespace(&string);
|
|
||||||
if (var->type == VariableType_String) {
|
|
||||||
char c = At(string, 0);
|
|
||||||
ExpectP(c == u'"' || c == u'\'', "Expected string to follow the command name, instead got %S", string);
|
|
||||||
string = Skip(string, 1);
|
|
||||||
String quote = SkipUntil(&string, {&c, 1});
|
|
||||||
ExpectP(At(string, 0) == c, ":Set %S <error here>, unclosed quote", name);
|
|
||||||
ReportConsolef(":Set %S %c%S%c", name, c, quote, c);
|
|
||||||
*var->string = Intern(&GlobalInternTable, quote);
|
|
||||||
} else if (var->type == VariableType_Int) {
|
|
||||||
ExpectP(IsDigit(At(string, 0)), "Expected an integer to follow the command name, instead got: %S", string);
|
|
||||||
Int number = SkipInt(&string);
|
|
||||||
ReportConsolef(":Set %S %lld", name, number);
|
|
||||||
*var->i = number;
|
|
||||||
} else if (var->type == VariableType_Float) {
|
|
||||||
ExpectP(IsDigit(At(string, 0)), "Expected float to follow the command name, instead got: %S", string);
|
|
||||||
Float number = SkipFloat(&string);
|
|
||||||
ReportConsolef(":Set %S %f", name, number);
|
|
||||||
*var->f = number;
|
|
||||||
} else if (var->type == VariableType_Color) {
|
|
||||||
ExpectP(IsHexDigit(At(string, 0)), "Expected hex integer to follow the command name, instead got: %S", string);
|
|
||||||
String begin = {string.data, 0};
|
|
||||||
while (IsHexDigit(At(string, 0))) {
|
|
||||||
string = Skip(string, 1);
|
|
||||||
begin.len += 1;
|
|
||||||
}
|
|
||||||
ReportConsolef(":Set %S %S", name, begin);
|
|
||||||
var->color->value = (uint32_t)strtoll(begin.data, NULL, 16);
|
|
||||||
} ElseInvalidCodepath();
|
|
||||||
|
|
||||||
|
|
||||||
if (name == "FontSize" || name == "PathToFont") {
|
|
||||||
ReloadFont(PathToFont, (U32)FontSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PLUGIN_PROJECT_MANAGEMENT
|
|
||||||
if (name == "ProjectDirectory") {
|
|
||||||
SetProjectDirectory(*var->string);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Command *cmd = NULL;
|
|
||||||
For (GlobalCommands) {
|
|
||||||
if (it.name == name) {
|
|
||||||
cmd = ⁢
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
SkipWhitespace(&string);
|
|
||||||
char c = At(string, 0);
|
|
||||||
ExpectP(c == u'"' || c == u'\'', "Expected string to follow the command name, instead got %S", string);
|
|
||||||
string = Skip(string, 1);
|
|
||||||
String quote = SkipUntil(&string, {&c, 1});
|
|
||||||
ExpectP(At(string, 0) == c, "Failed to parse command, unclose quote");
|
|
||||||
quote = Intern(&GlobalInternTable, quote);
|
|
||||||
ReportConsolef(":Set %S %c%S%c", name, c, quote, c);
|
|
||||||
Trigger *trigger = ParseKeyCached(quote);
|
|
||||||
if (trigger) {
|
|
||||||
cmd->binding = quote;
|
|
||||||
cmd->trigger = trigger;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReportErrorf("Failed to :Set, no such variable found: %S", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedOpen ResolveOpen(Allocator alo, String path, ResolveOpenMeta meta) {
|
ResolvedOpen ResolveOpen(Allocator alo, String path, ResolveOpenMeta meta) {
|
||||||
ResolvedOpen result = {};
|
ResolvedOpen result = {};
|
||||||
path = Trim(path);
|
path = Trim(path);
|
||||||
@@ -692,18 +598,12 @@ BSet Open(Window *window, String path, ResolveOpenMeta meta, bool set_active = t
|
|||||||
if (set_active) {
|
if (set_active) {
|
||||||
NextActiveWindowID = set.window->id;
|
NextActiveWindowID = set.window->id;
|
||||||
}
|
}
|
||||||
|
View *view = WindowOpenBufferView(set.window, o.path);
|
||||||
if (IsDir(o.path)) {
|
if (IsDir(o.path)) {
|
||||||
View *view = WindowOpenBufferView(set.window, o.path);
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
SetFuzzy(view);
|
OpenDirectoryNavigation(view);
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
#endif
|
||||||
ResetBuffer(buffer);
|
|
||||||
RawAppendf(buffer, "\n");
|
|
||||||
for (FileIter it = IterateFiles(scratch, o.path); IsValid(it); Advance(&it)) {
|
|
||||||
RawAppendf(buffer, "%S\n", it.filename);
|
|
||||||
}
|
|
||||||
SelectRange(view, GetBufferBeginAsRange(buffer));
|
|
||||||
} else {
|
} else {
|
||||||
View *view = WindowOpenBufferView(set.window, o.path);
|
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
if (o.line != -1) {
|
if (o.line != -1) {
|
||||||
if (o.col == -1) o.col = 1;
|
if (o.col == -1) o.col = 1;
|
||||||
@@ -784,10 +684,6 @@ void CMD_KillProcess() {
|
|||||||
KillProcess(main.view);
|
KillProcess(main.view);
|
||||||
} RegisterCommand(CMD_KillProcess, "", "Kill process in the last active primary window");
|
} RegisterCommand(CMD_KillProcess, "", "Kill process in the last active primary window");
|
||||||
|
|
||||||
void CMD_CloseWindow() {
|
|
||||||
Close(PrimaryWindowID);
|
|
||||||
} RegisterCommand(CMD_CloseWindow, "", "Close the last active primary window");
|
|
||||||
|
|
||||||
void AddCommand(Array<Command> *arr, String name, String binding, CMDFunction *function) {
|
void AddCommand(Array<Command> *arr, String name, String binding, CMDFunction *function) {
|
||||||
Command cmd = {};
|
Command cmd = {};
|
||||||
cmd.name = name;
|
cmd.name = name;
|
||||||
@@ -960,26 +856,6 @@ String Coro_CloseAllEx(mco_coro *co) {
|
|||||||
return "Yes";
|
return "Yes";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMD_QuitWithoutSaving() {
|
|
||||||
#ifdef PLUGIN_REMEDYBG
|
|
||||||
QuitDebugger();
|
|
||||||
#endif
|
|
||||||
AppIsRunning = false;
|
|
||||||
} RegisterCommand(CMD_QuitWithoutSaving, "", "Self explanatory");
|
|
||||||
|
|
||||||
void Coro_Quit(mco_coro *co) {
|
|
||||||
String res = Coro_CloseAllEx(co);
|
|
||||||
if (res != "Cancel") {
|
|
||||||
CMD_QuitWithoutSaving();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMD_Quit() {
|
|
||||||
CoRemove("Coro_Quit");
|
|
||||||
CoData *data = CoAdd(Coro_Quit);
|
|
||||||
CoResume(data);
|
|
||||||
} RegisterCommand(CMD_Quit, "", "Ask user which files he would like to save and exit");
|
|
||||||
|
|
||||||
void Coro_CloseAll(mco_coro *co) {
|
void Coro_CloseAll(mco_coro *co) {
|
||||||
Coro_CloseAllEx(co);
|
Coro_CloseAllEx(co);
|
||||||
}
|
}
|
||||||
@@ -990,32 +866,6 @@ void CMD_CloseAll() {
|
|||||||
CoResume(data);
|
CoResume(data);
|
||||||
} RegisterCommand(CMD_CloseAll, "", "Ask user which files to save and close all open normal views and buffers");
|
} RegisterCommand(CMD_CloseAll, "", "Ask user which files to save and close all open normal views and buffers");
|
||||||
|
|
||||||
void CMD_JumpPrev() {
|
|
||||||
BSet main = GetBSet(PrimaryWindowID);
|
|
||||||
JumpToLastValidView(main.window);
|
|
||||||
NextActiveWindowID = main.window->id;
|
|
||||||
} RegisterCommand(CMD_JumpPrev, "ctrl-tab", "Go to the previous open view in primary window");
|
|
||||||
|
|
||||||
void CMD_Prev() {
|
|
||||||
BSet main = GetBSet(PrimaryWindowID);
|
|
||||||
main.window->skip_checkpoint = true;
|
|
||||||
JumpBack(main.window);
|
|
||||||
NextActiveWindowID = main.window->id;
|
|
||||||
} RegisterCommand(CMD_Prev, "alt-q | mousex1", "Go to previous position (either previous view that was open or caret position) in the primary window");
|
|
||||||
|
|
||||||
void CMD_Next() {
|
|
||||||
BSet main = GetBSet(PrimaryWindowID);
|
|
||||||
main.window->skip_checkpoint = true;
|
|
||||||
JumpForward(main.window);
|
|
||||||
NextActiveWindowID = main.window->id;
|
|
||||||
} RegisterCommand(CMD_Next, "alt-shift-q | mousex2", "Go to next position, after backtracking, in the primary window");
|
|
||||||
|
|
||||||
void CMD_OpenUpFolder() {
|
|
||||||
BSet main = GetBSet(PrimaryWindowID);
|
|
||||||
String name = ChopLastSlash(main.buffer->name);
|
|
||||||
Open(name);
|
|
||||||
} RegisterCommand(CMD_OpenUpFolder, "ctrl-o", "Open current's file directory or up directory in other cases");
|
|
||||||
|
|
||||||
void CMD_MakeFontLarger() {
|
void CMD_MakeFontLarger() {
|
||||||
FontSize += 1;
|
FontSize += 1;
|
||||||
ReloadFont(PathToFont, (U32)FontSize);
|
ReloadFont(PathToFont, (U32)FontSize);
|
||||||
@@ -1035,41 +885,6 @@ void CMD_OpenLoadWord() {
|
|||||||
Open(load_word);
|
Open(load_word);
|
||||||
} RegisterCommand(CMD_OpenLoadWord, "ctrl-q | f12", "Open a link under the caret (file link, url, command) or open the selection");
|
} RegisterCommand(CMD_OpenLoadWord, "ctrl-q | f12", "Open a link under the caret (file link, url, command) or open the selection");
|
||||||
|
|
||||||
void CMD_FocusLeftWindow() {
|
|
||||||
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
|
|
||||||
} RegisterCommand(CMD_FocusLeftWindow, "alt-left");
|
|
||||||
|
|
||||||
void CMD_FocusRightWindow() {
|
|
||||||
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
|
|
||||||
} RegisterCommand(CMD_FocusRightWindow, "alt-right");
|
|
||||||
|
|
||||||
void CMD_FocusWindow1() {
|
|
||||||
NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
|
|
||||||
} RegisterCommand(CMD_FocusWindow1, "ctrl-1");
|
|
||||||
|
|
||||||
void CMD_FocusWindow2() {
|
|
||||||
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
|
|
||||||
Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
|
|
||||||
NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
|
|
||||||
} RegisterCommand(CMD_FocusWindow2, "ctrl-2");
|
|
||||||
|
|
||||||
void CMD_FocusWindow3() {
|
|
||||||
Window *first = GetOverlappingWindow({0,0});
|
|
||||||
if (first) {
|
|
||||||
Window *second = GetOverlappingWindow(GetSideOfWindow(first, DIR_RIGHT));
|
|
||||||
if (second) {
|
|
||||||
Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
|
|
||||||
if (third) {
|
|
||||||
NextActiveWindowID = third->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} RegisterCommand(CMD_FocusWindow3, "ctrl-3");
|
|
||||||
|
|
||||||
void CMD_NewWindow() {
|
|
||||||
CreateWind();
|
|
||||||
} RegisterCommand(CMD_NewWindow, "ctrl-backslash");
|
|
||||||
|
|
||||||
void Coro_ReplaceAll(mco_coro *co) {
|
void Coro_ReplaceAll(mco_coro *co) {
|
||||||
BSet main = GetBSet(PrimaryWindowID);
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
String16 string = FetchLoadWord(main.view);
|
String16 string = FetchLoadWord(main.view);
|
||||||
@@ -1144,9 +959,14 @@ void Coro_ReplaceAll(mco_coro *co) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ForItem (buffer, Buffers) {
|
ForItem (buffer, Buffers) {
|
||||||
if (buffer->special || buffer->is_dir || buffer->temp || buffer->dont_try_to_save_in_bulk_ops) {
|
if (buffer->special || buffer->temp || buffer->dont_try_to_save_in_bulk_ops) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
|
if (buffer->is_dir) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
View *view = OpenBufferView(buffer->name);
|
View *view = OpenBufferView(buffer->name);
|
||||||
if (SelectAllOccurences(view, needle)) {
|
if (SelectAllOccurences(view, needle)) {
|
||||||
|
|||||||
58
src/text_editor/commands_window_management.cpp
Normal file
58
src/text_editor/commands_window_management.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
void CMD_JumpPrev() {
|
||||||
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
|
JumpToLastValidView(main.window);
|
||||||
|
NextActiveWindowID = main.window->id;
|
||||||
|
} RegisterCommand(CMD_JumpPrev, "ctrl-tab", "Go to the previous open view in primary window");
|
||||||
|
|
||||||
|
void CMD_Prev() {
|
||||||
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
|
main.window->skip_checkpoint = true;
|
||||||
|
JumpBack(main.window);
|
||||||
|
NextActiveWindowID = main.window->id;
|
||||||
|
} RegisterCommand(CMD_Prev, "alt-q | mousex1", "Go to previous position (either previous view that was open or caret position) in the primary window");
|
||||||
|
|
||||||
|
void CMD_Next() {
|
||||||
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
|
main.window->skip_checkpoint = true;
|
||||||
|
JumpForward(main.window);
|
||||||
|
NextActiveWindowID = main.window->id;
|
||||||
|
} RegisterCommand(CMD_Next, "alt-shift-q | mousex2", "Go to next position, after backtracking, in the primary window");
|
||||||
|
|
||||||
|
void CMD_FocusLeftWindow() {
|
||||||
|
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
|
||||||
|
} RegisterCommand(CMD_FocusLeftWindow, "alt-left");
|
||||||
|
|
||||||
|
void CMD_FocusRightWindow() {
|
||||||
|
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
|
||||||
|
} RegisterCommand(CMD_FocusRightWindow, "alt-right");
|
||||||
|
|
||||||
|
void CMD_FocusWindow1() {
|
||||||
|
NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
|
||||||
|
} RegisterCommand(CMD_FocusWindow1, "ctrl-1");
|
||||||
|
|
||||||
|
void CMD_FocusWindow2() {
|
||||||
|
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
|
||||||
|
Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
|
||||||
|
NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
|
||||||
|
} RegisterCommand(CMD_FocusWindow2, "ctrl-2");
|
||||||
|
|
||||||
|
void CMD_FocusWindow3() {
|
||||||
|
Window *first = GetOverlappingWindow({0,0});
|
||||||
|
if (first) {
|
||||||
|
Window *second = GetOverlappingWindow(GetSideOfWindow(first, DIR_RIGHT));
|
||||||
|
if (second) {
|
||||||
|
Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
|
||||||
|
if (third) {
|
||||||
|
NextActiveWindowID = third->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} RegisterCommand(CMD_FocusWindow3, "ctrl-3");
|
||||||
|
|
||||||
|
void CMD_NewWindow() {
|
||||||
|
CreateWind();
|
||||||
|
} RegisterCommand(CMD_NewWindow, "ctrl-backslash");
|
||||||
|
|
||||||
|
void CMD_CloseWindow() {
|
||||||
|
Close(PrimaryWindowID);
|
||||||
|
} RegisterCommand(CMD_CloseWindow, "", "Close the last active primary window");
|
||||||
@@ -351,3 +351,94 @@ BufferID LoadConfig(String config_path) {
|
|||||||
}
|
}
|
||||||
return buffer->id;
|
return buffer->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ExpectP(x, ...) \
|
||||||
|
if (!(x)) { \
|
||||||
|
ReportErrorf("Failed to parse '" __FUNCTION__ "' command, " __VA_ARGS__); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(String string) {
|
||||||
|
String name = SkipIdent(&string);
|
||||||
|
ExpectP(name.len != 0, "expected a variable name, instead got '%S'", string);
|
||||||
|
|
||||||
|
Variable *var = NULL;
|
||||||
|
For (Variables) {
|
||||||
|
if (name == it.name) {
|
||||||
|
var = ⁢
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var) {
|
||||||
|
SkipWhitespace(&string);
|
||||||
|
if (var->type == VariableType_String) {
|
||||||
|
char c = At(string, 0);
|
||||||
|
ExpectP(c == u'"' || c == u'\'', "Expected string to follow the command name, instead got %S", string);
|
||||||
|
string = Skip(string, 1);
|
||||||
|
String quote = SkipUntil(&string, {&c, 1});
|
||||||
|
ExpectP(At(string, 0) == c, ":Set %S <error here>, unclosed quote", name);
|
||||||
|
ReportConsolef(":Set %S %c%S%c", name, c, quote, c);
|
||||||
|
*var->string = Intern(&GlobalInternTable, quote);
|
||||||
|
} else if (var->type == VariableType_Int) {
|
||||||
|
ExpectP(IsDigit(At(string, 0)), "Expected an integer to follow the command name, instead got: %S", string);
|
||||||
|
Int number = SkipInt(&string);
|
||||||
|
ReportConsolef(":Set %S %lld", name, number);
|
||||||
|
*var->i = number;
|
||||||
|
} else if (var->type == VariableType_Float) {
|
||||||
|
ExpectP(IsDigit(At(string, 0)), "Expected float to follow the command name, instead got: %S", string);
|
||||||
|
Float number = SkipFloat(&string);
|
||||||
|
ReportConsolef(":Set %S %f", name, number);
|
||||||
|
*var->f = number;
|
||||||
|
} else if (var->type == VariableType_Color) {
|
||||||
|
ExpectP(IsHexDigit(At(string, 0)), "Expected hex integer to follow the command name, instead got: %S", string);
|
||||||
|
String begin = {string.data, 0};
|
||||||
|
while (IsHexDigit(At(string, 0))) {
|
||||||
|
string = Skip(string, 1);
|
||||||
|
begin.len += 1;
|
||||||
|
}
|
||||||
|
ReportConsolef(":Set %S %S", name, begin);
|
||||||
|
var->color->value = (uint32_t)strtoll(begin.data, NULL, 16);
|
||||||
|
} ElseInvalidCodepath();
|
||||||
|
|
||||||
|
|
||||||
|
if (name == "FontSize" || name == "PathToFont") {
|
||||||
|
ReloadFont(PathToFont, (U32)FontSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLUGIN_PROJECT_MANAGEMENT
|
||||||
|
if (name == "ProjectDirectory") {
|
||||||
|
SetProjectDirectory(*var->string);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command *cmd = NULL;
|
||||||
|
For (GlobalCommands) {
|
||||||
|
if (it.name == name) {
|
||||||
|
cmd = ⁢
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd) {
|
||||||
|
SkipWhitespace(&string);
|
||||||
|
char c = At(string, 0);
|
||||||
|
ExpectP(c == u'"' || c == u'\'', "Expected string to follow the command name, instead got %S", string);
|
||||||
|
string = Skip(string, 1);
|
||||||
|
String quote = SkipUntil(&string, {&c, 1});
|
||||||
|
ExpectP(At(string, 0) == c, "Failed to parse command, unclose quote");
|
||||||
|
quote = Intern(&GlobalInternTable, quote);
|
||||||
|
ReportConsolef(":Set %S %c%S%c", name, c, quote, c);
|
||||||
|
Trigger *trigger = ParseKeyCached(quote);
|
||||||
|
if (trigger) {
|
||||||
|
cmd->binding = quote;
|
||||||
|
cmd->trigger = trigger;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportErrorf("Failed to :Set, no such variable found: %S", name);
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ void CMD_ShowDebugBufferList() {
|
|||||||
NextActiveWindowID = command_bar.window->id;
|
NextActiveWindowID = command_bar.window->id;
|
||||||
ResetBuffer(command_bar.buffer);
|
ResetBuffer(command_bar.buffer);
|
||||||
For (Buffers) {
|
For (Buffers) {
|
||||||
bool is_special = it->special || it->temp || it->is_dir || it->dont_try_to_save_in_bulk_ops;
|
bool is_special = it->special || it->temp || it->dont_try_to_save_in_bulk_ops;
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
|
is_special |= it->is_dir;
|
||||||
|
#endif
|
||||||
if (!is_special) {
|
if (!is_special) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -56,7 +59,10 @@ void CMD_ShowBufferList() {
|
|||||||
NextActiveWindowID = command_bar.window->id;
|
NextActiveWindowID = command_bar.window->id;
|
||||||
ResetBuffer(command_bar.buffer);
|
ResetBuffer(command_bar.buffer);
|
||||||
For (Buffers) {
|
For (Buffers) {
|
||||||
bool is_special = it->special || it->temp || it->is_dir || it->dont_try_to_save_in_bulk_ops;
|
bool is_special = it->special || it->temp || it->dont_try_to_save_in_bulk_ops;
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
|
is_special |= it->is_dir;
|
||||||
|
#endif
|
||||||
if (is_special) {
|
if (is_special) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
156
src/text_editor/plugin_directory_navigation.cpp
Normal file
156
src/text_editor/plugin_directory_navigation.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
// @todo: On save rename files, delete files it should apply the changes
|
||||||
|
// Instead of toying with Reopen maybe it should actually detect changes in directory etc. on update
|
||||||
|
|
||||||
|
void CMD_OpenUpFolder() {
|
||||||
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
|
String name = ChopLastSlash(main.buffer->name);
|
||||||
|
Open(name);
|
||||||
|
} RegisterCommand(CMD_OpenUpFolder, "ctrl-o", "Open current's file directory or up directory in other cases");
|
||||||
|
|
||||||
|
void InsertDirectoryNavigation(Buffer *buffer) {
|
||||||
|
Assert(buffer->is_dir);
|
||||||
|
Scratch scratch;
|
||||||
|
ResetBuffer(buffer);
|
||||||
|
RawAppendf(buffer, "\n");
|
||||||
|
for (FileIter it = IterateFiles(scratch, buffer->name); IsValid(it); Advance(&it)) {
|
||||||
|
RawAppendf(buffer, "%S\n", it.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenDirectoryNavigation(View *view) {
|
||||||
|
SetFuzzy(view);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
InsertDirectoryNavigation(buffer);
|
||||||
|
SelectRange(view, GetBufferBeginAsRange(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HANDLE dir;
|
||||||
|
OVERLAPPED ov;
|
||||||
|
HANDLE event;
|
||||||
|
BYTE buffer[4096];
|
||||||
|
BOOL pending;
|
||||||
|
} DirectoryWatcher;
|
||||||
|
|
||||||
|
BOOL InitDirectoryWatcher(DirectoryWatcher *w, const wchar_t *path)
|
||||||
|
{
|
||||||
|
ZeroMemory(w, sizeof(*w));
|
||||||
|
|
||||||
|
w->dir = CreateFileW(
|
||||||
|
path,
|
||||||
|
FILE_LIST_DIRECTORY,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (w->dir == INVALID_HANDLE_VALUE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
w->event = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!w->event)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
w->ov.hEvent = w->event;
|
||||||
|
w->pending = FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WasDirectoryModified(DirectoryWatcher *w)
|
||||||
|
{
|
||||||
|
DWORD bytes;
|
||||||
|
|
||||||
|
if (!w->pending) {
|
||||||
|
ResetEvent(w->event);
|
||||||
|
w->pending = ReadDirectoryChangesW(
|
||||||
|
w->dir,
|
||||||
|
w->buffer,
|
||||||
|
sizeof(w->buffer),
|
||||||
|
TRUE,
|
||||||
|
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||||
|
FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||||
|
FILE_NOTIFY_CHANGE_SIZE |
|
||||||
|
FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||||
|
NULL,
|
||||||
|
&w->ov,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (!w->pending)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForSingleObject(w->event, 0) == WAIT_OBJECT_0) {
|
||||||
|
GetOverlappedResult(w->dir, &w->ov, &bytes, FALSE);
|
||||||
|
w->pending = FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyDirectoryWatcher(DirectoryWatcher *w)
|
||||||
|
{
|
||||||
|
if (w->dir != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(w->dir);
|
||||||
|
if (w->event)
|
||||||
|
CloseHandle(w->event);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
DirectoryWatcher w;
|
||||||
|
InitDirectoryWatcher(&w, L"C:\\mydir");
|
||||||
|
|
||||||
|
if (WasDirectoryModified(&w)) {
|
||||||
|
// something changed
|
||||||
|
}
|
||||||
|
|
||||||
|
#if OS_LINUX
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fd;
|
||||||
|
int wd;
|
||||||
|
} DirectoryWatcher;
|
||||||
|
|
||||||
|
int InitDirectoryWatcher(DirectoryWatcher *w, const char *path)
|
||||||
|
{
|
||||||
|
w->fd = inotify_init1(IN_NONBLOCK);
|
||||||
|
if (w->fd < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
w->wd = inotify_add_watch(
|
||||||
|
w->fd,
|
||||||
|
path,
|
||||||
|
IN_CREATE | IN_DELETE | IN_MOVE | IN_MODIFY
|
||||||
|
);
|
||||||
|
|
||||||
|
return w->wd >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WasDirectoryModified(DirectoryWatcher *w)
|
||||||
|
{
|
||||||
|
char buffer[4096];
|
||||||
|
ssize_t len = read(w->fd, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0; // no data = no changes
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyDirectoryWatcher(DirectoryWatcher *w)
|
||||||
|
{
|
||||||
|
if (w->wd >= 0)
|
||||||
|
inotify_rm_watch(w->fd, w->wd);
|
||||||
|
if (w->fd >= 0)
|
||||||
|
close(w->fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
3
src/text_editor/plugin_directory_navigation.h
Normal file
3
src/text_editor/plugin_directory_navigation.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#define PLUGIN_DIRECTORY_NAVIGATION
|
||||||
|
void InsertDirectoryNavigation(struct Buffer *buffer);
|
||||||
|
void OpenDirectoryNavigation(struct View *view);
|
||||||
@@ -13,9 +13,14 @@ void Coro_SearchOpenBuffers(mco_coro *co) {
|
|||||||
|
|
||||||
ForItem (id, buffers) {
|
ForItem (id, buffers) {
|
||||||
Buffer *it = GetBuffer(id, NULL);
|
Buffer *it = GetBuffer(id, NULL);
|
||||||
if (it == NULL || it->special || it->is_dir || it->temp || it->dont_try_to_save_in_bulk_ops) {
|
if (it == NULL || it->special || it->temp || it->dont_try_to_save_in_bulk_ops) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
|
if (it->is_dir) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "render/generated_font.cpp"
|
#include "render/generated_font.cpp"
|
||||||
#include "render/font.cpp"
|
#include "render/font.cpp"
|
||||||
#include "render/opengl.cpp"
|
#include "render/opengl.cpp"
|
||||||
|
#include "plugin_directory_navigation.h"
|
||||||
#include "text_editor.h"
|
#include "text_editor.h"
|
||||||
#include "plugin_command_window.h"
|
#include "plugin_command_window.h"
|
||||||
#include "plugin_search_window.h"
|
#include "plugin_search_window.h"
|
||||||
@@ -39,7 +40,9 @@
|
|||||||
#include "draw.cpp"
|
#include "draw.cpp"
|
||||||
#include "test/tests.cpp"
|
#include "test/tests.cpp"
|
||||||
|
|
||||||
|
#include "commands_window_management.cpp"
|
||||||
#include "commands_clipboard.cpp"
|
#include "commands_clipboard.cpp"
|
||||||
|
#include "plugin_directory_navigation.cpp"
|
||||||
#include "plugin_search_open_buffers.cpp"
|
#include "plugin_search_open_buffers.cpp"
|
||||||
#include "plugin_project_management.cpp"
|
#include "plugin_project_management.cpp"
|
||||||
#include "plugin_basic_commands.cpp"
|
#include "plugin_basic_commands.cpp"
|
||||||
@@ -183,6 +186,26 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMD_QuitWithoutSaving() {
|
||||||
|
#ifdef PLUGIN_REMEDYBG
|
||||||
|
QuitDebugger();
|
||||||
|
#endif
|
||||||
|
AppIsRunning = false;
|
||||||
|
} RegisterCommand(CMD_QuitWithoutSaving, "", "Self explanatory");
|
||||||
|
|
||||||
|
void Coro_Quit(mco_coro *co) {
|
||||||
|
String res = Coro_CloseAllEx(co);
|
||||||
|
if (res != "Cancel") {
|
||||||
|
CMD_QuitWithoutSaving();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMD_Quit() {
|
||||||
|
CoRemove("Coro_Quit");
|
||||||
|
CoData *data = CoAdd(Coro_Quit);
|
||||||
|
CoResume(data);
|
||||||
|
} RegisterCommand(CMD_Quit, "", "Ask user which files he would like to save and exit");
|
||||||
|
|
||||||
void OnCommand(Event event) {
|
void OnCommand(Event event) {
|
||||||
ProfileFunction();
|
ProfileFunction();
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -63,7 +63,9 @@ struct Buffer {
|
|||||||
uint32_t dont_try_to_save_in_bulk_ops : 1;
|
uint32_t dont_try_to_save_in_bulk_ops : 1;
|
||||||
uint32_t close : 1;
|
uint32_t close : 1;
|
||||||
uint32_t special : 1;
|
uint32_t special : 1;
|
||||||
|
#ifdef PLUGIN_DIRECTORY_NAVIGATION
|
||||||
uint32_t is_dir : 1;
|
uint32_t is_dir : 1;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user