Files
text_editor/build_file.cpp

655 lines
19 KiB
C++

#include "src/build_tool/library.cpp"
enum {
PROFILE_DEBUG,
PROFILE_RELEASE,
};
int Profile = PROFILE_DEBUG;
S8_String Compiler = "cl.exe";
void AddCommonFlags(Array<S8_String> *cmd) {
if (Compiler == "cl.exe") {
cmd->add("/MP");
}
cmd->add("/Zi /FC /nologo");
cmd->add("/WX /W3 /wd4200 /diagnostics:column");
if (Compiler == "clang-cl.exe") {
cmd->add("-fdiagnostics-absolute-paths");
cmd->add("-Wno-missing-braces");
cmd->add("-Wno-writable-strings");
cmd->add("-Wno-unused-function");
}
cmd->add("/Oi");
cmd->add("-D_CRT_SECURE_NO_WARNINGS");
if (Profile == PROFILE_DEBUG) {
cmd->add("-DDEBUG_BUILD=1");
cmd->add("-DRELEASE_BUILD=0");
// cmd->add("-fsanitize=address");
// cmd->add("-DUSE_ADDRESS_SANITIZER");
// cmd->add("/MDd");
} else {
cmd->add("-DDEBUG_BUILD=0");
cmd->add("-DRELEASE_BUILD=1");
cmd->add("/O2 /MT /DNDEBUG /GL");
}
}
struct Library {
Array<S8_String> sources;
Array<S8_String> objects;
Array<S8_String> include_paths;
Array<S8_String> defines;
Array<S8_String> link;
};
Library PrepareSDL() {
Library l = {};
l.include_paths.add("../src/external/SDL/include");
l.objects.add("../src/external/SDL/VisualC/static_x64/Release/SDL3.lib");
l.link.add("/SUBSYSTEM:WINDOWS");
l.link.add("opengl32.lib");
l.link.add("imm32.lib");
l.link.add("gdi32.lib");
l.link.add("winmm.lib");
l.link.add("shell32.lib");
l.link.add("user32.lib");
l.link.add("advapi32.lib");
l.link.add("Setupapi.lib");
l.link.add("ole32.lib");
l.link.add("oleaut32.lib");
l.link.add("Version.lib");
return l;
}
Library PrepareSDLDynamic() {
Library l = {};
l.include_paths.add("../src/external/SDL/include");
l.objects.add("../src/external/SDL/VisualC/x64/Release/SDL3.lib");
l.link.add("/SUBSYSTEM:WINDOWS");
OS_CopyFile("../src/external/SDL/VisualC/x64/Release/SDL3.dll", "./SDL3.dll", false);
return l;
}
Library PrepareRaylib() {
Library l = {};
l.include_paths.add("../src/external/raylib/include");
if (0) {
l.objects.add("../src/external/raylib/lib/raylib.lib");
} else {
l.objects.add("../src/external/raylib/lib/raylibdll.lib");
OS_CopyFile("../src/external/raylib/lib/raylib.dll", "./raylib.dll", false);
}
return l;
}
Library PrepareLua() {
Library l = {};
l.include_paths.add("../src/external/lua/src");
MA_Scratch scratch;
for (OS_FileIter it = OS_IterateFiles(scratch, "../src/external/lua/src"); OS_IsValid(it); OS_Advance(&it)) {
if (it.filename == "luac.c") continue;
if (it.filename == "lua.c") continue;
if (S8_EndsWith(it.filename, ".c", true)) {
l.sources.add(it.absolute_path);
S8_String file = S8_ChopLastPeriod(it.filename);
l.objects.add(Fmt("%.*s.obj", S8_Expand(file)));
}
}
if (!OS_FileExists(l.objects[0])) {
Array<S8_String> cmd = {};
cmd.add(Compiler);
cmd.add("-c");
AddCommonFlags(&cmd);
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
cmd += l.sources;
Run(cmd);
}
return l;
}
Library PrepareGlad() {
Library l = {};
l.sources.add("../src/external/glad/glad.c");
l.include_paths.add("../src/external/glad/");
l.objects.add("glad.obj");
if (!OS_FileExists(l.objects[0])) {
Array<S8_String> cmd = {};
cmd.add(Compiler);
cmd.add("-c");
AddCommonFlags(&cmd);
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
cmd += l.sources;
Run(cmd);
}
return l;
}
int CompileTextEditor() {
int result = 0;
Array<Library> libs = {};
// if (Profile == PROFILE_DEBUG) libs.add(PrepareSDLDynamic());
// else
libs.add(PrepareSDL());
libs.add(PrepareLua());
libs.add(PrepareGlad());
Array<S8_String> cmd = {};
cmd.add(Compiler);
cmd.add("-Fe:te.exe");
cmd.add("-Fd:te.pdb");
cmd.add("-I ../src");
AddCommonFlags(&cmd);
For2(lib, libs) For(lib.defines) cmd.add(it);
cmd.add("../src/text_editor/text_editor.cpp");
cmd.add("../src/basic/win32.cpp");
For2(lib, libs) For(lib.include_paths) cmd.add(Fmt("-I %.*s", S8_Expand(it)));
cmd.add("/link");
cmd.add("/incremental:no");
// cmd.add("/SUBSYSTEM:WINDOWS");
// cmd.add("opengl32.lib gdi32.lib winmm.lib shell32.lib user32.lib msvcrt.lib /NODEFAULTLIB:LIBCMT");
For2(lib, libs) For(lib.link) cmd.add(it);
For(libs) For2(o, it.objects) cmd.add(o);
cmd.add("icon.res");
OS_DeleteFile("te.pdb");
// For(cmd) IO_Printf("%.*s\n", S8_Expand(it));
if (!OS_FileExists("icon.res")) {
OS_CopyFile("../data/icon.ico", "icon.ico", true);
OS_CopyFile("../data/icon.rc", "icon.rc", true);
Run("rc icon.rc");
}
result += Run(cmd);
if (result == 0) {
OS_MakeDir("../package");
OS_CopyFile("../build/te.exe", "../package/te.exe", true);
OS_CopyFile("../build/te.pdb", "../package/te.pdb", true);
}
return result;
}
char *C(const char *value) {
if (value[0] == '0' && value[1] == 'x') {
S8_String f = Fmt("{0x%.*s, 0x%.*s, 0x%.*s, 0x%.*s}", 2, value + 2, 2, value + 4, 2, value + 6, 2, value + 8);
return f.str;
} else {
return (char *)value;
}
}
S8_String LuaScript = R"==(
SDLK_CTRL = 1073742048
SDLK_PAGE_DOWN = 1073741902
SDLK_PAGE_UP = 1073741899
SDLK_DOWN = 1073741905 -- 0x40000051
SDLK_UP = 1073741906 -- 0x40000052u
SDLK_RIGHT = 1073741903
SDLK_LEFT = 1073741904
SDLK_Q = 113
SDLK_BACKSLASH = 0x5c
SDLK_RETURN = 13
SDLK_F1 = 0x4000003a
SDLK_F2 = 0x4000003b
SDLK_F3 = 0x4000003c
SDLK_F4 = 0x4000003d
SDLK_F5 = 0x4000003e
SDLK_F6 = 0x4000003f
SDLK_F7 = 0x40000040
SDLK_F8 = 0x40000041
SDLK_F9 = 0x40000042
SDLK_F10 = 0x40000043
SDLK_F11 = 0x40000044
SDLK_F12 = 0x40000045
SDLK_A = 0x00000061
SDLK_B = 0x00000062
SDLK_C = 0x00000063
SDLK_D = 0x00000064
SDLK_E = 0x00000065
SDLK_F = 0x00000066
SDLK_G = 0x00000067
SDLK_H = 0x00000068
SDLK_I = 0x00000069
SDLK_J = 0x0000006a
SDLK_K = 0x0000006b
SDLK_L = 0x0000006c
SDLK_M = 0x0000006d
SDLK_N = 0x0000006e
SDLK_O = 0x0000006f
SDLK_P = 0x00000070
SDLK_Q = 0x00000071
SDLK_R = 0x00000072
SDLK_S = 0x00000073
SDLK_T = 0x00000074
SDLK_U = 0x00000075
SDLK_V = 0x00000076
SDLK_W = 0x00000077
SDLK_X = 0x00000078
SDLK_Y = 0x00000079
SDLK_Z = 0x0000007a
function SkipLineAndColumn(s)
local line, col = "1", "1"
function parse_line_and_column(line_and_col, delimiter)
ic, jc = line_and_col:find(delimiter)
line = line_and_col:sub(1, ic - 1)
col = line_and_col:sub(ic + 1)
return line, col
end
do -- :line:column
local i, j = s:find("^:%d+:%d+")
if i then
skip_pattern = s:sub(j + 1)
line, col = parse_line_and_column(s:sub(2, j), ":")
return line, col, skip_pattern
end
end
do -- :line
local i, j = s:find("^:%d+")
if i then
skip_pattern = s:sub(j + 1)
line = s:sub(2, j)
return line, col, skip_pattern
end
end
do -- (line,column)
local i, j = s:find("^%(%d+,%d+%)")
if i then
skip_pattern = s:sub(j + 1)
line, col = parse_line_and_column(s:sub(2, j - 1), ",")
return line, col, skip_pattern
end
end
do -- (line)
local i, j = s:find("^%(%d+%)")
if i then
skip_pattern = s:sub(j + 1)
line = s:sub(2, j - 1)
return line, col, skip_pattern
end
end
return line, col, s
end
function SkipSlashes(s)
found_slash = false
while s:sub(1,1) == '/' or s:sub(1,1) == '\\' do
s = s:sub(2)
found_slash = true
end
return s, found_slash
end
function SkipDrive(s)
local i, j = s:find("^%a:")
if not i then return s, nil, true end
local drive = s:sub(i, j)
local new_s = s:sub(j + 1)
new_s, found_slash = SkipSlashes(new_s)
if not found_slash then return s, drive, false end
return new_s, drive, true
end
function SkipPathCell(s)
local i, j = s:find("^[%w_%.-% +]+")
if not i then return s, nil, false end
local word = s:sub(i, j)
local new_s = s:sub(j + 1)
local new_s, found_slash = SkipSlashes(new_s)
return new_s, word, found_slash
end
function SkipPath(s)
local input_s = s
local s, drive, ok = SkipDrive(s)
if not ok then return s end
local cells = {}
while true do
s, word, slash_eaten = SkipPathCell(s)
if word then cells[#cells + 1] = word end
if not slash_eaten then break end
end
if #cells == 0 then return s end
local skip_size = input_s:len() - s:len()
local path = input_s:sub(1, skip_size)
return s, path, drive, cells
end
function BufferNameExists(name)
buffers = GetBufferList()
for i = 1,#buffers do
buff = buffers[i]
if buff == name then
return true
end
end
return false
end
function MatchWindowsPath(_s)
local s, file_path, drive = SkipPath(_s)
if not file_path then return nil end
if not drive then
local d = GetActiveMainWindowBufferDir()
file_path = d..'/'..file_path
end
local line, col, s = SkipLineAndColumn(s)
local exists = FileExists(file_path) or BufferNameExists(file_path)
if not exists then return nil end
Print("OPEN :: INPUT = ".._s.." KIND = ".."text".." ".."FILE_PATH = "..file_path.."["..line..","..col.."]")
return {kind = "text", file_path = file_path, line = line, col = col}
end
function MatchGitCommit(s)
local i, j = string.find(s, "^commit ([a-zA-Z0-9]+)")
if i then
s = s:sub(8)
local command = "git --no-pager show "..s
return {kind = "exec", cmd = command, working_dir = GetActiveMainWindowBufferDir()}
end
return nil
end
InternetBrowser = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
function MatchURL(s)
local i, j = string.find(s, "^https://")
if i then
return {kind = "exec_console", cmd = '"'..InternetBrowser..'" '..s, working_dir = GetActiveMainWindowBufferDir()}
end
return nil
end
Rules = {
MatchWindowsPath,
MatchGitCommit,
MatchURL,
}
function ApplyRules(s)
for i = #Rules,1,-1 do
rule = Rules[i]
result = rule(s)
if result then
return result
end
end
return nil
end
function IsWhitespace(w)
local result = w == string.byte('\n') or
w == string.byte(' ') or
w == string.byte('\t') or
w == string.byte('\v') or
w == string.byte('\r')
return result
end
function IsSymbol(w)
local result = (w >= string.byte('!') and w <= string.byte('/')) or
(w >= string.byte(':') and w <= string.byte('@')) or
(w >= string.byte('[') and w <= string.byte('`')) or
(w >= string.byte('{') and w <= string.byte('~'))
return result
end
function IsLoadWord(w)
local result = w == string.byte('(') or
w == string.byte(')') or
w == string.byte('/') or
w == string.byte('\\') or
w == string.byte(':') or
w == string.byte('+') or
w == string.byte('_') or
w == string.byte('.') or
w == string.byte('-') or
w == string.byte(',') or
w == string.byte('"') or
w == string.byte("'")
if not result then
result = not (IsSymbol(w) or IsWhitespace(w))
end
return result
end
Coroutines = {}
function AddCo(f)
local i = #Coroutines + 1
Coroutines[i] = coroutine.create(f)
coroutine.resume(Coroutines[i])
return Coroutines[i]
end
function OnUpdate(e)
local new_co_list = {}
for key, co in pairs(Coroutines) do
local status = coroutine.status(co)
if status ~= "dead" then
coroutine.resume(co, e)
new_co_list[#new_co_list + 1] = co
end
end
Coroutines = new_co_list
end
OnCommandCallbacks = {}
table.insert(OnCommandCallbacks, function (e)
if e.key == SDLK_F and e.ctrl == 1 and e.shift == 1 then
C("git grep -n "..GetLoadWord().." :/") end
if e.key == SDLK_L and e.ctrl == 1 then
Eval(GetLoadWord()) end
if e.key == SDLK_B and e.ctrl == 1 then
C(GetLoadWord()) end
end)
-- REMEBER: AS LITTLE ACTUAL CODE AS POSSIBLE IN LUA
-- ONLY CONFIGURABLES
function OnCommand(e)
for i = #OnCommandCallbacks,1,-1 do
on_command = OnCommandCallbacks[i]
on_command(e)
end
end
function OnInit()
end
)==";
void GenerateConfig() {
struct Var {
const char *name;
const char *value;
};
Array<Var> gruvbox = {};
gruvbox.add({"GruvboxDark0Hard", "0x1d2021ff"});
gruvbox.add({"GruvboxDark0", "0x282828ff"});
gruvbox.add({"GruvboxDark0Soft", "0x32302fff"});
gruvbox.add({"GruvboxDark1", "0x3c3836ff"});
gruvbox.add({"GruvboxDark2", "0x504945ff"});
gruvbox.add({"GruvboxDark3", "0x665c54ff"});
gruvbox.add({"GruvboxDark4", "0x7c6f64ff"});
gruvbox.add({"GruvboxGray245", "0x928374ff"});
gruvbox.add({"GruvboxGray244", "0x928374ff"});
gruvbox.add({"GruvboxLight0Hard", "0xf9f5d7ff"});
gruvbox.add({"GruvboxLight0", "0xfbf1c7ff"});
gruvbox.add({"GruvboxLight0Soft", "0xf2e5bcff"});
gruvbox.add({"GruvboxLight1", "0xebdbb2ff"});
gruvbox.add({"GruvboxLight2", "0xd5c4a1ff"});
gruvbox.add({"GruvboxLight3", "0xbdae93ff"});
gruvbox.add({"GruvboxLight4", "0xa89984ff"});
gruvbox.add({"GruvboxBrightRed", "0xfb4934ff"});
gruvbox.add({"GruvboxBrightGreen", "0xb8bb26ff"});
gruvbox.add({"GruvboxBrightYellow", "0xfabd2fff"});
gruvbox.add({"GruvboxBrightBlue", "0x83a598ff"});
gruvbox.add({"GruvboxBrightPurple", "0xd3869bff"});
gruvbox.add({"GruvboxBrightAqua", "0x8ec07cff"});
gruvbox.add({"GruvboxBrightOrange", "0xfe8019ff"});
gruvbox.add({"GruvboxNeutralRed", "0xcc241dff"});
gruvbox.add({"GruvboxNeutralGreen", "0x98971aff"});
gruvbox.add({"GruvboxNeutralYellow", "0xd79921ff"});
gruvbox.add({"GruvboxNeutralBlue", "0x458588ff"});
gruvbox.add({"GruvboxNeutralPurple", "0xb16286ff"});
gruvbox.add({"GruvboxNeutralAqua", "0x689d6aff"});
gruvbox.add({"GruvboxNeutralOrange", "0xd65d0eff"});
gruvbox.add({"GruvboxFadedRed", "0x9d0006ff"});
gruvbox.add({"GruvboxFadedGreen", "0x79740eff"});
gruvbox.add({"GruvboxFadedYellow", "0xb57614ff"});
gruvbox.add({"GruvboxFadedBlue", "0x076678ff"});
gruvbox.add({"GruvboxFadedPurple", "0x8f3f71ff"});
gruvbox.add({"GruvboxFadedAqua", "0x427b58ff"});
gruvbox.add({"GruvboxFadedOrange", "0xaf3a03ff"});
Array<Var> colors = {};
colors.add({"Text", "GruvboxDark0Hard"});
colors.add({"LoadTextHighlight", "0x0000000F"});
colors.add({"Background", "GruvboxLight0Hard"});
colors.add({"InactiveWindow", "0x0000000F"});
colors.add({"TextLineNumbers", "GruvboxDark4"});
colors.add({"LineHighlight", "GruvboxLight0Soft"});
colors.add({"MainCaret", "GruvboxDark0Hard"});
colors.add({"SubCaret", "GruvboxGray245"});
colors.add({"Selection", "GruvboxLight1"});
colors.add({"WhitespaceDuringSelection", "GruvboxLight4"});
colors.add({"MouseUnderline", "GruvboxDark0Hard"});
colors.add({"CaretUnderline", "GruvboxGray245"});
colors.add({"FuzzySearchLineHighlight", "GruvboxDark0"});
colors.add({"ScrollbarBackground", "GruvboxLight2"});
colors.add({"ScrollbarScroller", "GruvboxLight1"});
colors.add({"ScrollbarScrollerSelected", "GruvboxLight0Hard"});
colors.add({"TitleBarText", "GruvboxDark2"});
colors.add({"TitleBarBackground", "GruvboxLight1"});
colors.add({"TitleBarSelection", "GruvboxLight3"});
Array<Var> style = {};
style.add({"WaitForEvents", "1"});
style.add({"DrawLineNumbers", "1"});
style.add({"DrawScrollbar", "1"});
style.add({"IndentSize", "4"});
style.add({"TrimWhitespaceOnSave", "1"});
style.add({"ClangFormatOnSave", "0"});
style.add({"FontSize", "12"});
style.add({"FontFilter", "0"}); // nearest = 0, linear = 1 - seems like nearest always better?
style.add({"Font", "C:/Windows/Fonts/consola.ttf"});
style.add({"VCVarsall", "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvars64.bat"});
{
MA_Scratch scratch;
Array<S8_String> sb = {MA_GetAllocator(scratch)};
{
For(gruvbox) sb.add(Fmt("Color %s = %s;", it.name, C(it.value)));
For(colors) sb.add(Fmt("Color Color%s = %s;", it.name, C(it.value)));
For(style) {
if (CHAR_IsDigit(it.value[0])) sb.add(Fmt("Int Style%s = %s;", it.name, it.value));
else sb.add(Fmt("String Style%s = \"%s\";", it.name, it.value));
}
}
S8_String string = Merge(scratch, sb, "\n");
OS_WriteFile("../src/text_editor/generated_variables.cpp", string);
sb = {};
sb.add("String BaseLuaConfig = R\"==(");
{
For(gruvbox) sb.add(Fmt("local %s = %s", it.name, it.value));
sb.add("Color = {}");
For(colors) sb.add(Fmt("Color.%s = %s", it.name, it.value));
sb.add("Style = {}");
For(style) {
if (CHAR_IsDigit(it.value[0])) sb.add(Fmt("Style.%s = %s", it.name, it.value));
else sb.add(Fmt("Style.%s = \"%s\"", it.name, it.value));
}
sb.add(LuaScript);
}
sb.add(")==\";");
sb.add("void ReloadStyle() {");
{
For(colors) sb.add(Fmt(" Color%s = GetColor(\"%s\", Color%s);", it.name, it.name, it.name));
For(style) {
if (CHAR_IsDigit(it.value[0])) sb.add(Fmt(" Style%s = GetStyleInt(\"%s\", Style%s);", it.name, it.name, it.name));
else sb.add(Fmt(" Style%s = GetStyleString(\"%s\", Style%s);", it.name, it.name, it.name));
}
}
sb.add("}");
string = Merge(scratch, sb, "\n");
OS_WriteFile("../src/text_editor/generated.cpp", string);
}
}
void GenerateLuaApi() {
MA_Scratch scratch;
S8_String file = OS_ReadFile(scratch, "../src/text_editor/lua_api.cpp");
S8_List list = S8_Split(scratch, file, "\n");
S8_List funcs = {};
for (S8_Node *it = list.first; it; it = it->next) {
S8_String s = S8_Trim(it->string);
if (S8_StartsWith(s, "int Lua_")) {
s = S8_Skip(s, 4);
S8_Seek(s, "(", 0, &s.len);
S8_Add(scratch, &funcs, s);
}
}
S8_List sb = {};
S8_AddF(scratch, &sb, "luaL_Reg LuaFunctions[] = {\n");
for (S8_Node *it = funcs.first; it; it = it->next) {
S8_String lua_name = S8_Skip(it->string, 4);
S8_AddF(scratch, &sb, " {\"%.*s\", %.*s},\n", S8_Expand(lua_name), S8_Expand(it->string));
}
S8_AddF(scratch, &sb, " {NULL, NULL},\n");
S8_AddF(scratch, &sb, "};\n");
S8_String output = S8_Merge(scratch, sb);
OS_WriteFile("../src/text_editor/lua_api_generated.cpp", output);
}
int main() {
MA_InitScratch();
SRC_InitCache(Perm, "te.cache");
GenerateLuaApi();
GenerateConfig();
int result = CompileTextEditor();
// int result = CompileNewPlatform();
if (result != 0) {
OS_DeleteFile("te.cache");
return result;
}
SRC_SaveCache();
return 0;
}