This commit is contained in:
sfja 2025-07-04 02:48:44 +02:00
commit d940df2869
13 changed files with 817 additions and 0 deletions

19
.clang-format Normal file
View File

@ -0,0 +1,19 @@
Language: Cpp
BasedOnStyle: WebKit
IndentWidth: 4
ColumnLimit: 80
IndentCaseLabels: true
InsertNewlineAtEOF: true
AllowShortFunctionsOnASingleLine: None
AlignAfterOpenBracket: AlwaysBreak
BinPackArguments: false
AllowAllArgumentsOnNextLine: true
# BinPackParameters: OnePerLine # llvm >= 20
BinPackParameters: true
AllowAllParametersOfDeclarationOnNextLine: true
PenaltyReturnTypeOnItsOwnLine: 1000 # abitrary, seems to work

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
fed

27
Makefile Normal file
View File

@ -0,0 +1,27 @@
CFLAGS = -std=c23
CFLAGS += -fsanitize=address,undefined -g
CFLAGS += -Wall -Wextra -Wpedantic -Wconversion -pedantic -pedantic-errors
LFLAGS = -lm
CFLAGS += $(shell pkg-config sdl2 SDL2_ttf --cflags)
LFLAGS += $(shell pkg-config sdl2 SDL2_ttf --libs)
CFILES = \
main.c \
app.c \
buffer.c \
editor.c \
HFILES = $(shell find . -name "*.h")
TARGET=fed
$(TARGET): $(CFILES) $(HFILES)
gcc -o $@ $(CFILES) $(CFLAGS) $(LFLAGS)
clean:
rm -rf $(TARGET)

122
app.c Normal file
View File

@ -0,0 +1,122 @@
#include "app.h"
#include "editor.h"
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_ttf.h>
#include <stdlib.h>
static void ptr_vec_push(
void*** vec, size_t* capacity, size_t* size, void* element)
{
if (*size + 1 > *capacity) {
*capacity *= 2;
*vec = realloc(*vec, *capacity * sizeof(void*));
}
(*vec)[*size] = element;
*size += 1;
}
void app_init(App* app)
{
const size_t buffers_initial_capacity = 16;
*app = (App) {
.buffers = malloc(buffers_initial_capacity),
.buffers_capacity = buffers_initial_capacity,
.buffers_size = 0,
.res = (AppRessources) {
.font = nullptr,
.char_size = {},
},
.editor = {},
};
editor_init(&app->editor, 1000, 1000, &app->res);
}
void app_deinit(App* app)
{
if (app->res.font)
TTF_CloseFont(app->res.font);
for (size_t i = 0; i < app->buffers_size; ++i) {
buffer_deinit(app->buffers[i]);
free(app->buffers[i]);
}
free(app->buffers);
}
int app_ressources_load(App* app)
{
app->res.font
= TTF_OpenFont("/usr/share/fonts/TTF/FiraCodeNerdFont-Medium.ttf", 16);
if (!app->res.font) {
fprintf(stderr, "error: cannot open font: %s\n", SDL_GetError());
return -1;
}
app->res.char_size = text_size("A", app->res.font);
app->res.theme = defaultTheme;
return 0;
}
void app_ressources_unload(App* app)
{
if (app->res.font) {
TTF_CloseFont(app->res.font);
app->res.font = nullptr;
}
}
void app_new_file(App* app)
{
Buffer* buffer = malloc(sizeof(Buffer));
buffer_init(buffer);
ptr_vec_push(
(void***)&app->buffers,
&app->buffers_capacity,
&app->buffers_size,
buffer);
}
void app_open_file(App* app, const char* path)
{
Buffer* buffer = malloc(sizeof(Buffer));
buffer_from_file(buffer, path);
ptr_vec_push(
(void***)&app->buffers,
&app->buffers_capacity,
&app->buffers_size,
buffer);
}
void app_prepare(App* app)
{
if (app->buffers_size == 0) {
app_new_file(app);
}
editor_open(&app->editor, app->buffers[app->buffers_size - 1]);
}
void app_handle_keydown(App* app, int keysum)
{
switch (keysum) {
case SDLK_UP:
editor_cursor_up(&app->editor);
break;
case SDLK_DOWN:
editor_cursor_down(&app->editor);
break;
case SDLK_LEFT:
editor_cursor_left(&app->editor);
break;
case SDLK_RIGHT:
editor_cursor_right(&app->editor);
break;
}
}
void app_render(App* app, void* renderer)
{
editor_render(&app->editor, renderer, 0, 0);
}

