Porting to WASM
This commit is contained in:
2
build.sh
2
build.sh
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
void InitScratch() {
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
7
src/external/minicoro.h
vendored
7
src/external/minicoro.h
vendored
@@ -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 */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define BASIC_IMPL
|
||||
#include "basic/basic.h"
|
||||
#include "basic/filesystem.h"
|
||||
#include "basic/unix.cpp"
|
||||
|
||||
int main() {
|
||||
InitScratch();
|
||||
|
||||
|
||||
@@ -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);
|
||||
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,9 +417,11 @@ void DrawCircle(Vec2 pos, float radius, Color color) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------- ReloadFont - replace DSA texture calls ----------
|
||||
void ReloadFont() {
|
||||
Int size = StyleFontSize;
|
||||
size = ClampBottom((Int)2, size);
|
||||
size = ClampBottom((Int)2, size);
|
||||
if (MainFont.texture_id) {
|
||||
glDeleteTextures(1, &MainFont.texture_id);
|
||||
Dealloc(&MainFont.glyphs);
|
||||
@@ -362,20 +429,25 @@ void ReloadFont() {
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
|
||||
MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont);
|
||||
{
|
||||
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;
|
||||
FontCharSpacing = GetCharSpacing(&MainFont);
|
||||
FontLineSpacing = GetLineSpacing(&MainFont);
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
if (SavedClipboardString.data) {
|
||||
Dealloc(sys_allocator, &SavedClipboardString.data);
|
||||
SavedClipboardString = {};
|
||||
}
|
||||
void SetClipboardText(String16 string16) {
|
||||
String string = ToString(SysAllocator, string16);
|
||||
defer { Dealloc(SysAllocator, &string.data); };
|
||||
_SetClipboardText(string.data);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
MainLoop();
|
||||
}
|
||||
end_of_editor_loop:;
|
||||
#endif
|
||||
|
||||
SDL_DestroyWindow(SDLWindow);
|
||||
SDL_Quit();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user