Porting to WASM

This commit is contained in:
Krzosa Karol
2025-11-24 22:59:11 +01:00
parent 166f06d1fb
commit 56cdb9557d
19 changed files with 414 additions and 654 deletions

View File

@@ -48,7 +48,7 @@ if [ ! -f "lbaselib.o" ]; then
fi
if [ ! -f "metaprogram.exe" ]; then
clang ../src/metaprogram/metaprogram.cpp -o metaprogram.exe \
clang ../src/metaprogram/metaprogram.cpp ../src/basic/unix.cpp -o metaprogram.exe \
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
-Wno-writable-strings \
-I../src

View File

@@ -59,7 +59,7 @@ Color.TitleBarSelection = GruvboxLight3
Color.ResizerBackground = GruvboxLight0Hard
Color.ResizerOutline = GruvboxLight3
Style = {}
Style.WaitForEvents = 1
Style.WaitForEvents = 0
Style.DrawLineNumbers = 1
Style.DrawScrollbar = 1
Style.IndentSize = 4

View File

@@ -17,6 +17,8 @@
#elif defined(__linux__)
#define OS_POSIX 1
#define OS_LINUX 1
#elif defined(__EMSCRIPTEN__)
#define OS_WASM 1
#else
#error Unsupported platform
#endif
@@ -31,6 +33,10 @@
#error Unsupported compiler
#endif
#ifndef OS_WASM
#define OS_WASM 0
#endif
#ifndef OS_MAC
#define OS_MAC 0
#endif
@@ -60,14 +66,18 @@
#endif
#if OS_WINDOWS
#define DebugBreak() __debugbreak()
#define BREAK() __debugbreak()
#elif OS_LINUX
#define DebugBreak() raise(SIGTRAP)
#define BREAK() raise(SIGTRAP)
#elif OS_WASM
#include <emscripten.h>
extern "C" void JS_Breakpoint(void);
#define BREAK() JS_Breakpoint()
#endif
#define Assert(x) \
if (!(x)) { \
DebugBreak(); \
BREAK(); \
}
#define InvalidCodepath() Assert(!"invalid codepath")
#define ElseInvalidCodepath() else {InvalidCodepath()}
@@ -1035,8 +1045,8 @@ bool VCommit(void *p, size_t size);
bool VRelease(void *p, size_t size);
bool VDecommit(void *p, size_t size);
void InitArena(Arena *arena, size_t reserve = GiB(4));
Arena *AllocArena(size_t reserve = GiB(4));
void InitArena(Arena *arena, size_t reserve = MiB(256));
Arena *AllocArena(size_t reserve = MiB(256));
Arena *AllocArena(Allocator allocator, size_t size);
void *PushSize(Arena *arena, size_t size);
void Release(Arena *arena);
@@ -1707,11 +1717,22 @@ void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
}
thread_local Arena *ScratchArenaPool[4];
#if OS_WASM
void InitScratch() {
Allocator sys_allocator = GetSystemAllocator();
ScratchArenaPool[0] = AllocArena(sys_allocator, MiB(8));
ScratchArenaPool[1] = AllocArena(sys_allocator, MiB(2));
ScratchArenaPool[3] = AllocArena(sys_allocator, MiB(1));
ScratchArenaPool[3] = AllocArena(sys_allocator, KiB(512));
}
#else
void InitScratch() {
for (int i = 0; i < Lengthof(ScratchArenaPool); i += 1) {
ScratchArenaPool[i] = AllocArena();
}
}
#endif
TempArena GetScratchEx(Arena **conflicts, int conflict_count) {
Arena *unoccupied = 0;

View File

@@ -15,7 +15,6 @@
#include <spawn.h>
#include <poll.h>
void (*Error)(const char *, ...);
void *VReserve(size_t size) {
@@ -112,7 +111,7 @@ String GetAbsolutePath(Allocator al, String path) {
char *buffer = AllocArray(al, char, PATH_MAX);
realpath(null_term.data, buffer);
String result = buffer;
return buffer;
return result;
}
bool FileExists(String path) {

View File

@@ -14,11 +14,7 @@ void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) {
entry->data = data;
entry->callback = callback;
wq->completion_goal += 1;dex_to_read + 1) % Lengthof(wq->entries);
if (original_index_to_read != wq->index_to_write) {
int64_t index = AtomicCompareAndSwap(&wq->index_to_read, new_index_to_read, original_index_to_read);
if (index == original_index_to_read) {
WorkQueueEntry *entry = wq->entries +
wq->completion_goal += 1;
_WriteBarrier();
wq->index_to_write = new_index;
ReleaseSemaphore(wq->semaphore, 1, 0);
@@ -27,7 +23,11 @@ void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) {
bool TryDoingWork(WorkQueue *wq) {
bool should_sleep = false;
int64_t original_index_to_read = wq->index_to_read;
int64_t new_index_to_read = (original_inindex;
int64_t new_index_to_read = (original_index_to_read + 1) % Lengthof(wq->entries);
if (original_index_to_read != wq->index_to_write) {
int64_t index = AtomicCompareAndSwap(&wq->index_to_read, new_index_to_read, original_index_to_read);
if (index == original_index_to_read) {
WorkQueueEntry *entry = wq->entries + index;
entry->callback(entry->data);
AtomicIncrement(&wq->completion_index);
}

View File

@@ -349,10 +349,6 @@ MCO_API const char *mco_result_description(mco_result res); /* Get the descripti
#ifdef MINICORO_IMPL
#ifdef __cplusplus
extern "C" {
#endif
/* ---------------------------------------------------------------------------------------------- */
/* Minimum stack size when creating a coroutine. */
@@ -1973,9 +1969,6 @@ const char *mco_result_description(mco_result res) {
return "Unknown error";
}
#ifdef __cplusplus
}
#endif
#endif /* MINICORO_IMPL */

View File

@@ -1,7 +1,7 @@
#define BASIC_IMPL
#include "basic/basic.h"
#include "basic/filesystem.h"
#include "basic/unix.cpp"
int main() {
InitScratch();

View File

@@ -1,10 +1,3 @@
struct Shader {
uint32_t pipeline;
uint32_t fshader;
uint32_t vshader;
};
Shader CreateShader(char *glsl_vshader, char *glsl_fshader);
struct Vertex2D {
Vec2 pos;
Vec2 tex;
@@ -23,6 +16,12 @@ struct VertexList2D {
VertexNode2D *last;
};
struct Shader {
GLuint program; // linked program (vertex+fragment)
GLint uni_invHalf; // uniform location for inv half-screen size
GLint uni_texture; // sampler location
};
VertexList2D Vertices;
int64_t TotalVertexCount;
@@ -35,6 +34,155 @@ Font MainFont;
Int FontLineSpacing;
Int FontCharSpacing;
// ---------- shaders (ES3 / WebGL2) ----------
static const char *glsl_vshader_es3 = R"==(#version 300 es
precision highp float;
uniform vec2 U_InvHalfScreenSize; // same meaning as before
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec2 aTex;
layout(location = 2) in vec4 aColor; // normalized unsigned byte will map to 0..1 if we use normalized=true
out vec2 vUV;
out vec4 vColor;
void main() {
vec2 pos = aPos * U_InvHalfScreenSize;
pos.y = 2.0 - pos.y; // invert Y the same way you had
pos -= vec2(1.0, 1.0);
gl_Position = vec4(pos, 0.0, 1.0);
vUV = aTex;
vColor = aColor; // already 0..1
}
)==";
static const char *glsl_fshader_es3 = R"==(#version 300 es
precision mediump float;
in vec2 vUV;
in vec4 vColor;
uniform sampler2D S_Texture;
out vec4 OutColor;
void main() {
float a = texture(S_Texture, vUV).r;
vec4 c = vColor;
c.a *= a;
OutColor = c;
}
)==";
void ReportWarningf(const char *fmt, ...);
void GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) {
ReportWarningf("OpenGL message: %s", message);
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL error", message, NULL);
}
}
// ---------- helper: compile/link ----------
static GLuint CompileShaderSrc(GLenum kind, const char *src) {
GLuint s = glCreateShader(kind);
glShaderSource(s, 1, &src, NULL);
glCompileShader(s);
GLint ok = 0;
glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
if (!ok) {
char buf[1024];
glGetShaderInfoLog(s, sizeof(buf), NULL, buf);
SDL_Log("%s", buf);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
(kind == GL_VERTEX_SHADER ? "Vertex shader compile error" : "Fragment shader compile error"),
buf, NULL);
}
return s;
}
Shader CreateShaderES3(const char *vsrc, const char *fsrc) {
Shader out = {};
GLuint vs = CompileShaderSrc(GL_VERTEX_SHADER, vsrc);
GLuint fs = CompileShaderSrc(GL_FRAGMENT_SHADER, fsrc);
GLuint prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
// Bind attribute locations to match layout locations (optional because we use layout(location=...))
// glBindAttribLocation(prog, 0, "aPos");
// glBindAttribLocation(prog, 1, "aTex");
// glBindAttribLocation(prog, 2, "aColor");
glLinkProgram(prog);
GLint linked = 0;
glGetProgramiv(prog, GL_LINK_STATUS, &linked);
if (!linked) {
char buf[1024];
glGetProgramInfoLog(prog, sizeof(buf), NULL, buf);
SDL_Log("%s", buf);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Program link error", buf, NULL);
}
// We can detach/delete shaders after linking
glDetachShader(prog, vs);
glDetachShader(prog, fs);
glDeleteShader(vs);
glDeleteShader(fs);
out.program = prog;
out.uni_invHalf = glGetUniformLocation(prog, "U_InvHalfScreenSize");
out.uni_texture = glGetUniformLocation(prog, "S_Texture");
return out;
}
// ---------- InitRender for ES3 ----------
void InitRender() {
#if OS_WASM
RenderArena = *AllocArena(GetSystemAllocator(), MiB(64));
#else
InitArena(&RenderArena);
#endif
#if !OS_WASM
glDebugMessageCallback(&GLDebugCallback, NULL);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
#endif
// Create VBO (non-DSA path)
glGenBuffers(1, &VBO);
// reserve buffer big enough for one VertexNode2D->vertices array (same as original intent)
GLsizeiptr vbo_size = (GLsizeiptr) (Lengthof(((VertexNode2D*)0)->vertices) * sizeof(Vertex2D));
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vbo_size, NULL, GL_DYNAMIC_DRAW); // NULL initial, dynamic usage
// Create and setup VAO
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// attribute 0 : pos (vec2, floats)
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, pos));
// attribute 1 : tex (vec2)
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, tex));
// attribute 2 : color (vec4) -- stored as 4 unsigned bytes; we want normalized floats 0..1
glEnableVertexAttribArray(2);
// Using normalized GL_TRUE to map 0..255 -> 0..1 directly in shader
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, color));
// Unbind VAO and VBO
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Create shader program (ES3)
Shader2D = CreateShaderES3(glsl_vshader_es3, glsl_fshader_es3);
// other initializations like fonts will be done elsewhere (ReloadFont)
}
void BeginFrameRender(float wx, float wy) {
Clear(&RenderArena);
TotalVertexCount = 0;
@@ -43,6 +191,7 @@ void BeginFrameRender(float wx, float wy) {
CurrentScissor = Rect0Size(wx, wy);
}
// ---------- EndFrameRender for ES3 ----------
void EndFrameRender(float wx, float wy, Color color) {
glEnable(GL_BLEND);
glEnable(GL_SCISSOR_TEST);
@@ -55,131 +204,47 @@ void EndFrameRender(float wx, float wy, Color color) {
glClearColor(color.r, color.g, color.b, color.a);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Default draw using the font texture
glBindProgramPipeline(Shader2D.pipeline);
// Use program and set uniforms
glUseProgram(Shader2D.program);
float xinverse = 1.f / (wx / 2.f);
float yinverse = 1.f / (wy / 2.f);
glProgramUniform2f(Shader2D.vshader, 0, xinverse, yinverse);
// set uniform (U_InvHalfScreenSize)
if (Shader2D.uni_invHalf >= 0) {
glUniform2f(Shader2D.uni_invHalf, xinverse, yinverse);
}
// set sampler to texture unit 0
if (Shader2D.uni_texture >= 0) {
glUniform1i(Shader2D.uni_texture, 0);
}
glBindVertexArray(VAO);
for (VertexNode2D *it = Vertices.first; it; it = it->next) {
Rect2 rect = it->scissor;
GLint x = (GLint)rect.min.x;
GLint y = (GLint)rect.min.y;
GLsizei w = (GLsizei)(rect.max.x - x);
GLsizei h = (GLsizei)(rect.max.y - y);
// convert scissor Y to OpenGL bottom-left origin like before
glScissor(x, (GLint)wy - (GLint)rect.max.y, w, h);
glNamedBufferSubData(VBO, 0, it->count * sizeof(Vertex2D), it->vertices);
glBindVertexArray(VAO);
GLint s_texture = 0; // texture unit that sampler2D will use in GLSL code
glBindTextureUnit(s_texture, MainFont.texture_id);
// upload vertex data into VBO at offset 0
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, it->count * sizeof(Vertex2D), it->vertices);
// bind texture unit 0 and the font texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, MainFont.texture_id);
// draw
glDrawArrays(GL_TRIANGLES, 0, it->count);
// unbind VBO (optional)
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
glUseProgram(0);
}
void ReportWarningf(const char *fmt, ...);
void GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) {
ReportWarningf("OpenGL message: %s", message);
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL error", message, NULL);
}
}
void InitRender() {
InitArena(&RenderArena);
glDebugMessageCallback(&GLDebugCallback, NULL);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glCreateBuffers(1, &VBO);
glNamedBufferStorage(VBO, Lengthof(VertexNode2D::vertices) * sizeof(Vertex2D), 0, GL_DYNAMIC_STORAGE_BIT);
glCreateVertexArrays(1, &VAO);
GLint vbuf_index = 0;
glVertexArrayVertexBuffer(VAO, vbuf_index, VBO, 0, sizeof(struct Vertex2D));
GLint a_pos = 0;
glVertexArrayAttribFormat(VAO, a_pos, 2, GL_FLOAT, GL_FALSE, offsetof(struct Vertex2D, pos));
glVertexArrayAttribBinding(VAO, a_pos, vbuf_index);
glEnableVertexArrayAttrib(VAO, a_pos);
GLint a_tex = 1;
glVertexArrayAttribFormat(VAO, a_tex, 2, GL_FLOAT, GL_FALSE, offsetof(struct Vertex2D, tex));
glVertexArrayAttribBinding(VAO, a_tex, vbuf_index);
glEnableVertexArrayAttrib(VAO, a_tex);
GLint a_color = 2;
glVertexArrayAttribFormat(VAO, a_color, 4, GL_UNSIGNED_BYTE, GL_FALSE, offsetof(struct Vertex2D, color));
glVertexArrayAttribBinding(VAO, a_color, vbuf_index);
glEnableVertexArrayAttrib(VAO, a_color);
char *glsl_vshader = R"==(
#version 450 core
layout(location=0) uniform vec2 U_InvHalfScreenSize;
layout(location=0) in vec2 VPos;
layout(location=1) in vec2 VTex;
layout(location=2) in vec4 VColor;
out gl_PerVertex { vec4 gl_Position; }; // required because of ARB_separate_shader_objects
out vec2 FUV;
out vec4 FColor;
void main() {
vec2 pos = VPos * U_InvHalfScreenSize;
pos.y = 2 - pos.y; // invert y axis
pos -= vec2(1, 1); // convert to 0,1 range
gl_Position = vec4(pos, 0, 1);
FUV = VTex;
FColor = VColor / 255.0;
}
)==";
char *glsl_fshader = R"==(
#version 450 core
in vec2 FUV;
in vec4 FColor;
layout (binding=0) uniform sampler2D S_Texture;
layout (location=0) out vec4 OutColor;
void main() {
vec4 c = FColor;
c.a *= texture(S_Texture, FUV).r;
OutColor = c;
}
)==";
Shader2D = CreateShader(glsl_vshader, glsl_fshader);
}
Shader CreateShader(char *glsl_vshader, char *glsl_fshader) {
Shader result = {};
result.vshader = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
result.fshader = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
GLint linked;
glGetProgramiv(result.vshader, GL_LINK_STATUS, &linked);
if (!linked) {
char message[1024];
glGetProgramInfoLog(result.vshader, sizeof(message), NULL, message);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to create vertex shader!", message, NULL);
}
glGetProgramiv(result.fshader, GL_LINK_STATUS, &linked);
if (!linked) {
char message[1024];
glGetProgramInfoLog(result.fshader, sizeof(message), NULL, message);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to create fragment shader!", message, NULL);
}
glGenProgramPipelines(1, &result.pipeline);
glUseProgramStages(result.pipeline, GL_VERTEX_SHADER_BIT, result.vshader);
glUseProgramStages(result.pipeline, GL_FRAGMENT_SHADER_BIT, result.fshader);
return result;
}
VertexNode2D *AllocVertexNode2D(Allocator allocator, VertexList2D *list) {
VertexNode2D *node = AllocType(allocator, VertexNode2D);
@@ -352,6 +417,8 @@ void DrawCircle(Vec2 pos, float radius, Color color) {
}
}
// ---------- ReloadFont - replace DSA texture calls ----------
void ReloadFont() {
Int size = StyleFontSize;
size = ClampBottom((Int)2, size);
@@ -364,18 +431,23 @@ void ReloadFont() {
Scratch scratch;
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont);
{
// create and fill texture with ES3-compatible API
GLint filter = GL_NEAREST;
if (StyleFontFilter == 1) filter = GL_LINEAR;
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, filter);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, filter);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureStorage2D(atlas.texture_id, 1, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y);
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap);
}
MainFont.texture_id = atlas.texture_id;
GLuint tex = 0;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// allocate storage and upload
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, 0, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap);
glBindTexture(GL_TEXTURE_2D, 0);
MainFont.texture_id = tex;
FontCharSpacing = GetCharSpacing(&MainFont);
FontLineSpacing = GetLineSpacing(&MainFont);
}