29
app.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef APP_H
#define APP_H
#include "app_ressources.h"
#include "buffer.h"
#include "editor.h"
#include <stddef.h>
typedef struct {
Buffer** buffers;
size_t buffers_capacity;
size_t buffers_size;
AppRessources res;
Editor editor;
} App;
void app_init(App* app);
void app_deinit(App* app);
int app_ressources_load(App* app);
void app_ressources_unload(App* app);
void app_new_file(App* app);
void app_open_file(App* app, const char* path);
void app_prepare(App* app);
void app_handle_keydown(App* app, int keysum);
void app_render(App* app, void* renderer);
extern const Theme defaultTheme;
#endif

28
app_ressources.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef APP_RESSOURCES_H
#define APP_RESSOURCES_H
#include <stdint.h>
typedef struct {
int width, height;
} TextSize;
TextSize text_size(const char* text, void* font);
typedef struct {
uint8_t r, g, b, a;
} Color;
typedef struct {
Color foreground;
Color background;
Color linenumber;
} Theme;
typedef struct {
void* font;
TextSize char_size;
Theme theme;
} AppRessources;
#endif

69
buffer.c Normal file
View File

@ -0,0 +1,69 @@
#include "buffer.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int file_read(
char** text, size_t* text_capacity, size_t* text_length, const char* path)
{
FILE* file = fopen(path, "r");
if (!file) {
fprintf(stderr, "error: could not open file '%s'\n", path);
return -1;
}
fseek(file, 0, SEEK_END);
size_t file_size = (size_t)ftell(file);
rewind(file);
size_t initial_capacity = 8;
while (initial_capacity < file_size + 1)
initial_capacity *= 2;
*text = calloc(initial_capacity, sizeof(char));
*text_capacity = initial_capacity;
*text_length = file_size;
size_t bytes_read = fread(*text, sizeof(char), file_size, file);
if (bytes_read != file_size) {
fprintf(stderr, "error: could not read file '%s'\n", path);
return -1;
}
return 0;
}
void buffer_init(Buffer* buffer)
{
const size_t text_initial_capacity = 8;
*buffer = (Buffer) {
.path = nullptr,
.text = calloc(1, text_initial_capacity),
.text_capacity = text_initial_capacity,
.text_length = 0,
.changed = false,
};
}
int buffer_from_file(Buffer* buffer, const char* path)
{
*buffer = (Buffer) {
.path = strdup(path),
.text = nullptr,
.text_capacity = 0,
.text_length = 0,
.changed = false,
};
int status = file_read(
&buffer->text, &buffer->text_capacity, &buffer->text_length, path);
return status;
}
void buffer_deinit(Buffer* buffer)
{
if (buffer->path)
free(buffer->path);
free(buffer->text);
}

18
buffer.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef BUFFER_H
#define BUFFER_H
#include <stddef.h>
typedef struct {
char* path;
char* text;
size_t text_capacity;
size_t text_length;
bool changed;
} Buffer;
void buffer_init(Buffer* buffer);
int buffer_from_file(Buffer* buffer, const char* path);
void buffer_deinit(Buffer* buffer);
#endif

10
compile_flags.txt Normal file
View File

