Lua.OnSave, GetViewForFixingWhenBufferCommand
This commit is contained in:
@@ -99,9 +99,21 @@ void MouseLoadWord(Event event, void (*cmd_function)(String16 string)) {
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
|
||||
Scratch scratch;
|
||||
View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL) {
|
||||
View *view = NULL;
|
||||
if (is_active) {
|
||||
*is_active = false;
|
||||
}
|
||||
|
||||
Window *active_window = GetWindow(ActiveWindow);
|
||||
View *active_view = GetView(active_window->active_view);
|
||||
if (active_view->active_buffer == buffer->id) {
|
||||
if (is_active) {
|
||||
*is_active = true;
|
||||
}
|
||||
return active_view;
|
||||
}
|
||||
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
if (it->active_buffer != buffer->id) {
|
||||
continue;
|
||||
@@ -114,8 +126,14 @@ void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
|
||||
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;
|
||||
Command_SelectRangeOneCursor(view, range);
|
||||
Array<Edit> edits = Command_ReplaceEx(scratch, view, string);
|
||||
|
||||
@@ -559,15 +577,22 @@ void Command_IndentSelectedLines(View *view, bool shift = false) {
|
||||
view->update_scroll = false;
|
||||
}
|
||||
|
||||
void Command_TrimTrailingWhitespace(View *view, bool dont_trim_lines_with_cursor) {
|
||||
void TrimTrailingWhitespace(Buffer *buffer, bool trim_lines_with_caret = false) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
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 (dont_trim_lines_with_cursor) lines_to_skip_triming = GetSelectedLinesSorted(scratch, view);
|
||||
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);
|
||||
@@ -588,16 +613,31 @@ void Command_TrimTrailingWhitespace(View *view, bool dont_trim_lines_with_cursor
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
view->update_scroll = false;
|
||||
}
|
||||
int Lua_TrimTrailingWhitespace(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
int trim_lines_with_caret = lua_toboolean(L, 2);
|
||||
lua_pop(L, 2);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
TrimTrailingWhitespace(buffer, trim_lines_with_caret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_ConvertLineEndings(View *view, bool dont_trim_lines_with_cursor) {
|
||||
void ConvertLineEndingsToLF(Buffer *buffer, bool trim_lines_with_caret = false) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
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 (dont_trim_lines_with_cursor) lines_to_skip_triming = GetSelectedLinesSorted(scratch, view);
|
||||
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);
|
||||
@@ -613,27 +653,39 @@ void Command_ConvertLineEndings(View *view, bool dont_trim_lines_with_cursor) {
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
view->update_scroll = false;
|
||||
}
|
||||
|
||||
bool IsCFile(String name) {
|
||||
bool result = EndsWith(name, ".cpp") || EndsWith(name, ".c") || EndsWith(name, ".hpp") || EndsWith(name, ".h");
|
||||
return result;
|
||||
int Lua_ConvertLineEndingsToLF(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
int trim_lines_with_caret = lua_toboolean(L, 2);
|
||||
lua_pop(L, 2);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
ConvertLineEndingsToLF(buffer, trim_lines_with_caret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SaveBuffer(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
bool dont_trim_lines_with_cursor = true;
|
||||
Command_ConvertLineEndings(view, dont_trim_lines_with_cursor);
|
||||
if (StyleTrimWhitespaceOnSave) {
|
||||
Command_TrimTrailingWhitespace(view, dont_trim_lines_with_cursor);
|
||||
Assert(view->active_buffer == buffer->id);
|
||||
}
|
||||
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});
|
||||
}
|
||||
int Lua_ApplyClangFormat(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
ApplyClangFormat(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (StyleClangFormatOnSave && IsCFile(buffer->name)) {
|
||||
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});
|
||||
}
|
||||
int Lua_GetBufferNameByID(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
lua_pushlstring(L, buffer->name.data, buffer->name.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SaveBuffer(Buffer *buffer) {
|
||||
CallOnSave(buffer->id);
|
||||
|
||||
Scratch scratch;
|
||||
String string = AllocCharString(scratch, buffer);
|
||||
@@ -647,6 +699,14 @@ void SaveBuffer(View *view) {
|
||||
ReportWarningf("Failed to save file with name: %.*s", FmtString(buffer->name));
|
||||
}
|
||||
}
|
||||
void Command_Save() {
|
||||
BSet set = GetActiveMainSet();
|
||||
SaveBuffer(set.buffer);
|
||||
}
|
||||
int Lua_Save(lua_State *L) {
|
||||
Command_Save();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_KillSelectedLines(View *view) {
|
||||
Scratch scratch;
|
||||
@@ -956,8 +1016,7 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
|
||||
Scratch scratch;
|
||||
BSet set = GetBSet(window);
|
||||
OnOpenResult ores = CallOnOpen(path, meta);
|
||||
String kind = FieldString(LuaState, "kind");
|
||||
if (kind == "text") {
|
||||
if (ores.kind == "text") {
|
||||
if (set_active) {
|
||||
ActiveWindow = set.window->id;
|
||||
}
|
||||
@@ -978,16 +1037,16 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
|
||||
}
|
||||
}
|
||||
UpdateScroll(set.window, true);
|
||||
} else if (kind == "exec") {
|
||||
} else if (ores.kind == "exec") {
|
||||
if (set_active) {
|
||||
ActiveWindow = set.window->id;
|
||||
}
|
||||
JumpGarbageBuffer(&set);
|
||||
Exec(set.view->id, true, ores.cmd, ores.working_dir);
|
||||
} else if (kind == "exec_console") {
|
||||
} else if (ores.kind == "exec_console") {
|
||||
// this shouldn't change the focus/window/view
|
||||
Exec(NullViewID, true, ores.cmd, ores.working_dir);
|
||||
} else if (kind == "skip") {
|
||||
} else if (ores.kind == "skip") {
|
||||
return {};
|
||||
} else {
|
||||
ReportWarningf("Failed to match any of OnOpen results!");
|
||||
|
||||
@@ -661,7 +661,7 @@ void OnCommand(Event event) {
|
||||
|
||||
|
||||
if (CtrlPress(SDLK_S)) {
|
||||
SaveBuffer(active.view);
|
||||
SaveBuffer(active.buffer);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_PERIOD)) {
|
||||
|
||||
@@ -64,12 +64,13 @@ Style.WaitForEvents = 1
|
||||
Style.DrawLineNumbers = 1
|
||||
Style.DrawScrollbar = 1
|
||||
Style.IndentSize = 4
|
||||
Style.TrimWhitespaceOnSave = 1
|
||||
Style.ClangFormatOnSave = 0
|
||||
Style.FontSize = 15
|
||||
Style.FontFilter = 0
|
||||
Style.Font = "C:/Windows/Fonts/consola.ttf"
|
||||
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
|
||||
Style.TrimWhitespaceOnSave = true
|
||||
Style.ClangFormatOnSave = false
|
||||
|
||||
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
|
||||
|
||||
SDLK_CTRL = 1073742048
|
||||
@@ -357,6 +358,19 @@ end
|
||||
|
||||
function OnInit()
|
||||
end
|
||||
|
||||
function OnSave(buffer_id)
|
||||
local dont_trim_lines_with_caret = false
|
||||
ConvertLineEndingsToLF(buffer_id, dont_trim_lines_with_caret)
|
||||
if Style.TrimWhitespaceOnSave then
|
||||
TrimTrailingWhitespace(buffer_id, dont_trim_lines_with_caret)
|
||||
end
|
||||
|
||||
local name = GetBufferNameByID(buffer_id)
|
||||
if Style.ClangFormatOnSave and (name:match(".c$") or name:match(".h$") or name:match(".cpp$") or name:match(".hpp$")) then
|
||||
ApplyClangFormat(buffer_id)
|
||||
end
|
||||
end
|
||||
)==";
|
||||
void ReloadStyle() {
|
||||
ColorText = GetColor("Text", ColorText);
|
||||
@@ -385,8 +399,6 @@ void ReloadStyle() {
|
||||
StyleDrawLineNumbers = GetStyleInt("DrawLineNumbers", StyleDrawLineNumbers);
|
||||
StyleDrawScrollbar = GetStyleInt("DrawScrollbar", StyleDrawScrollbar);
|
||||
StyleIndentSize = GetStyleInt("IndentSize", StyleIndentSize);
|
||||
StyleTrimWhitespaceOnSave = GetStyleInt("TrimWhitespaceOnSave", StyleTrimWhitespaceOnSave);
|
||||
StyleClangFormatOnSave = GetStyleInt("ClangFormatOnSave", StyleClangFormatOnSave);
|
||||
StyleFontSize = GetStyleInt("FontSize", StyleFontSize);
|
||||
StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter);
|
||||
StyleFont = GetStyleString("Font", StyleFont);
|
||||
|
||||
@@ -61,8 +61,6 @@ Int StyleWaitForEvents = 1;
|
||||
Int StyleDrawLineNumbers = 1;
|
||||
Int StyleDrawScrollbar = 1;
|
||||
Int StyleIndentSize = 4;
|
||||
Int StyleTrimWhitespaceOnSave = 1;
|
||||
Int StyleClangFormatOnSave = 0;
|
||||
Int StyleFontSize = 15;
|
||||
Int StyleFontFilter = 0;
|
||||
String StyleFont = "C:/Windows/Fonts/consola.ttf";
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
String FieldString(lua_State *L, String name) {
|
||||
String result = {};
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushlstring(L, name.data, name.len);
|
||||
lua_gettable(L, -2);
|
||||
defer { lua_pop(L, 1); };
|
||||
if (lua_isstring(L, -1)) {
|
||||
result = lua_tostring(L, -1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Lua_Print(lua_State *L) {
|
||||
Scratch scratch;
|
||||
int nargs = lua_gettop(L);
|
||||
@@ -197,6 +184,19 @@ Color GetColor(String name, Color default_color) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetFieldString(lua_State *L, String name) {
|
||||
String result = {};
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushlstring(L, name.data, name.len);
|
||||
lua_gettable(L, -2);
|
||||
defer { lua_pop(L, 1); };
|
||||
if (lua_isstring(L, -1)) {
|
||||
result = lua_tostring(L, -1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Int GetInt(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
lua_Integer num = lua_tointeger(L, -1);
|
||||
@@ -300,7 +300,18 @@ void ReloadLuaConfigs() {
|
||||
}
|
||||
}
|
||||
|
||||
bool CallLuaFunc(char *func_name, int arg_count, int ret_count) {
|
||||
if (lua_pcall(LuaState, arg_count, ret_count, 0) != 0) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed to call a lua function: %s! %s", func_name, error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct OnOpenResult {
|
||||
String kind;
|
||||
String file_path;
|
||||
Int line, col;
|
||||
String working_dir;
|
||||
@@ -311,18 +322,16 @@ OnOpenResult CallOnOpen(String path, String meta) {
|
||||
lua_getglobal(LuaState, "OnOpen");
|
||||
lua_pushlstring(LuaState, path.data, path.len);
|
||||
lua_pushlstring(LuaState, meta.data, meta.len);
|
||||
if (lua_pcall(LuaState, 2, 1, 0) != 0) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed the call to OnOpen! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
if (!CallLuaFunc("OnOpen", 2, 1)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
String file_path = FieldString(LuaState, "file_path");
|
||||
String line_string = FieldString(LuaState, "line");
|
||||
String col_string = FieldString(LuaState, "col");
|
||||
String cmd = FieldString(LuaState, "cmd");
|
||||
String working_dir = FieldString(LuaState, "working_dir");
|
||||
String file_path = GetFieldString(LuaState, "file_path");
|
||||
String line_string = GetFieldString(LuaState, "line");
|
||||
String col_string = GetFieldString(LuaState, "col");
|
||||
String cmd = GetFieldString(LuaState, "cmd");
|
||||
String working_dir = GetFieldString(LuaState, "working_dir");
|
||||
String kind = GetFieldString(LuaState, "kind");
|
||||
|
||||
OnOpenResult result = {};
|
||||
result.cmd = cmd;
|
||||
@@ -330,38 +339,32 @@ OnOpenResult CallOnOpen(String path, String meta) {
|
||||
result.file_path = file_path;
|
||||
if (col_string.len) result.col = strtoll(col_string.data, NULL, 10);
|
||||
if (line_string.len) result.line = strtoll(line_string.data, NULL, 10);
|
||||
result.kind = kind;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CallOnSave(BufferID buffer_id) {
|
||||
lua_getglobal(LuaState, "OnSave");
|
||||
lua_pushinteger(LuaState, buffer_id.id);
|
||||
CallLuaFunc("OnSave", 1, 0);
|
||||
}
|
||||
|
||||
void CallOnCommand(Event *event) {
|
||||
lua_getglobal(LuaState, "OnCommand");
|
||||
PushEvent(LuaState, event);
|
||||
if (lua_pcall(LuaState, 1, 0, 0) != 0) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed the call to OnCommand! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
return;
|
||||
}
|
||||
CallLuaFunc("OnCommand", 1, 0);
|
||||
}
|
||||
|
||||
void CallLuaOnUpdate(Event *event) {
|
||||
lua_getglobal(LuaState, "OnUpdate");
|
||||
PushEvent(LuaState, event);
|
||||
if (lua_pcall(LuaState, 1, 0, 0) != 0) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed the call to OnUpdate! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
return;
|
||||
}
|
||||
CallLuaFunc("OnUpdate", 1, 0);
|
||||
}
|
||||
|
||||
void CallLuaOnInit() {
|
||||
if (luaL_dostring(LuaState, "OnInit()") != LUA_OK) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportErrorf("Error in OnInit! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
lua_getglobal(LuaState, "OnInit");
|
||||
CallLuaFunc("OnInit", 0, 0);
|
||||
}
|
||||
|
||||
void InitLuaConfig() {
|
||||
|
||||
@@ -14,6 +14,11 @@ luaL_Reg LuaFunctions[] = {
|
||||
{"GetMainDir", Lua_GetMainDir},
|
||||
{"SplitSize", Lua_SplitSize},
|
||||
{"Play", Lua_Play},
|
||||
{"TrimTrailingWhitespace", Lua_TrimTrailingWhitespace},
|
||||
{"ConvertLineEndingsToLF", Lua_ConvertLineEndingsToLF},
|
||||
{"ApplyClangFormat", Lua_ApplyClangFormat},
|
||||
{"GetBufferNameByID", Lua_GetBufferNameByID},
|
||||
{"Save", Lua_Save},
|
||||
{"Reopen", Lua_Reopen},
|
||||
{"ToggleFullscreen", Lua_ToggleFullscreen},
|
||||
{"GetCFiles", Lua_GetCFiles},
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
- Changing window properties by changing the window name?
|
||||
- Scroll the console properly
|
||||
- commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top
|
||||
- organize commands and lua bindings somehow, it's kinda confusing right now, maybe group command->luacommand, the command name implies it also doubles as lua command?
|
||||
- Add metadata to Lua bindings so that we would get a better listing (function args?, what else?)
|
||||
- rules, interface for opening files using the F4 (aka next path from build output)
|
||||
- for now add ./ and .\ to valid line starters
|
||||
- Kill buffer command (it should be marked for deletion and deleted at the end of frame!)
|
||||
- Delete directory/file on disk command
|
||||
- Create directory command (probably should enter it automatically
|
||||
- Convert more commands to taking buffer instead of view
|
||||
- Check. Convert more commands to taking buffer instead of view
|
||||
- Check. Rewrite more commands to use already implemented commands?
|
||||
|
||||
- Command that will select a lua (block|function|line)? and eval
|
||||
|
||||
- save all relevant buffers and build
|
||||
- shift down on last line should move the cursor to end of line!!! same for up
|
||||
- maybe most of the bindings should be in lua, but actual code in C
|
||||
- LoadWord, EncloseWord configurable?
|
||||
- dump text editor state to file, restore state
|
||||
@@ -45,7 +44,6 @@ backlog
|
||||
- text_editor --record events.txt text_editor --playback events.txt
|
||||
- make the editor replayable, store events and then replay, be careful about globals
|
||||
- maybe open should return multiple options if there are many more? (like in sublime if many symbols you get a window and you choose and it automatically jumps you to the symbol in the background)
|
||||
- we could rewrite kill lines with simpler commands - extend selection to encompass lines->replace
|
||||
- I want a way to assign flags to buffers/views/windows from user perspective so that console window concept can be created from user space
|
||||
- font cache and on demand unicode loads
|
||||
- color parens, braces
|
||||
|
||||
Reference in New Issue
Block a user