View File

@@ -1,367 +0,0 @@
#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;
}
}
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({"TitleBarActiveBackground", "0xfefefefe"});
colors.add({"TitleBarSelection", "GruvboxLight3"});
colors.add({"ResizerBackground", "GruvboxLight0Hard"});
colors.add({"ResizerOutline", "GruvboxLight3"});
Array<Var> style = {};
style.add({"WaitForEvents", "1"});
style.add({"DrawLineNumbers", "1"});
style.add({"DrawScrollbar", "1"});
style.add({"IndentSize", "4"});
style.add({"FontSize", "15"});
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/Microsoft Visual Studio/2022/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));
}
S8_String init_file = OS_ReadFile(scratch, "../data/init.lua");
sb.add(init_file);
}
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_String file2 = OS_ReadFile(scratch, "../src/text_editor/commands.cpp");
S8_List list = S8_Split(scratch, file, "\n");
S8_List list2 = S8_Split(scratch, file2, "\n");
list = S8_ConcatLists(scratch, list, list2);
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;
}

View File

@@ -14,7 +14,7 @@ void AddText(String string) {
event.kind = EVENT_TEXT_INPUT;
event.xwindow = 1280;
event.ywindow = 720;
event.text = Copy(Perm, string).data;
event.text = Copy(SysAllocator, string).data;
Add(&EventPlayback, event);
}
@@ -26,7 +26,7 @@ void Wait(mco_coro *co) {
void PlayTestOpen(mco_coro *co) {
// Open file, move a little, then open again and verify the caret didn't move
String basic_env_cpp = Format(Perm, "%.*s/basic_env/basic_env.cpp", FmtString(TestDir));
String basic_env_cpp = Format(SysAllocator, "%.*s/basic_env/basic_env.cpp", FmtString(TestDir));
AddCtrlPress(SDLK_P);
Add(&EventPlayback, {EVENT_KEY_PRESS, SDLK_UP, 1280, 720});
@@ -69,7 +69,7 @@ void PlayTestOpen(mco_coro *co) {
buffer_len = main.buffer->len;
}
AddText(Format(Perm, "%.*s:20", FmtString(basic_env_cpp)));
AddText(Format(SysAllocator, "%.*s:20", FmtString(basic_env_cpp)));
AddCtrlPress(SDLK_Q);
Wait(co);
@@ -98,7 +98,7 @@ void PlayTestOpen(mco_coro *co) {
}
void Test(mco_coro *co) {
WorkDir = Format(Perm, "%.*s/basic_env", FmtString(TestDir));
WorkDir = Format(SysAllocator, "%.*s/basic_env", FmtString(TestDir));
PlayTestOpen(co);
@@ -110,7 +110,7 @@ void InitTests() {
StyleWaitForEvents = false;
{
String file = __FILE__;
file = NormalizePath(Perm, file);
file = NormalizePath(SysAllocator, file);
file = ChopLastSlash(file);
TestDir = file;
}

View File

@@ -1,32 +1,43 @@
void MakeSureToUseSystemAllocator_SaveInClipboard(String16 string, Array<String16> caret_strings = {}) {
Allocator sys_allocator = GetSystemAllocator();
#if OS_WASM
EM_ASYNC_JS(void, _SetClipboardText, (const char* c_str), {
const type = "text/plain";
const clipboardItemData = {
[type]: UTF8ToString(c_str),
};
const clipboardItem = new ClipboardItem(clipboardItemData);
await navigator.clipboard.write([clipboardItem]);
})
if (SavedClipboardCarets.data) {
For(SavedClipboardCarets) Dealloc(sys_allocator, &it.data);
Dealloc(sys_allocator, &SavedClipboardCarets.data);
SavedClipboardCarets.len = {};
EM_ASYNC_JS(const char *, GetClipboardText, (), {
const text = await navigator.clipboard.readText();
return stringToNewUTF8(text);
})
#define FreeClipboardText free
#else
#define FreeClipboardText SDL_free
#define GetClipboardText SDL_GetClipboardText
#define _SetClipboardText SDL_SetClipboardText
#endif
void SetClipboardText(String16 string16) {
String string = ToString(SysAllocator, string16);
defer { Dealloc(SysAllocator, &string.data); };
_SetClipboardText(string.data);
}
if (SavedClipboardString.data) {
Dealloc(sys_allocator, &SavedClipboardString.data);
SavedClipboardString = {};
}
SavedClipboardString = string;
SavedClipboardCarets = caret_strings;
Scratch scratch;
String string_to_save = ToString(scratch, SavedClipboardString).data;
SDL_SetClipboardText(string_to_save.data);
void FreeClipboardGlobals() {
For(SavedClipboardCarets) Dealloc(SysAllocator, &it.data);
SavedClipboardCarets.len = 0;
Dealloc(SysAllocator, &SavedClipboardString.data);
}
void SaveStringInClipboard(String16 string) {
string = Copy(GetSystemAllocator(), string);
MakeSureToUseSystemAllocator_SaveInClipboard(string);
FreeClipboardGlobals();
SavedClipboardString = Copy(SysAllocator, string);
SetClipboardText(string);
}
void Command_Copy(View *view) {
Allocator sys_allocator = GetSystemAllocator();
Buffer *buffer = GetBuffer(view->active_buffer);
// First, if there is no selection - select the entire line
@@ -38,25 +49,27 @@ void Command_Copy(View *view) {
}
}
Array<String16> caret_strings = {sys_allocator};
FreeClipboardGlobals();
For(view->carets) {
String16 string = GetString(buffer, it.range);
String16 copy = Copy(sys_allocator, string);
String16 copy = Copy(SysAllocator, string);
Add(&SavedClipboardCarets, copy);
}
// @todo: maybe only add new line if there is no new line at the end, experiment with it
String16 final_string = Merge(sys_allocator, SavedClipboardCarets, u"\n");
MakeSureToUseSystemAllocator_SaveInClipboard(final_string, caret_strings);
SavedClipboardString = Merge(SysAllocator, SavedClipboardCarets, u"\n");
SetClipboardText(SavedClipboardString);
}
void Command_Paste(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
const char *text = SDL_GetClipboardText();
defer { SDL_free((void *)text); };
const char *text = GetClipboardText();
defer { FreeClipboardText((void *)text); };
String16 string = ToUnixString16(scratch, text);
String16 string = ToUnixString16(SysAllocator, text);
defer { Dealloc(SysAllocator, &string.data); };
// Regular paste
if (string != SavedClipboardString || SavedClipboardCarets.len != view->carets.len) {

View File

@@ -60,7 +60,7 @@ Color.TitleBarSelection = GruvboxLight3
Color.ResizerBackground = GruvboxLight0Hard
Color.ResizerOutline = GruvboxLight3
Style = {}
Style.WaitForEvents = 1
Style.WaitForEvents = 0
Style.DrawLineNumbers = 1
Style.DrawScrollbar = 1
Style.IndentSize = 4

View File

@@ -4,8 +4,9 @@ struct InternTable {
};
String Intern(InternTable *table, String string) {
Allocator sys_allocator = GetSystemAllocator();
if (table->arena == NULL) {
table->arena = AllocArena();
table->arena = AllocArena(sys_allocator, MiB(8));
table->strings.allocator = *table->arena;
}
String *value = table->strings.get(string);

View File

@@ -51,7 +51,7 @@ extern luaL_Reg LuaFunctions[];
// clipboard
String16 SavedClipboardString;
Array<String16> SavedClipboardCarets;
Array<String16> SavedClipboardCarets = {SysAllocator};
String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") {
@@ -181,7 +181,7 @@ Buffer *CreateTempBuffer(Allocator allocator, Int size = 4096) {
}
Window *CreateWindow(bool create_command_buffer = true) {
Window *w = AllocType(Perm, Window);
Window *w = AllocType(SysAllocator, Window);
w->visible = true;
w->draw_scrollbar = StyleDrawScrollbar;
w->draw_line_numbers = StyleDrawLineNumbers;

View File

@@ -161,6 +161,25 @@ Event TranslateSDLEvent(SDL_Event *input_event) {
return event;
}
#if OS_WASM
EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), {
document.getElementById("canvas").style.cursor = UTF8ToString(cursor_str);
})
void SetMouseCursor(SDL_SystemCursor id) {
if (id == SDL_SYSTEM_CURSOR_EW_RESIZE) {
JS_SetMouseCursor("ew-resize");
} else if (id == SDL_SYSTEM_CURSOR_NS_RESIZE) {
JS_SetMouseCursor("ns-resize");
} else if (id == SDL_SYSTEM_CURSOR_DEFAULT) {
JS_SetMouseCursor("default");
} else if (id == SDL_SYSTEM_CURSOR_TEXT) {
JS_SetMouseCursor("text");
} else {
InvalidCodepath();
}
}
#else
void SetMouseCursor(SDL_SystemCursor id) {
static SDL_Cursor *SDL_MouseCursor;
static SDL_SystemCursor last_id;
@@ -174,6 +193,7 @@ void SetMouseCursor(SDL_SystemCursor id) {
last_id = id;
}
}
#endif
void SetMouseCursor(Event event) {
Scratch scratch;
@@ -309,6 +329,59 @@ void Windows_SetupVCVarsall(mco_coro *co) {
}
}
void MainLoop() {
FrameID += 1;
Scratch scratch;
Array<Event> frame_events = GetEventsForFrame(scratch);
For(frame_events) {
// Serialize(&ser, &it);
if (it.kind == EVENT_QUIT) {
AppIsRunning = false;
return;
}
if (it.xwindow == 0 || it.ywindow == 0) {
int xwindow, ywindow;
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow);
it.xwindow = xwindow;
it.ywindow = ywindow;
}
Update(it);
}
WaitForEvents = StyleWaitForEvents;
if (IsDocumentSelectionValid() || IsScrollbarSelectionValid() || ActiveProcesses.len) {
WaitForEvents = false;
}
// This shouldn't matter to the state of the program, only appearance for
// the user
{
Window *window = GetActiveWindow();
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
const char *dirty = buffer->dirty ? " !" : "";
String string = Format(scratch, "%.*s%s", FmtString(buffer->name), dirty);
SDL_SetWindowTitle(SDLWindow, string.data);
}
Event *event = GetLast(frame_events);
SetMouseCursor(*event);
LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay
BeginFrameRender(event->xwindow, event->ywindow);
DrawSplits(&WindowSplits);
Array<Window *> order = GetWindowZOrder(scratch);
For(IterateInReverse(&order)) {
if (!it->visible) continue;
DrawWindow(it, *GetLast(frame_events));
}
EndFrameRender(event->xwindow, event->ywindow, ColorBackground);
SDL_GL_SwapWindow(SDLWindow);
}
#if _WIN32
int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd)
#else
@@ -322,7 +395,6 @@ int main(int argc, char **argv)
#endif
BeginProfiler();
InitScratch();
InitArena(&Perm);
#if !OS_WINDOWS
for (int i = 0; environ[i]; i += 1) {
@@ -330,7 +402,7 @@ int main(int argc, char **argv)
}
#endif
WorkDir = GetWorkingDir(Perm);
WorkDir = GetWorkingDir(SysAllocator);
{
String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor");
if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '\\') {
@@ -339,7 +411,7 @@ int main(int argc, char **argv)
if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '/') {
sdl_config_path = Chop(sdl_config_path, 1); // chop '/'
}
ConfigDir = NormalizePath(Perm, sdl_config_path);
ConfigDir = NormalizePath(SysAllocator, sdl_config_path);
SDL_free(sdl_config_path.data);
}
@@ -352,9 +424,15 @@ int main(int argc, char **argv)
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
#if OS_WASM
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
#endif
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
@@ -410,6 +488,7 @@ int main(int argc, char **argv)
InitWindows();
InitOS(ReportWarningf);
bool testing = false;
for (int i = 1; i < argc; i += 1) {
String it = argv[i];
@@ -428,61 +507,16 @@ int main(int argc, char **argv)
ReportConsolef("WorkDir = %.*s", FmtString(WorkDir));
InitLuaConfig();
if (testing) InitTests();
#if _WIN32
#if OS_WINDOWS
AddCo(Windows_SetupVCVarsall);
#endif
Serializer ser = {EventBuffer};
#if OS_WASM
emscripten_set_main_loop(MainLoop, 0, 1);
#else
while (AppIsRunning) {
FrameID += 1;
Scratch scratch;
Array<Event> frame_events = GetEventsForFrame(scratch);
For(frame_events) {
Serialize(&ser, &it);
if (it.kind == EVENT_QUIT) goto end_of_editor_loop;
if (it.xwindow == 0 || it.ywindow == 0) {
int xwindow, ywindow;
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow);
it.xwindow = xwindow;
it.ywindow = ywindow;
MainLoop();
}
Update(it);
}
WaitForEvents = StyleWaitForEvents;
if (IsDocumentSelectionValid() || IsScrollbarSelectionValid() || ActiveProcesses.len) {
WaitForEvents = false;
}
// This shouldn't matter to the state of the program, only appearance for
// the user
{
Window *window = GetActiveWindow();
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
const char *dirty = buffer->dirty ? " !" : "";
String string = Format(scratch, "%.*s%s", FmtString(buffer->name), dirty);
SDL_SetWindowTitle(SDLWindow, string.data);
}
Event *event = GetLast(frame_events);
SetMouseCursor(*event);
LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay
BeginFrameRender(event->xwindow, event->ywindow);
DrawSplits(&WindowSplits);
Array<Window *> order = GetWindowZOrder(scratch);
For(IterateInReverse(&order)) {
if (!it->visible) continue;
DrawWindow(it, *GetLast(frame_events));
}
EndFrameRender(event->xwindow, event->ywindow, ColorBackground);
SDL_GL_SwapWindow(SDLWindow);
}
end_of_editor_loop:;
#endif
SDL_DestroyWindow(SDLWindow);
SDL_Quit();

View File

@@ -101,8 +101,8 @@ struct BSet {
// Dont use it
Int FrameID;
Allocator SysAllocator = {SystemAllocator_Alloc};
String ConfigDir;
Arena Perm;
float DPIScale = 1.0f;
Rect2I GetVisibleCells(Window *window);

View File

@@ -53,6 +53,7 @@ void ReplaceTitleBarData(Window *window) {
Range replace_range = {0, title.buffer->len};
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
// Parse the title and line
if (window->id == ActiveWindow) {
if (title.buffer->change_id == title.window->title_bar_last_buffer_change_id) {
return;
@@ -112,9 +113,16 @@ void ReplaceTitleBarData(Window *window) {
AdjustCarets(edits, &caret_copy);
}
// replace data up to separator with filename and stuff
const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : "";
String s = Format(scratch, "%.*s:%lld:%lld%s", FmtString(main.buffer->name), (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
For (ActiveProcesses) {
if (it.view_id == main.view->id.id) {
s = Format(scratch, "%.*s %lld", FmtString(s), (long long)it.id);
}
}
String16 string = ToString16(scratch, s);
String16 string_to_replace = GetString(title.buffer, replace_range);
if (string_to_replace != string) {

View File

@@ -1,4 +1,3 @@
FEATURE SaveAll dirty files which are saved on disk already but dirty
DESIGN try to make console less special, make stuff reusable etc.
DESIGN Config file versions, when loading should be checked, at the top of the file, what to do when old version?
ISSUE Ctrl+Alt+Down (DuplicateLine) doesn't work on ubuntu
@@ -9,32 +8,21 @@ FEATURE KillConsole, or maybe some window targetting but how??
ISSUE I hit a case where GC tried deleting a buffer which was not attached to the buffer list, it had zeroed next, prev. It happened after iterating through directories using the ctrl + period
FEATURE Search whole words, case sensitive etc.
FEATURE Select all searched occurences
DESIGN Indicate maybe on the console border that a process is running in the console! also maybe exit code when exits
PLATFORM Fix windows build
ISSUE What to do / how should Reopen work after we delete the file on disk in some other program?
- Changing window properties by changing the window name?
- commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top
- Add metadata to Lua bindings so that we would get a better listing (function args?, what else?)
- Kill buffer command (it should be marked for deletion and deleted at the end of frame!)
- Delete directory/file on disk command
- Check. Convert more commands to taking buffer instead of view
- Check. Rewrite more commands to use already implemented commands?
- Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)?
- Some decl/function indexing in fuzzy format
- Fix jump scroll, the query ends up the last line on screen, kind of wacky
- LoadWord, EncloseWord configurable?
- dump text editor state to file, restore state
- proper lister
- ask user if he really wants to quit even though he has an unsaved buffer - popup window | we could just show ForceClose() in the titlebar
- Find matches using grep, change things in that buffer then apply those changes to all items
- group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character
DESIGN Changing window properties by changing the window name?
FEATURE commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top
FEATURE Kill buffer command (it should be marked for deletion and deleted at the end of frame!)
DESIGN Check. Convert more commands to taking buffer instead of view
DESIGN Check. Rewrite more commands to use already implemented commands?
FEATURE Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)?
FEATURE Some decl/function indexing in fuzzy format
ISSUE? Fix jump scroll, the query ends up the last line on screen, kind of wacky
FEATURE dump text editor state to file, restore state
DESIGN ask user if he really wants to quit even though he has an unsaved buffer - popup window | we could just show ForceClose() in the titlebar
FEATURE Find matches using grep, change things in that buffer then apply those changes to all items
FEATURE group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character
- Search and replace
- A lister which is going to show project without the full path and sorted by recency
- word complete
- Search all buffers in 10X style, incrementally searched results popping up on every key press (maybe we need coroutine library in C so this is easier?)
- escapeing multiple cursor after ctrl + d should put the cursor where it was (probably will need to swap secondary and primary cursor for new cursor

View File

@@ -61,7 +61,7 @@ Int GetTitleBarSize(Window *window) {
}
WindowSplit *CreateSplitForWindow(WindowSplit *parent, Window *window) {
WindowSplit *split = AllocType(Perm, WindowSplit);
WindowSplit *split = AllocType(SysAllocator, WindowSplit);
split->kind = WindowSplitKind_Window;
split->window = window;
split->parent = parent;
@@ -79,7 +79,7 @@ void SplitWindowEx(WindowSplit **node, WindowSplit *split, Window *target, Windo
return;
}
WindowSplit *hori = AllocType(Perm, WindowSplit);
WindowSplit *hori = AllocType(SysAllocator, WindowSplit);
hori->parent = node[0]->parent;
hori->kind = kind;
hori->value = 0.5;
@@ -156,8 +156,6 @@ https://www.lua.org/manual/5.4/
}
void InitWindows() {
Allocator sys_allocator = Perm;
WindowSplit *split = &WindowSplits;
split->kind = WindowSplitKind_Horizontal;
split->value = (double)0.9;
@@ -192,7 +190,7 @@ void InitWindows() {
window->visible = false;
window->z = 2;
Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "debug"));
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
DebugBufferID = buffer->id;
buffer->no_history = true;