@ -0,0 +1,10 @@
-xc
-std=c23
-Wall
-Wextra
-Wpedantic
-Wconversion
-pedantic
-pedantic-errors
-Wno-unused-variable

170
editor.c Normal file
View File

@ -0,0 +1,170 @@
#include "editor.h"
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_ttf.h>
void render_text(
SDL_Renderer* renderer, const char* text, TTF_Font* font, int x, int y,
SDL_Color fg, SDL_Color bg);
void editor_init(
Editor* editor, int width, int height, AppRessources* ressources)
{
*editor = (Editor) {
.buffer = nullptr,
width,
height,
.cursor_idx = 0,
.cursor_line = 1,
.cursor_col = 1,
ressources,
};
}
void editor_open(Editor* editor, Buffer* buffer)
{
editor->buffer = buffer;
editor->cursor_idx = 0;
editor->cursor_line = 1;
editor->cursor_col = 1;
}
static int cols_at_idx(Editor* editor, size_t idx)
{
Buffer* buffer = editor->buffer;
int line_start = (int)idx;
while (line_start > 0 && buffer->text[line_start] != '\n') {
line_start -= 1;
}
int line_end = (int)idx + 1;
while (line_end < (int)buffer->text_length
&& buffer->text[line_end] != '\n') {
line_end += 1;
}
printf("idx = %ld, cols = %d\n", idx, line_end - line_start);
return line_end - line_start;
}
static void cursor_increment(Editor* editor)
{
if (editor->cursor_idx >= editor->buffer->text_length)
return;
if (editor->buffer->text[editor->cursor_idx] == '\n') {
editor->cursor_line += 1;
editor->cursor_col = 1;
} else {
editor->cursor_col += 1;
}
editor->cursor_idx += 1;
}
static void cursor_decrement(Editor* editor)
{
if (editor->cursor_idx <= 0)
return;
editor->cursor_idx -= 1;
if (editor->buffer->text[editor->cursor_idx] == '\n') {
editor->cursor_line -= 1;
editor->cursor_col = cols_at_idx(editor, editor->cursor_idx);
} else {
editor->cursor_col -= 1;
}
}
void editor_cursor_up(Editor* editor)
{
if (editor->cursor_line == 1)
return;
int originalLine = editor->cursor_line;
int originalCol = editor->cursor_col;
while (editor->cursor_line >= originalLine
|| editor->cursor_col > originalCol) {
cursor_decrement(editor);
}
}
void editor_cursor_down(Editor* editor)
{
int originalLine = editor->cursor_line;
int originalCol = editor->cursor_col;
while (editor->cursor_line <= originalLine
|| editor->cursor_col > originalCol) {
cursor_increment(editor);
}
}
void editor_cursor_left(Editor* editor)
{
}
void editor_cursor_right(Editor* editor)
{
}
void editor_render(Editor* editor, void* renderer, int x, int y)
{
Theme* theme = &editor->ressources->theme;
SDL_Color fg = *(SDL_Color*)&theme->foreground;
SDL_Color bg = *(SDL_Color*)&theme->background;
SDL_SetRenderDrawColor(renderer, bg.r, bg.g, bg.b, bg.a);
SDL_RenderFillRect(
renderer, &(SDL_Rect) { 0, 0, editor->width, editor->height });
TextSize char_size = editor->ressources->char_size;
Buffer* buffer = editor->buffer;
size_t i = 0;
int line = 1;
int offset_y = 0;
while (i < buffer->text_length) {
size_t line_start = i;
while (i < buffer->text_length && buffer->text[i] != '\n') {
i += 1;
}
char line_number[16] = "";
snprintf(line_number, 15, "%4d", line);
TextSize ln_size = text_size(line_number, editor->ressources->font);
render_text(
renderer,
line_number,
editor->ressources->font,
x,
y + offset_y,
*(SDL_Color*)&theme->linenumber,
bg);
char* line_text = strndup(&buffer->text[line_start], i - line_start);
TextSize line_size = text_size(line_text, editor->ressources->font);
render_text(
renderer,
line_text,
editor->ressources->font,
x + ln_size.width + 8,
y + offset_y,
fg,
bg);
free(line_text);
offset_y += line_size.height;
if (i < buffer->text_length && buffer->text[i] == '\n') {
i += 1;
}
line += 1;
}
SDL_SetRenderDrawColor(renderer, fg.r, fg.g, fg.b, fg.a);
SDL_RenderFillRect(
renderer,
&(SDL_Rect) {
x + char_size.width * (editor->cursor_col - 1 + 4) + 8 - 1,
y + char_size.height * (editor->cursor_line - 1),
2,
char_size.height,
});
}

