Skip to content

Instantly share code, notes, and snippets.

@akkartik
Created January 12, 2021 06:14
Show Gist options
  • Save akkartik/88dbfa920778e75caa4dd348ce037ea7 to your computer and use it in GitHub Desktop.
Save akkartik/88dbfa920778e75caa4dd348ce037ea7 to your computer and use it in GitHub Desktop.
Adding a gap buffer to a text editor
#include <SDL2/SDL.h>
#include <stdio.h>
int error(char *msg, const char *err) {
printf("Error %s: %s\n", msg, err);
return 0;
}
#define HOR 32
#define VER 16
#define PAD 8
#define TEXTSZ 1024 * 32
char text[TEXTSZ+1];
int text_len = 0;
int cursor = 0;
void pushchar(char c) {
int i;
if(text_len >= TEXTSZ)
return;
for(i = text_len-1; i >= cursor; --i)
text[i + 1] = text[i];
text_len++;
text[cursor] = c;
cursor++;
}
void left() {
if(cursor > 0) --cursor;
}
void right() {
if(cursor < text_len-1) ++cursor;
}
int loadtxt(char *name) {
char line[256];
FILE *f = fopen(name, "r");
if(!f) return error("Load", "Invalid input file");
text_len = 0;
while(fgets(line, 256, f)) {
int i = 0;
char c;
while((c = line[i++]))
pushchar(c);
}
/* reset cursor */
cursor = 0;
printf("Loaded: %s\n", name);
fclose(f);
return 1;
}
int cursorcol() {
int result = 0;
int c;
for(c = cursor-1; c >= 0; --c) {
if(text[c] == '\n') break;
++result;
}
return result;
}
void down() {
int col = cursorcol();
/* skip rest of line */
for(; cursor < text_len && text[cursor] != '\n'; ++cursor)
right();
/* scan forward on next line */
right();
for(; col > 0 && cursor < text_len && text[cursor] != '\n'; --col)
right();
}
void up() {
int col = cursorcol();
/* scan back to end of previous line */
left();
while(cursor > 0 && text[cursor] != '\n')
left();
/* scan back to start of previous line */
left();
while(cursor > 0 && text[cursor] != '\n')
left();
/* scan forward on previous line */
for(; col > 0 && cursor < text_len && text[cursor] != '\n'; --col)
right();
}
int WIDTH = 8 * HOR + PAD * 2;
int HEIGHT = 8 * (VER + 2) + PAD * 2;
int FPS = 30, GUIDES = 1, ZOOM = 2;
Uint8 chrbuf[2048];
SDL_Window *gWindow = NULL;
SDL_Renderer *gRenderer = NULL;
SDL_Texture *gTexture = NULL;
Uint32 *pixels;
void clear(Uint32 *dst) {
int i, j;
for(i = 0; i < HEIGHT; i++)
for(j = 0; j < WIDTH; j++)
dst[i * WIDTH + j] = 0;
}
void putpixel(Uint32 *dst, int x, int y) {
if(x >= 0 && x < WIDTH - 8 && y >= 0 && y < HEIGHT - 8)
dst[(y + PAD) * WIDTH + (x + PAD)] = 0xffffffff;
}
void drawletter(Uint32 *dst, int x, int y, int id) {
int v, h, offset = id * 16;
for(v = 0; v < 8; v++)
for(h = 0; h < 8; h++) {
int px = (x * 8) + (8 - h);
int py = (y * 8) + v;
int ch1 = chrbuf[offset + v];
int ch2 = chrbuf[offset + v + 8];
int clr = ((ch1 >> h) & 0x1) + (((ch2 >> h) & 0x1) << 1);
if(clr)
putpixel(dst, px, py);
}
}
void drawbody(Uint32 *dst) {
int i, x = 0, line = 0;
for(i = 0; i < text_len; ++i) {
char c = text[i];
drawletter(dst, x, line, (int)c);
x++;
if(c == '\n') {
x = 0;
line++;
}
}
}
void redraw(Uint32 *dst) {
clear(dst);
drawbody(dst);
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32));
SDL_RenderClear(gRenderer);
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
SDL_RenderPresent(gRenderer);
}
void dotext(SDL_Event *event) {
int i;
for(i = 0; i < SDL_TEXTINPUTEVENT_TEXT_SIZE; ++i) {
char c = event->text.text[i];
if(c < ' ' || c > '~') break;
pushchar(c);
}
redraw(pixels);
}
void dokey(SDL_Event *event) {
switch(event->key.keysym.sym) {
case SDLK_RETURN: pushchar('\n'); break;
case SDLK_DOWN: down(); break;
case SDLK_UP: up(); break;
case SDLK_LEFT: left(); break;
case SDLK_RIGHT: right(); break;
}
}
int loadchr(FILE *f) {
if(!f) return error("Load", "Invalid font file");
if(!fread(chrbuf, sizeof(chrbuf), 1, f))
return error("Load", "Invalid font file size");
puts("Load: Complete");
fclose(f);
return 1;
}
int init(void) {
if(SDL_Init(SDL_INIT_VIDEO) < 0)
return error("Init", SDL_GetError());
gWindow = SDL_CreateWindow("Moogle",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WIDTH * ZOOM,
HEIGHT * ZOOM,
SDL_WINDOW_SHOWN);
if(gWindow == NULL)
return error("Window", SDL_GetError());
gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
if(gRenderer == NULL)
return error("Renderer", SDL_GetError());
gTexture = SDL_CreateTexture(gRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
WIDTH,
HEIGHT);
if(gTexture == NULL)
return error("Texture", SDL_GetError());
pixels = (Uint32 *)malloc(WIDTH * HEIGHT * sizeof(Uint32));
if(pixels == NULL)
return error("Pixels", "Failed to allocate memory");
clear(pixels);
return 1;
}
void quit(void) {
free(pixels);
SDL_DestroyTexture(gTexture);
gTexture = NULL;
SDL_DestroyRenderer(gRenderer);
gRenderer = NULL;
SDL_DestroyWindow(gWindow);
gWindow = NULL;
SDL_Quit();
exit(0);
}
int main(int argc, char *argv[]) {
int ticknext = 0;
if(!init())
return error("Init", "Failure");
loadchr(fopen("type.chr", "r"));
if(argc > 1)
loadtxt(argv[1]);
redraw(pixels);
while(1) {
int tick = SDL_GetTicks();
SDL_Event event;
if(tick < ticknext)
SDL_Delay(ticknext - tick);
ticknext = tick + (1000 / FPS);
while(SDL_PollEvent(&event) != 0) {
switch(event.type) {
case SDL_QUIT: quit(); break;
case SDL_TEXTINPUT: dotext(&event); break;
case SDL_KEYDOWN: dokey(&event); break;
}
}
}
quit();
return 0;
}
#include <SDL2/SDL.h>
#include <stdio.h>
int error(char *msg, const char *err) {
printf("Error %s: %s\n", msg, err);
return 0;
}
#define HOR 32
#define VER 16
#define PAD 8
#define TEXTSZ 1024 * 32
char text_before[TEXTSZ+1]; /* index 0 = start of file */
int text_before_len = 0; /* where the next char typed will go */
char text_after[TEXTSZ+1]; /* index 0 = end of file */
int text_after_len = 0;
void pushchar(char c) {
if(text_before_len + text_after_len >= TEXTSZ)
return;
text_before[text_before_len++] = c;
}
void left() {
if(text_before_len == 0) return;
text_after[text_after_len] = text_before[text_before_len-1];
++text_after_len;
--text_before_len;
text_before[text_before_len] = '\0';
}
void right() {
if(text_after_len == 0) return;
text_before[text_before_len] = text_after[text_after_len-1];
++text_before_len;
--text_after_len;
text_before[text_after_len] = '\0';
}
int loadtxt(char *name) {
char line[256];
FILE *f = fopen(name, "r");
if(!f) return error("Load", "Invalid input file");
text_before_len = 0;
text_after_len = 0;
while(fgets(line, 256, f)) {
int i = 0;
char c;
while((c = line[i++]))
pushchar(c);
}
/* reset cursor */
while(text_before_len > 0)
left();
printf("Loaded: %s\n", name);
fclose(f);
return 1;
}
int cursorcol() {
int result = 0;
int c;
for(c = text_before_len-1; c >= 0; --c) {
if(text_before[c] == '\n') break;
++result;
}
return result;
}
void down() {
int col = cursorcol();
/* skip rest of line */
while(text_after_len > 0 && text_after[text_after_len-1] != '\n')
right();
/* scan forward on next line */
right();
for(; col > 0 && text_after_len > 0 && text_after[text_after_len-1] != '\n'; --col)
right();
}
void up() {
int col = cursorcol();
/* scan back to end of previous line */
left();
while(text_before_len > 0 && text_before[text_before_len-1] != '\n')
left();
/* scan back to start of previous line */
left();
while(text_before_len > 0 && text_before[text_before_len-1] != '\n')
left();
/* scan forward on previous line */
for(; col > 0 && text_after_len > 0 && text_after[text_after_len-1] != '\n'; --col)
right();
}
int WIDTH = 8 * HOR + PAD * 2;
int HEIGHT = 8 * (VER + 2) + PAD * 2;
int FPS = 30, GUIDES = 1, ZOOM = 2;
Uint8 chrbuf[2048];
SDL_Window *gWindow = NULL;
SDL_Renderer *gRenderer = NULL;
SDL_Texture *gTexture = NULL;
Uint32 *pixels;
void clear(Uint32 *dst) {
int i, j;
for(i = 0; i < HEIGHT; i++)
for(j = 0; j < WIDTH; j++)
dst[i * WIDTH + j] = 0;
}
void putpixel(Uint32 *dst, int x, int y) {
if(x >= 0 && x < WIDTH - 8 && y >= 0 && y < HEIGHT - 8)
dst[(y + PAD) * WIDTH + (x + PAD)] = 0xffffffff;
}
void drawletter(Uint32 *dst, int x, int y, int id) {
int v, h, offset = id * 16;
for(v = 0; v < 8; v++)
for(h = 0; h < 8; h++) {
int px = (x * 8) + (8 - h);
int py = (y * 8) + v;
int ch1 = chrbuf[offset + v];
int ch2 = chrbuf[offset + v + 8];
int clr = ((ch1 >> h) & 0x1) + (((ch2 >> h) & 0x1) << 1);
if(clr)
putpixel(dst, px, py);
}
}
void drawbody(Uint32 *dst) {
int i, x = 0, line = 0;
for(i = 0; i < text_before_len; ++i) {
char c = text_before[i];
drawletter(dst, x, line, (int)c);
x++;
if(c == '\n') {
x = 0;
line++;
}
}
for(i = text_after_len-1; i >= 0; --i) {
char c = text_after[i];
drawletter(dst, x, line, (int)c);
x++;
if(c == '\n') {
x = 0;
line++;
}
}
}
void redraw(Uint32 *dst) {
clear(dst);
drawbody(dst);
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32));
SDL_RenderClear(gRenderer);
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
SDL_RenderPresent(gRenderer);
}
void dotext(SDL_Event *event) {
int i;
for(i = 0; i < SDL_TEXTINPUTEVENT_TEXT_SIZE; ++i) {
char c = event->text.text[i];
if(c < ' ' || c > '~') break;
pushchar(c);
}
redraw(pixels);
}
void dokey(SDL_Event *event) {
switch(event->key.keysym.sym) {
case SDLK_RETURN: pushchar('\n'); break;
case SDLK_DOWN: down(); break;
case SDLK_UP: up(); break;
case SDLK_LEFT: left(); break;
case SDLK_RIGHT: right(); break;
}
}
int loadchr(FILE *f) {
if(!f) return error("Load", "Invalid font file");
if(!fread(chrbuf, sizeof(chrbuf), 1, f))
return error("Load", "Invalid font file size");
puts("Load: Complete");
fclose(f);
return 1;
}
int init(void) {
if(SDL_Init(SDL_INIT_VIDEO) < 0)
return error("Init", SDL_GetError());
gWindow = SDL_CreateWindow("Moogle",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WIDTH * ZOOM,
HEIGHT * ZOOM,
SDL_WINDOW_SHOWN);
if(gWindow == NULL)
return error("Window", SDL_GetError());
gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
if(gRenderer == NULL)
return error("Renderer", SDL_GetError());
gTexture = SDL_CreateTexture(gRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
WIDTH,
HEIGHT);
if(gTexture == NULL)
return error("Texture", SDL_GetError());
pixels = (Uint32 *)malloc(WIDTH * HEIGHT * sizeof(Uint32));
if(pixels == NULL)
return error("Pixels", "Failed to allocate memory");
clear(pixels);
return 1;
}
void quit(void) {
free(pixels);
SDL_DestroyTexture(gTexture);
gTexture = NULL;
SDL_DestroyRenderer(gRenderer);
gRenderer = NULL;
SDL_DestroyWindow(gWindow);
gWindow = NULL;
SDL_Quit();
exit(0);
}
int main(int argc, char *argv[]) {
int ticknext = 0;
if(!init())
return error("Init", "Failure");
loadchr(fopen("type.chr", "r"));
if(argc > 1)
loadtxt(argv[1]);
redraw(pixels);
while(1) {
int tick = SDL_GetTicks();
SDL_Event event;
if(tick < ticknext)
SDL_Delay(ticknext - tick);
ticknext = tick + (1000 / FPS);
while(SDL_PollEvent(&event) != 0) {
switch(event.type) {
case SDL_QUIT: quit(); break;
case SDL_TEXTINPUT: dotext(&event); break;
case SDL_KEYDOWN: dokey(&event); break;
}
}
}
quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment