Files
text_editor/src/text_editor/commands.cpp

1178 lines
36 KiB
C++

BSet GetBSet(Window *window) {
BSet set = {window};
set.view = GetView(set.window->active_view);
set.buffer = GetBuffer(set.view->active_buffer);
return set;
}
BSet GetBSet(WindowID window_id) {
Window *window = GetWindow(window_id);
BSet result = GetBSet(window);
return result;
}
BSet GetConsoleSet() {
BSet result = {};
result.window = GetWindow(NullWindowID);
result.view = GetView(NullViewID);
result.buffer = GetBuffer(NullBufferID);
return result;
}
String GetDir(Buffer *buffer) {
if (buffer->is_dir) {
return buffer->name;
} else {
return ChopLastSlash(buffer->name);
}
}
String GetMainDir() {
BSet main = GetBSet(LastActiveLayoutWindowID);
return GetDir(main.buffer);
}
void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
if (buffer_name.len == 0) {
buffer_name = GetUniqueBufferName(GetDir(set->buffer), "temp");
}
set->view = WindowOpenBufferView(set->window, buffer_name);
set->buffer = GetBuffer(set->view->active_buffer);
set->buffer->garbage = true;
}
void BeginJump(BSet *set, BufferID buffer_id = NullBufferID) {
set->buffer = GetBuffer(buffer_id);
set->view = WindowOpenBufferView(set->window, set->buffer->name);
}
void EndJump(BSet set) {
Int pos = XYToPos(set.buffer, {0, set.buffer->line_starts.len - 1});
set.view->carets[0] = MakeCaret(pos);
UpdateScroll(set.window, true);
}
void MouseLoadWord(Event event, String meta = "") {
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);
}
}
}
View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL) {
View *view = NULL;
if (is_active) {
*is_active = false;
}
BSet active = GetBSet(ActiveWindowID);
if (active.buffer->id == buffer->id) {
if (is_active) {
*is_active = true;
}
return active.view;
}
For(Views) {
if (it->active_buffer != buffer->id) {
continue;
}
view = it;
break;
}
if (!view) {
view = CreateView(buffer->id);
}
return view;
}
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
View *view = GetViewForFixingWhenBufferCommand(buffer);
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
Scratch scratch;
SelectRange(view, range);
ReplaceEx(scratch, view, string);
Dealloc(&view->carets);
view->carets = carets;
}
// @todo: revamp interface since it scrolls ALL VIEWS??? or maybe not??
void Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
struct ViewInfo {
View *view;
Array<Caret> carets;
bool scroll_to_end;
};
Array<ViewInfo> view_info = {scratch};
ForItem(it_view, Views) {
if (it_view->active_buffer != buffer->id) {
continue;
}
ViewInfo vi = {it_view};
if (scroll_to_end_if_cursor_on_last_line) {
Int line = PosToLine(buffer, GetFront(it_view->carets[0]));
if (line == buffer->line_starts.len - 1) {
vi.scroll_to_end = true;
}
}
if (!vi.scroll_to_end) {
vi.carets = Copy(GetSystemAllocator(), it_view->carets);
}
Add(&view_info, vi);
}
SelectRange(view, GetBufferEndAsRange(buffer));
Replace(view, string);
For (view_info) {
if (it.scroll_to_end) {
it.view->carets[0] = MakeCaret(GetBufferEndAsRange(buffer).min);
} else {
Dealloc(&it.view->carets);
it.view->carets = it.carets;
}
}
}
void Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line) {
Scratch scratch;
String16 string16 = ToString16(scratch, string);
Append(view, string16, scroll_to_end_if_cursor_on_last_line);
}
void Appendf(View *view, const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
Append(view, string, true);
}
bool YesNoMessageBox(const char *title, const char *msg) {
SDL_MessageBoxButtonData buttons[] = {
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "No" },
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "Yes" },
};
SDL_MessageBoxData data = {};
data.flags = SDL_MESSAGEBOX_WARNING;
data.title = title;
data.message = msg;
data.numbuttons = 2;
data.buttons = buttons;
int resp;
bool status = SDL_ShowMessageBox(&data, &resp);
Assert(status);
bool result = resp == 0;
return result;
}
enum SaveResult {
SAVE_CANCEL,
SAVE_NO,
SAVE_YES,
};
SaveResult SaveMessageBox(String filename) {
Scratch scratch;
const char *title = "There are unsaved changes, do you really want to quit?";
const char *msg = Format(scratch, "Do you really want to quit? Unsaved buffer: %S", filename).data;
SDL_MessageBoxButtonData buttons[] = {
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, SAVE_YES, "Save" },
{ 0, SAVE_NO, "Don't save" },
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, SAVE_CANCEL, "Cancel" },
};
SDL_MessageBoxData data = {};
data.flags = SDL_MESSAGEBOX_WARNING;
data.title = title;
data.message = msg;
data.numbuttons = 3;
data.buttons = buttons;
int resp;
bool status = SDL_ShowMessageBox(&data, &resp);
Assert(status);
return (SaveResult)resp;
}
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;
}
}
void ReportConsolef(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
View *view = GetView(NullViewID);
Appendf(view, "%S\n", string);
}
void ReportWarningf(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
View *null_view = GetView(NullViewID);
Appendf(null_view, "%S\n", string);
}
void ReportDebugf(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
RawAppendf(TraceBuffer, "%S\n", string);
}
void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
BSet set = GetBSet(window);
Rect2I visible_cells_rect = GetVisibleCells(window);
Int y = GetSize(visible_cells_rect).y - 2;
if (direction == DIR_UP) y = -y;
For(set.view->carets) {
XY xy = PosToXY(set.buffer, GetFront(it));
if (direction == DIR_DOWN && xy.line == set.buffer->line_starts.len - 1) {
Range line_range = GetLineRange(set.buffer, xy.line);
xy.col = line_range.max - line_range.min;
} else if (direction == DIR_UP && xy.line == 0) {
xy.col = 0;
}
xy.line += y;
Int pos = XYToPos(set.buffer, xy);
if (shift) {
it = SetFront(it, pos);
} else {
it = MakeCaret(pos);
}
}
}
void TrimTrailingWhitespace(Buffer *buffer, bool trim_lines_with_caret = false) {
Scratch scratch;
bool is_active_view = false;
View *view = GetViewForFixingWhenBufferCommand(buffer, &is_active_view);
if (!is_active_view && !trim_lines_with_caret) {
trim_lines_with_caret = true;
}
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets);
Array<Range> lines_to_skip_triming = {};
if (!trim_lines_with_caret) {
lines_to_skip_triming = GetSelectedLinesSorted(scratch, view);
}
for (Int i = 0; i < buffer->line_starts.len; i += 1) {
Int range_index = FindRangeByPos(&lines_to_skip_triming, i);
if (range_index != -1) continue;
Range range = GetLineRangeWithoutNL(buffer, i);
Int whitespace_end = range.max;
for (; whitespace_end > range.min; whitespace_end -= 1) {
U16 w = buffer->data[whitespace_end - 1];
bool is_whitespace = w == ' ' || w == '\t' || w == '\v' || w == '\r';
if (!is_whitespace) break;
}
Range whitespace_range = {whitespace_end, range.max};
AddEdit(&edits, whitespace_range, u"");
}
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
view->update_scroll = false;
}
void ConvertLineEndingsToLF(Buffer *buffer, bool trim_lines_with_caret = false) {
Scratch scratch;
bool is_active_view = false;
View *view = GetViewForFixingWhenBufferCommand(buffer, &is_active_view);
if (!is_active_view && !trim_lines_with_caret) {
trim_lines_with_caret = true;
}
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets);
Array<Range> lines_to_skip_triming = {};
if (!trim_lines_with_caret) {
lines_to_skip_triming = GetSelectedLinesSorted(scratch, view);
}
for (Int i = 0; i < buffer->line_starts.len; i += 1) {
Int range_index = FindRangeByPos(&lines_to_skip_triming, i);
if (range_index != -1) continue;
Range range = GetLineRangeWithoutNL(buffer, i);
char16_t cr = GetChar(buffer, range.max - 1);
char16_t lf = GetChar(buffer, range.max);
if (cr == u'\r' && lf == u'\n') {
AddEdit(&edits, {range.max - 1, range.max}, u"");
}
}
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
view->update_scroll = false;
}
void ApplyClangFormat(Buffer *buffer) {
Scratch scratch;
String string = AllocCharString(scratch, buffer);
Buffer *temp_buffer = ExecAndWait(scratch, "clang-format", GetDir(buffer), string);
ReplaceWithoutMovingCarets(buffer, GetRange(buffer), {temp_buffer->str, temp_buffer->len});
}
void GotoNextInList(Window *window, Int line_offset = 1) {
Assert(line_offset == 1 || line_offset == -1);
View *active_view = GetView(window->active_view);
View *view_goto = GetView(window->active_goto_list);
window->active_view = view_goto->id;
Buffer *buffer_goto = GetBuffer(view_goto->active_buffer);
int64_t pos = window->goto_list_pos;
Int line = PosToLine(buffer_goto, pos);
bool opened = false;
for (Int i = line + line_offset; i >= 0 && i < buffer_goto->line_starts.len; i += line_offset) {
Range line_range = GetLineRangeWithoutNL(buffer_goto, i);
String16 line = GetString(buffer_goto, line_range);
view_goto->carets[0] = MakeCaret(line_range.min);
window->goto_list_pos = line_range.min;
line = Trim(line);
MergeCarets(buffer_goto, &view_goto->carets);
IF_DEBUG(AssertRanges(view_goto->carets));
if (line.len == 0) {
continue;
}
BSet set = Open(line, "dont_error");
if (set.window == NULL) {
continue;
}
opened = true;
break;
}
if (!opened) window->active_view = active_view->id;
}
void New(Window *window, String name = "") {
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
Scratch scratch;
String dir = GetDir(buffer);
if (name != "") {
if (!IsAbsolute(name)) {
name = Format(scratch, "%S/%S", dir, name);
}
name = GetAbsolutePath(scratch, name);
} else {
name = GetUniqueBufferName(dir, "new");
}
WindowOpenBufferView(window, name);
}
void NewDir(Window *window, String name = "") {
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
Scratch scratch;
String dir = GetDir(buffer);
if (name != "") {
if (!IsAbsolute(name)) {
name = Format(scratch, "%S/%S", dir, name);
}
name = GetAbsolutePath(scratch, name);
} else {
name = GetUniqueBufferName(dir, "new");
}
MakeDir(name);
Open(name);
}
View *ExecHidden(String buffer_name, String cmd, String working_dir) {
View *view = OpenBufferView(buffer_name);
Buffer *buffer = GetBuffer(view->active_buffer);
buffer->dont_try_to_save_in_bulk_ops = true;
Exec(view->id, true, cmd, working_dir);
return view;
}
BSet Exec(String cmd, String working_dir, bool set_active = true) {
BSet main = GetBSet(LastActiveLayoutWindowID);
if (set_active) {
NextActiveWindowID = main.window->id;
}
JumpGarbageBuffer(&main);
Exec(main.view->id, true, cmd, working_dir);
return main;
}
BSet ExecBuild(String cmd) {
BSet main = GetBSet(LastActiveLayoutWindowID);
NextActiveWindowID = main.window->id;
View *view = WindowOpenBufferView(main.window, BuildBuffer->name);
ResetBuffer(BuildBuffer);
Exec(view->id, true, cmd, WorkDir);
main.window->active_goto_list = view->id;
main.window->goto_list_pos = 0;
return main;
}
void Command_Build() {
#if OS_WINDOWS
ExecBuild("build.bat");
#else
ExecBuild("./build.sh");
#endif
} RegisterCommand(Command_Build, "f1");
void Command_GotoNextInList() {
BSet main = GetBSet(LastActiveLayoutWindowID);
GotoNextInList(main.window, 1);
} RegisterCommand(Command_GotoNextInList, "ctrl-e");
void Command_GotoPrevInList() {
BSet main = GetBSet(LastActiveLayoutWindowID);
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;
}
ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) {
ResolvedOpen result = {};
// Editor command
{
if (StartsWith(path, ":")) {
result.kind = OpenKind_Command;
result.path = Skip(path, 1);
return result;
}
}
// Shell
{
if (StartsWith(path, "!")) {
result.kind = OpenKind_Exec;
result.path = Skip(path, 1);
return result;
}
}
// Web
{
if (StartsWith(path, "https://") || StartsWith(path, "http://")) {
result.path = Format(scratch, "%S %S", ConfigInternetBrowser, path);
result.kind = OpenKind_BackgroundExec;
return result;
}
}
// Commit
{
if (StartsWith(path, "commit ")) {
path = Skip(path, 7);
result.path = Format(scratch, "git --no-pager show %S", path);
result.kind = OpenKind_Exec;
return result;
}
}
{
String p = NormalizePath(scratch, path);
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 = SkipNumber(&p);
if (At(p, 0) == ':') {
p = Skip(p, 1);
Int b = SkipNumber(&p);
result.col = b;
}
} else if (At(p, 0) == '(') {
p = Skip(p, 1);
result.line = SkipNumber(&p);
if (At(p, 0) == ',') {
p = Skip(p, 1);
Int b = SkipNumber(&p);
result.col = b;
}
}
Buffer *existing_buffer = GetBuffer(path, NULL);
if (existing_buffer != NULL) {
result.path = path;
result.kind = OpenKind_Goto;
return result;
}
if (is_absolute && FileExists(path)) {
result.path = path;
result.kind = OpenKind_Goto;
return result;
} else {
String workspace_path = Format(scratch, "%S/%S", WorkDir, path);
if (GetBuffer(workspace_path, NULL) || FileExists(workspace_path)) {
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)) {
result.path = rel_path;
result.kind = OpenKind_Goto;
return result;
}
}
}
if (meta == "dont_error") {
result.kind = OpenKind_Skip;
return result;
}
return result;
}
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) {
NextActiveWindowID = set.window->id;
}
if (IsDir(o.path)) {
View *view = WindowOpenBufferView(set.window, o.path);
Buffer *buffer = GetBuffer(view->active_buffer);
ResetBuffer(buffer);
RawAppendf(buffer, "..\n");
for (FileIter it = IterateFiles(scratch, o.path); IsValid(it); Advance(&it)) {
RawAppendf(buffer, "%S\n", it.filename);
}
} else {
View *view = WindowOpenBufferView(set.window, o.path);
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});
view->carets[0] = MakeCaret(pos);
}
}
UpdateScroll(set.window, true);
} else if (o.kind == OpenKind_Exec) {
if (set_active) {
NextActiveWindowID = set.window->id;
}
JumpGarbageBuffer(&set);
Exec(set.view->id, true, o.path, GetMainDir());
} else if (o.kind == OpenKind_BackgroundExec) {
// this shouldn't change the focus/window/view
Exec(NullViewID, true, o.path, GetMainDir());
} else if (o.kind == OpenKind_Skip) {
return {};
} else {
ReportWarningf("Failed to open: %S", path);
}
return GetBSet(window);
}
BSet Open(String path, String meta) {
BSet main = GetBSet(LastActiveLayoutWindowID);
main = Open(main.window, path, meta);
return main;
}
BSet Open(String16 path, String meta) {
Scratch scratch;
String string = ToString(scratch, path);
return Open(string, meta);
}
void Command_Save() {
BSet active = GetBSet(LastActiveLayoutWindowID);
SaveBuffer(active.buffer);
} RegisterCommand(Command_Save, "ctrl-s");
void Command_SaveAll() {
For(Buffers) {
if (it->file_mod_time) {
SaveBuffer(it);
}
}
} RegisterCommand(Command_SaveAll, "ctrl-shift-s");
void Command_Reopen() {
BSet main = GetBSet(LastActiveLayoutWindowID);
ReopenBuffer(main.buffer);
NextActiveWindowID = main.window->id;
} RegisterCommand(Command_Reopen, "");
void Command_New() {
BSet main = GetBSet(LastActiveLayoutWindowID);
New(main.window, "");
} RegisterCommand(Command_New, "ctrl-n");
void Command_ToggleFullscreen() {
if (IsInFullscreen) {
SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY);
SDL_SetWindowPosition(SDLWindow, FullScreenPositionX, FullScreenPositionY);
} else {
SDL_GetWindowSize(SDLWindow, &FullScreenSizeX, &FullScreenSizeY);
SDL_GetWindowPosition(SDLWindow, &FullScreenPositionX, &FullScreenPositionY);
SDL_DisplayID display = SDL_GetDisplayForWindow(SDLWindow);
const SDL_DisplayMode *dm = SDL_GetCurrentDisplayMode(display);
SDL_SetWindowSize(SDLWindow, dm->w, dm->h);
SDL_SetWindowPosition(SDLWindow, 0, 0);
}
IsInFullscreen = !IsInFullscreen;
} RegisterCommand(Command_ToggleFullscreen, "f11");
void Command_SetWorkDir() {
BSet main = GetBSet(LastActiveLayoutWindowID);
WorkDir = ChopLastSlash(main.buffer->name);
} RegisterCommand(Command_SetWorkDir, "");
String CodeEndings[] = { ".c", ".cpp", ".h", ".hpp", ".py", ".lua", ".cxx", ".hxx", };
String Coro_OpenCodeDir;
void Coro_OpenCode(mco_coro *co) {
BlockArena arena = {};
Array<String> dirs = {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)) {
if (it.filename == ".git") {
continue;
}
ProfileScopeEx(it.filename);
if (it.is_directory) {
Add(&dirs, it.absolute_path);
} else {
bool match = false;
ForItem (ending, CodeEndings) {
if (EndsWith(it.absolute_path, ending)) {
match = true;
break;
}
}
if (match) {
BufferOpenFile(it.absolute_path);
}
}
CoYield(co);
}
}
Release(&arena);
}
void OpenCode(String dir) {
Coro_OpenCodeDir = dir;
CoAdd(Coro_OpenCode);
}
void Command_OpenCode() {
OpenCode(WorkDir);
} RegisterCommand(Command_OpenCode, "");
void Command_KillProcess() {
BSet main = GetBSet(LastActiveLayoutWindowID);
KillProcess(main.view);
} RegisterCommand(Command_KillProcess, "");
void Command_CloseWindow() {
Close(LastActiveLayoutWindowID);
} RegisterCommand(Command_CloseWindow, "");
SaveResult TrySavingBuffer(Buffer *buffer) {
if (buffer->dirty) {
SaveResult save = SaveMessageBox(buffer->name);
if (save == SAVE_CANCEL) {
return SAVE_CANCEL;
} else if (save == SAVE_YES) {
SaveBuffer(buffer);
return SAVE_YES;
} else {
return SAVE_NO;
}
}
return SAVE_YES;
}
SaveResult TrySavingAllBuffers() {
For (Buffers) {
if (it->garbage || it->special || it->dont_try_to_save_in_bulk_ops) {
continue;
}
if (it->dirty) {
SaveResult save = SaveMessageBox(it->name);
if (save == SAVE_CANCEL) {
return SAVE_CANCEL;
} else if (save == SAVE_YES) {
SaveBuffer(it);
}
}
}
return SAVE_YES;
}
void Command_Close() {
BSet main = GetBSet(LastActiveLayoutWindowID);
if (TrySavingBuffer(main.buffer) == SAVE_CANCEL) {
return;
}
main.window->active_view = FindInactiveView();
Close(main.view->id);
bool ref = false;
For (Views) {
if (it->id == main.view->id) {
continue;
}
if (it->active_buffer == main.buffer->id) {
ref = true;
break;
}
}
if (!ref) {
Close(main.buffer->id);
}
} RegisterCommand(Command_Close, "ctrl-w");
void Command_Quit() {
if (TrySavingAllBuffers() != SAVE_CANCEL) {
AppIsRunning = false;
}
} RegisterCommand(Command_Quit, "");
void Command_CloseAll() {
if (TrySavingAllBuffers() != SAVE_CANCEL) {
For (Views) {
if (it->special) {
continue;
}
Close(it->id);
}
For (Buffers) {
if (it->special) {
continue;
}
Close(it->id);
}
}
} RegisterCommand(Command_CloseAll, "");
void Command_GotoBackward() {
BSet main = GetBSet(LastActiveLayoutWindowID);
main.window->skip_checkpoint = true;
GotoBackward(main.window);
} RegisterCommand(Command_GotoBackward, "alt-q | mousex1");
void Command_GotoForward() {
BSet main = GetBSet(LastActiveLayoutWindowID);
main.window->skip_checkpoint = true;
GotoForward(main.window);
} RegisterCommand(Command_GotoForward, "alt-shift-q | mousex2");
void Command_OpenUpFolder() {
BSet main = GetBSet(LastActiveLayoutWindowID);
String name = ChopLastSlash(main.buffer->name);
Open(name);
} RegisterCommand(Command_OpenUpFolder, "ctrl-period");
void Command_EncloseLine() {
BSet active = GetBSet(ActiveWindowID);
EncloseLine(active.view);
} RegisterCommand(Command_EncloseLine, "ctrl-l");
void Command_SelectAll() {
BSet active = GetBSet(ActiveWindowID);
SelectEntireBuffer(active.view);
active.view->update_scroll = false;
} RegisterCommand(Command_SelectAll, "ctrl-a");
void Command_Redo() {
BSet active = GetBSet(ActiveWindowID);
RedoEdit(active.buffer, &active.view->carets);
} RegisterCommand(Command_Redo, "ctrl-shift-z");
void Command_Undo() {
BSet active = GetBSet(ActiveWindowID);
UndoEdit(active.buffer, &active.view->carets);
} RegisterCommand(Command_Undo, "ctrl-z");
void Command_MakeFontLarger() {
ConfigFontSize += 1;
ReloadFont(ConfigFont, (U32)ConfigFontSize);
} RegisterCommand(Command_MakeFontLarger, "ctrl-equals");
void Command_MakeFontSmaller() {
if (ConfigFontSize > 4) {
ConfigFontSize -= 1;
ReloadFont(ConfigFont, (U32)ConfigFontSize);
}
} RegisterCommand(Command_MakeFontSmaller, "ctrl-minus");
void Command_Open() {
BSet active = GetBSet(ActiveWindowID);
if (active.window->id == CommandWindowID) {
return;
}
Open(FetchLoadWord(active.view));
} RegisterCommand(Command_Open, "ctrl-q");
void Command_KillSelectedLines() {
BSet active = GetBSet(ActiveWindowID);
KillSelectedLines(active.view);
} RegisterCommand(Command_KillSelectedLines, "ctrl-shift-k");
void Command_IndentSelectedLines() {
BSet active = GetBSet(ActiveWindowID);
IndentSelectedLines(active.view);
} RegisterCommand(Command_IndentSelectedLines, "ctrl-rightbracket | tab");
void Command_DedentSelectedLines() {
BSet active = GetBSet(ActiveWindowID);
IndentSelectedLines(active.view, true);
} RegisterCommand(Command_DedentSelectedLines, "ctrl-leftbracket | shift-tab");
void Command_DuplicateLineDown() {
BSet active = GetBSet(ActiveWindowID);
DuplicateLine(active.view, DIR_DOWN);
} RegisterCommand(Command_DuplicateLineDown, "ctrl-alt-down");
void Command_CreateCursorDown() {
BSet active = GetBSet(ActiveWindowID);
CreateCursorVertical(active.view, DIR_DOWN);
} RegisterCommand(Command_CreateCursorDown, "alt-shift-down");
void Command_SelectDownToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(Command_SelectDownToEmptyLine, "ctrl-shift-down");
void Command_MoveLineDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCaretsLine(active.view, DIR_DOWN);
} RegisterCommand(Command_MoveLineDown, "alt-down");
void Command_MoveDownToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED);
} RegisterCommand(Command_MoveDownToEmptyLine, "ctrl-down");
void Command_SelectDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN, false, SHIFT_PRESS);
} RegisterCommand(Command_SelectDown, "shift-down");
void Command_MoveDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN);
} RegisterCommand(Command_MoveDown, "down");
void Command_DuplicateLineUp() {
BSet active = GetBSet(ActiveWindowID);
DuplicateLine(active.view, DIR_UP);
} RegisterCommand(Command_DuplicateLineUp, "ctrl-alt-up");
void Command_CreateCursorUp() {
BSet active = GetBSet(ActiveWindowID);
CreateCursorVertical(active.view, DIR_UP);
} RegisterCommand(Command_CreateCursorUp, "alt-shift-up");
void Command_SelectUpToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(Command_SelectUpToEmptyLine, "ctrl-shift-up");
void Command_MoveLineUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCaretsLine(active.view, DIR_UP);
} RegisterCommand(Command_MoveLineUp, "alt-up");
void Command_MoveUpToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP, CTRL_PRESSED);
} RegisterCommand(Command_MoveUpToEmptyLine, "ctrl-up");
void Command_SelectUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP, false, SHIFT_PRESS);
} RegisterCommand(Command_SelectUp, "shift-up");
void Command_MoveUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP);
} RegisterCommand(Command_MoveUp, "up");
void Command_BoundarySelectLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(Command_BoundarySelectLeft, "ctrl-shift-left");
void Command_BoundaryMoveLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED);
} RegisterCommand(Command_BoundaryMoveLeft, "ctrl-left");
void Command_SelectLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
} RegisterCommand(Command_SelectLeft, "shift-left");
void Command_FocusLeftWindow() {
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
} RegisterCommand(Command_FocusLeftWindow, "alt-left");
void Command_MoveLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT);
} RegisterCommand(Command_MoveLeft, "left");
void Command_BoundarySelectRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(Command_BoundarySelectRight, "ctrl-shift-right");
void Command_BoundaryMoveRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED);
} RegisterCommand(Command_BoundaryMoveRight, "ctrl-right");
void Command_SelectRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
} RegisterCommand(Command_SelectRight, "shift-right");
void Command_FocusRightWindow() {
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
} RegisterCommand(Command_FocusRightWindow, "alt-right");
void Command_MoveRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT);
} RegisterCommand(Command_MoveRight, "right");
void Command_MoveUpAPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_UP);
} RegisterCommand(Command_MoveUpAPage, "pageup");
void Command_SelectUpPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_UP, SHIFT_PRESS);
} RegisterCommand(Command_SelectUpPage, "shift-pageup");
void Command_MoveToStart() {
BSet active = GetBSet(ActiveWindowID);
SelectRange(active.view, MakeRange(0));
} RegisterCommand(Command_MoveToStart, "ctrl-pageup");
void Command_SelectDownPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
} RegisterCommand(Command_SelectDownPage, "shift-pagedown");
void Command_MoveToEnd() {
BSet active = GetBSet(ActiveWindowID);
SelectRange(active.view, MakeRange(active.buffer->len));
} RegisterCommand(Command_MoveToEnd, "ctrl-pagedown");
void Command_MoveDownPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_DOWN);
} RegisterCommand(Command_MoveDownPage, "pagedown");
void Command_SelectToLineStart() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_LEFT, SHIFT_PRESS);
} RegisterCommand(Command_SelectToLineStart, "shift-home");
void Command_MoveToLineStart() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_LEFT);
} RegisterCommand(Command_MoveToLineStart, "home");
void Command_MoveToLineEnd() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_RIGHT);
} RegisterCommand(Command_MoveToLineEnd, "end");
void Command_SelectToLineEnd() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
} RegisterCommand(Command_SelectToLineEnd, "shift-end");
void Command_Delete() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_LEFT);
} RegisterCommand(Command_Delete, "backspace");
void Command_DeleteBoundary() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_LEFT, SHIFT_PRESS);
} RegisterCommand(Command_DeleteBoundary, "ctrl-backspace");
void Command_DeleteForward() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_RIGHT);
} RegisterCommand(Command_DeleteForward, "delete");
void Command_DeleteForwardBoundary() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_RIGHT, SHIFT_PRESS);
} RegisterCommand(Command_DeleteForwardBoundary, "ctrl-delete");
void Command_InsertNewLineUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_LEFT);
IdentedNewLine(active.view);
MoveCarets(active.view, DIR_UP);
} RegisterCommand(Command_InsertNewLineUp, "ctrl-shift-enter");
void Command_InsertNewLineDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_RIGHT);
IdentedNewLine(active.view);
} RegisterCommand(Command_InsertNewLineDown, "ctrl-enter");
void Command_NewLine() {
if (ActiveWindowID == CommandWindowID || ActiveWindowID == SearchWindowID) {
return;
}
BSet active = GetBSet(ActiveWindowID);
IdentedNewLine(active.view);
} RegisterCommand(Command_NewLine, "enter");
void Command_CreateCaretOnNextFind() {
BSet active = GetBSet(ActiveWindowID);
String16 string = GetString(active.buffer, active.view->carets[0].range);
Caret caret = FindNext(active.buffer, string, active.view->carets[0]);
Insert(&active.view->carets, caret, 0);
MergeCarets(active.buffer, &active.view->carets);
} RegisterCommand(Command_CreateCaretOnNextFind, "ctrl-d");
void Command_FocusWindow1() {
NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
} RegisterCommand(Command_FocusWindow1, "ctrl-1");
void Command_FocusWindow2() {
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
} RegisterCommand(Command_FocusWindow2, "ctrl-2");
void Command_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(Command_FocusWindow3, "ctrl-3");
void Command_NewWindow() {
CreateWind();
} RegisterCommand(Command_NewWindow, "ctrl-backslash");
void Command_ClearCarets() {
BSet active = GetBSet(ActiveWindowID);
active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
if (active.window->lose_focus_on_escape && active.window->id == ActiveWindowID) {
if (active.window->layout) {
//
} else {
NextActiveWindowID = LastActiveLayoutWindowID;
}
}
For (Windows) {
if (it->lose_visibility_on_escape && it->visible) {
it->visible = false;
}
}
} RegisterCommand(Command_ClearCarets, "escape");