26
editor.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef EDITOR_H
#define EDITOR_H
#include "app_ressources.h"
#include "buffer.h"
typedef struct {
Buffer* buffer;
int width;
int height;
size_t cursor_idx;
int cursor_line;
int cursor_col;
AppRessources* ressources;
} Editor;
void editor_init(
Editor* editor, int width, int height, AppRessources* ressources);
void editor_open(Editor* editor, Buffer* buffer);
void editor_cursor_up(Editor* editor);
void editor_cursor_down(Editor* editor);
void editor_cursor_left(Editor* editor);
void editor_cursor_right(Editor* editor);
void editor_render(Editor* editor, void* renderer, int x, int y);
#endif

175
init.patch Normal file
View File

@ -0,0 +1,175 @@
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..a56cbd0
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,14 @@
+Language: Cpp
+BasedOnStyle: WebKit
+IndentWidth: 4
+ColumnLimit: 80
+IndentCaseLabels: true
+InsertNewlineAtEOF: true
+AllowShortFunctionsOnASingleLine: None
+
+BinPackArguments: false
+AllowAllArgumentsOnNextLine: true
+
+BinPackParameters: false
+AllowAllParametersOfDeclarationOnNextLine: true
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1fd9dda
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+./game
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3fef9c2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+
+CFLAGS = -std=c23
+CFLAGS += -fsanitize=address,undefined -g
+CFLAGS += -Wall -Wextra -Wpedantic -Wconversion -pedantic -pedantic-errors
+
+LFLAGS =
+
+CFLAGS += $(shell pkg-config sdl2 --cflags)
+LFLAGS += $(shell pkg-config sdl2 --libs)
+
+game: main.c
+ gcc -o $@ $^ $(CFLAGS) $(LFLAGS)
+
+clean:
+ rm -rf game
+
+
diff --git a/compile_flags.txt b/compile_flags.txt
new file mode 100644
index 0000000..7672925
--- /dev/null
+++ b/compile_flags.txt
@@ -0,0 +1,10 @@
+-xc
+-std=c23
+-Wall
+-Wextra
+-Wpedantic
+-Wconversion
+-pedantic
+-pedantic-errors
+-Wno-unused-variable
+
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..879ae5d
--- /dev/null
+++ b/main.c
@@ -0,0 +1,102 @@
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_blendmode.h>
+#include <SDL2/SDL_events.h>
+#include <SDL2/SDL_keycode.h>
+#include <SDL2/SDL_pixels.h>
+#include <SDL2/SDL_rect.h>
+#include <SDL2/SDL_render.h>
+#include <SDL2/SDL_timer.h>
+#include <SDL2/SDL_video.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+uint32_t be_to_le_u32(uint32_t be_value);
+uint32_t rgba(uint32_t color);
+uint32_t rgb(uint32_t color);
+
+int main(void)
+{
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ SDL_Window* window;
+ SDL_Renderer* renderer;
+
+ SDL_CreateWindowAndRenderer(512, 512, 0, &window, &renderer);
+ // SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
+
+ SDL_Texture* buffer = SDL_CreateTexture(renderer,
+ SDL_PIXELFORMAT_RGBA32,
+ SDL_TEXTUREACCESS_STREAMING,
+ 512,
+ 512);
+
+ SDL_SetTextureBlendMode(buffer, SDL_BLENDMODE_BLEND);
+
+ while (true) {
+
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT:
+ goto exit_game;
+ case SDL_KEYDOWN: {
+ switch (event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ goto exit_game;
+ }
+ }
+ }
+ }
+
+ SDL_RenderClear(renderer);
+
+ uint32_t* pixels;
+ int row_size;
+ SDL_LockTexture(
+ buffer, &(SDL_Rect) { 0, 0, 512, 512 }, (void**)&pixels, &row_size);
+ row_size /= sizeof(uint32_t);
+
+ for (int y = 0; y < 100; ++y) {
+ for (int x = 0; x < 100; ++x) {
+ pixels[(y + 100) * row_size + x + 100] = rgb(0xff0000);
+ }
+ }
+
+ SDL_UnlockTexture(buffer);
+
+ SDL_RenderCopy(renderer, buffer, nullptr, nullptr);
+
+ SDL_RenderPresent(renderer);
+
+ SDL_Delay(16);
+ }
+
+exit_game:;
+ printf("exitting...\n");
+
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+}
+
+uint32_t be_to_le_u32(uint32_t be_value)
+{
+ uint32_t le_value = 0;
+ le_value |= (be_value & 0xff) << 24;
+ le_value |= (be_value >> 8 & 0xff) << 16;
+ le_value |= (be_value >> 16 & 0xff) << 8;
+ le_value |= be_value >> 24 & 0xff;
+ return le_value;
+}
+
+uint32_t rgba(uint32_t color)
+{
+ return be_to_le_u32(color);
+}
+
+uint32_t rgb(uint32_t color)
+{
+ return rgba(color << 8 | 0xff);
+}

122
main.c Normal file
View File

@ -0,0 +1,122 @@
#include "app.h"
#include "app_ressources.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_blendmode.h>
#include <SDL2/SDL_error.h>
#include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_stdinc.h>
#include <SDL2/SDL_surface.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_video.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
const Theme defaultTheme = {
.foreground = { 0xfb, 0xf1, 0xc7, 0xff },
.background = { 0x28, 0x28, 0x28, 0xff },
.linenumber = { 0x7c, 0x6f, 0x64, 0xff },
};
TextSize text_size(const char* text, void* font)
{
int w, h;
TTF_SizeText(font, text, &w, &h);
return (TextSize) { w, h };
}
void render_text(
SDL_Renderer* renderer, const char* text, TTF_Font* font, int x, int y,
SDL_Color fg, SDL_Color bg)
{
SDL_Surface* surface = TTF_RenderUTF8_Shaded(font, text, fg, bg);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
TextSize size = text_size(text, font);
SDL_RenderCopy(
renderer,
texture,
nullptr,
&(SDL_Rect) { x, y, size.width, size.height });
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);
}
int main(int argc, char** argv)
{
App app_instance;
App* app = &app_instance;
app_init(app);
for (int i = 1; i < argc; ++i) {
app_open_file(app, argv[i]);
}
app_prepare(app);
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
app_ressources_load(app);
SDL_Window* window = SDL_CreateWindow(
"fed",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
1000,
1000,
SDL_WINDOW_RESIZABLE);
SDL_Renderer* renderer = SDL_CreateRenderer(window, 0, 0);
// SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
uint64_t before = SDL_GetTicks64();
while (true) {
uint64_t now = SDL_GetTicks64();
uint64_t delta = now - before;
(void)delta;
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
goto exit_game;
case SDL_KEYDOWN: {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
goto exit_game;
}
}
default:
app_handle_keydown(app, event.key.keysym.sym);
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
app_render(app, renderer);
SDL_RenderPresent(renderer);
SDL_Delay(16);
before = now;
}
exit_game:;
printf("exitting...\n");
app_ressources_unload(app);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
SDL_Quit();
app_deinit(app);
}