summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Untitled1
-rw-r--r--buffer.c98
-rw-r--r--colors.h (renamed from colors.c)0
-rw-r--r--command.c18
-rw-r--r--command.h5
-rw-r--r--config.c8
-rw-r--r--main.c124
-rw-r--r--settings.h0
-rw-r--r--ted-base.c72
-rw-r--r--ted.cfg4
-rw-r--r--ted.h74
-rw-r--r--text.c19
-rw-r--r--util.c1
13 files changed, 259 insertions, 165 deletions
diff --git a/Untitled b/Untitled
index e1305f3..dce98ed 100644
--- a/Untitled
+++ b/Untitled
@@ -1,4 +1,3 @@
1 2 3 4
t e s t
he ll o!! !!
-
diff --git a/buffer.c b/buffer.c
index 5fbcd2e..fcd803e 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,50 +1,9 @@
// Text buffers - These store the contents of a file.
-// a position in the buffer
-typedef struct {
- u32 line;
- u32 index; // index of character in line (not the same as column, since a tab is settings->tab_width columns)
-} BufferPos;
-
-typedef struct {
- u32 len;
- u32 capacity;
- char32_t *str;
-} Line;
-
-// this refers to replacing prev_len characters (found in prev_text) at pos with new_len characters
-typedef struct BufferEdit {
- BufferPos pos;
- u32 new_len;
- u32 prev_len;
- char32_t *prev_text;
- double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
-} BufferEdit;
-
-typedef struct {
- char const *filename;
- Settings *settings;
- double scroll_x, scroll_y; // number of characters scrolled in the x/y direction
- Font *font;
- BufferPos cursor_pos;
- BufferPos selection_pos; // if selection is true, the text between selection_pos and cursor_pos is selected.
- bool selection;
- bool store_undo_events; // set to false to disable undo events
- float x1, y1, x2, y2;
- u32 nlines;
- u32 lines_capacity;
- Line *lines;
- char error[128];
- BufferEdit *undo_history; // dynamic array of undo history
- BufferEdit *redo_history; // dynamic array of redo history
-} TextBuffer;
-
-
-void buffer_create(TextBuffer *buffer, Font *font, Settings *settings) {
+void buffer_create(TextBuffer *buffer, Ted *ted) {
util_zero_memory(buffer, sizeof *buffer);
- buffer->font = font;
buffer->store_undo_events = true;
- buffer->settings = settings;
+ buffer->ted = ted;
}
// this is a macro so we get -Wformat warnings
@@ -153,6 +112,16 @@ BufferPos buffer_end_of_file(TextBuffer *buffer) {
return (BufferPos){.line = buffer->nlines - 1, .index = buffer->lines[buffer->nlines-1].len};
}
+// Get the font used for this buffer.
+static inline Font *buffer_font(TextBuffer *buffer) {
+ return buffer->ted->font;
+}
+
+// Get the settings used for this buffer.
+static inline Settings *buffer_settings(TextBuffer *buffer) {
+ return &buffer->ted->settings;
+}
+
// Returns a simple checksum of the buffer.
// This is only used for testing, and shouldn't be relied on.
static u64 buffer_checksum(TextBuffer *buffer) {
@@ -211,7 +180,7 @@ static BufferPos buffer_pos_advance(TextBuffer *buffer, BufferPos pos, size_t nc
while (line != end) {
u32 chars_from_this_line = line->len - index;
if (chars_left <= chars_from_this_line) {
- index += chars_left;
+ index += (u32)chars_left;
pos.index = index;
pos.line = (u32)(line - buffer->lines);
return pos;
@@ -380,7 +349,7 @@ static bool buffer_edit_does_anything(TextBuffer *buffer, BufferEdit *edit) {
// has enough time passed since the last edit that we should create a new one?
static bool buffer_edit_split(TextBuffer *buffer) {
double curr_time = time_get_seconds();
- double undo_time_cutoff = buffer->settings->undo_save_time; // only keep around edits for this long (in seconds).
+ double undo_time_cutoff = buffer_settings(buffer)->undo_save_time; // only keep around edits for this long (in seconds).
BufferEdit *last_edit = arr_lastp(buffer->undo_history);
if (!last_edit) return true;
return curr_time - last_edit->time > undo_time_cutoff;
@@ -466,8 +435,7 @@ void buffer_free(TextBuffer *buffer) {
arr_free(buffer->undo_history);
arr_free(buffer->redo_history);
- Settings *settings = buffer->settings;
- Font *font = buffer->font;
+ Ted *ted = buffer->ted;
// zero buffer, except for error
char error[sizeof buffer->error];
@@ -475,7 +443,7 @@ void buffer_free(TextBuffer *buffer) {
memset(buffer, 0, sizeof *buffer);
memcpy(buffer->error, error, sizeof error);
- buffer_create(buffer, font, settings);
+ buffer_create(buffer, ted);
}
@@ -611,10 +579,10 @@ static void buffer_print(TextBuffer const *buffer) {
static u32 buffer_index_to_column(TextBuffer *buffer, u32 line, u32 index) {
char32_t *str = buffer->lines[line].str;
u32 col = 0;
+ uint tab_width = buffer_settings(buffer)->tab_width;
for (u32 i = 0; i < index; ++i) {
switch (str[i]) {
case U'\t': {
- uint tab_width = buffer->settings->tab_width;
do
++col;
while (col % tab_width);
@@ -635,10 +603,10 @@ static u32 buffer_column_to_index(TextBuffer *buffer, u32 line, u32 column) {
char32_t *str = buffer->lines[line].str;
u32 len = buffer->lines[line].len;
u32 col = 0;
+ uint tab_width = buffer_settings(buffer)->tab_width;
for (u32 i = 0; i < len; ++i) {
switch (str[i]) {
case U'\t': {
- uint tab_width = buffer->settings->tab_width;
do {
if (col == column)
return i;
@@ -679,12 +647,12 @@ void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns) {
// returns the number of rows of text that can fit in the buffer, rounded down.
int buffer_display_lines(TextBuffer *buffer) {
- return (int)((buffer->y2 - buffer->y1) / text_font_char_height(buffer->font));
+ return (int)((buffer->y2 - buffer->y1) / text_font_char_height(buffer_font(buffer)));
}
// returns the number of columns of text that can fit in the buffer, rounded down.
int buffer_display_cols(TextBuffer *buffer) {
- return (int)((buffer->x2 - buffer->x1) / text_font_char_width(buffer->font));
+ return (int)((buffer->x2 - buffer->x1) / text_font_char_width(buffer_font(buffer)));
}
// make sure we don't scroll too far
@@ -729,9 +697,9 @@ v2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos) {
u32 line = pos.line, index = pos.index;
// we need to convert the index to a column
u32 col = buffer_index_to_column(buffer, line, index);
- float x = (float)((double)col - buffer->scroll_x) * text_font_char_width(buffer->font) + buffer->x1;
- float y = (float)((double)line - buffer->scroll_y) * text_font_char_height(buffer->font) + buffer->y1
- + text_font_char_height(buffer->font) * 0.2f; // slightly nudge
+ Font *font = buffer_font(buffer);
+ float x = (float)((double)col - buffer->scroll_x) * text_font_char_width(font) + buffer->x1;
+ float y = (float)((double)line - buffer->scroll_y + 0.2f /* nudge */) * text_font_char_height(font) + buffer->y1;
return V2(x, y);
}
@@ -739,12 +707,13 @@ v2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos) {
// returns false if the position is not inside the buffer.
bool buffer_pixels_to_pos(TextBuffer *buffer, v2 pixel_coords, BufferPos *pos) {
float x = pixel_coords.x, y = pixel_coords.y;
+ Font *font = buffer_font(buffer);
pos->line = pos->index = 0;
x -= buffer->x1;
y -= buffer->y1;
- x /= text_font_char_width(buffer->font);
- y /= text_font_char_height(buffer->font);
+ x /= text_font_char_width(font);
+ y /= text_font_char_height(font);
double display_col = (double)x;
if (display_col < 0 || display_col >= buffer_display_cols(buffer))
return false;
@@ -1139,7 +1108,7 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
buffer_edit(buffer, pos, 0, (u32)str.len);
} else {
// merge this edit into the previous one.
- last_edit->new_len += str.len;
+ last_edit->new_len += (u32)str.len;
}
}
@@ -1386,7 +1355,7 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
if (new_text_del_end > last_edit->new_len) new_text_del_end = last_edit->new_len;
if (new_text_del_end > new_text_del_start) {
// shrink length to get rid of that text
- last_edit->new_len -= new_text_del_end - new_text_del_start;
+ last_edit->new_len -= (u32)(new_text_del_end - new_text_del_start);
}
}
@@ -1617,13 +1586,16 @@ void buffer_check_valid(TextBuffer *buffer) {
// Render the text buffer in the given rectangle
void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
- Font *font = buffer->font;
+ // Correct the scroll, because the window size might have changed
+ buffer_correct_scroll(buffer);
+
+ Font *font = buffer_font(buffer);
u32 nlines = buffer->nlines;
Line *lines = buffer->lines;
float char_width = text_font_char_width(font),
char_height = text_font_char_height(font);
float header_height = char_height;
- Settings *settings = buffer->settings;
+ Settings *settings = buffer_settings(buffer);
u32 *colors = settings->colors;
// get screen coordinates of cursor
@@ -1693,7 +1665,6 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
u32 column = 0;
u32 start_line = (u32)buffer->scroll_y; // line to start rendering from
- //debug_print("Rendering from " U32_FMT, start_line);
if (buffer->selection) { // draw selection
glBegin(GL_QUADS);
@@ -1761,7 +1732,7 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
case U'\n': assert(0); break;
case U'\r': break; // for CRLF line endings
case U'\t': {
- uint tab_width = buffer->settings->tab_width;
+ uint tab_width = settings->tab_width;
do {
text_render_char(font, &text_state, U' ');
++column;
@@ -1778,7 +1749,6 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
text_state.x = render_start_x;
if (text_state.y > text_state.max_y) {
// made it to the bottom of the buffer view.
- //debug_println(" to " U32_FMT ".", line_idx);
break;
}
text_state.y += text_font_char_height(font);
diff --git a/colors.c b/colors.h
index 297e6d2..297e6d2 100644
--- a/colors.c
+++ b/colors.h
diff --git a/command.c b/command.c
index 8e210f0..6b99a92 100644
--- a/command.c
+++ b/command.c
@@ -19,6 +19,8 @@ char const *command_to_str(Command c) {
void command_execute(Ted *ted, Command c, i64 argument) {
TextBuffer *buffer = ted->active_buffer;
+ Settings *settings = &ted->settings;
+
switch (c) {
case CMD_UNKNOWN:
case CMD_COUNT:
@@ -120,7 +122,23 @@ void command_execute(Ted *ted, Command c, i64 argument) {
case CMD_REDO:
buffer_redo(buffer, argument);
break;
+
+ case CMD_TEXT_SIZE_INCREASE: {
+ i64 new_text_size = settings->text_size + argument;
+ if (new_text_size >= TEXT_SIZE_MIN && new_text_size <= TEXT_SIZE_MAX) {
+ settings->text_size = (u16)new_text_size;
+ ted_load_font(ted);
+ }
+ } break;
+ case CMD_TEXT_SIZE_DECREASE: {
+ i64 new_text_size = settings->text_size - argument;
+ if (new_text_size >= TEXT_SIZE_MIN && new_text_size <= TEXT_SIZE_MAX) {
+ settings->text_size = (u16)new_text_size;
+ ted_load_font(ted);
+ }
+ } break;
}
+
if (buffer_haserr(buffer)) {
strncpy(ted->error, buffer_geterr(buffer), sizeof ted->error - 1);
buffer_clearerr(buffer);
diff --git a/command.h b/command.h
index 5f69369..7744fdb 100644
--- a/command.h
+++ b/command.h
@@ -38,6 +38,9 @@ ENUM_U16 {
CMD_UNDO,
CMD_REDO,
+ CMD_TEXT_SIZE_INCREASE,
+ CMD_TEXT_SIZE_DECREASE,
+
CMD_COUNT
} ENUM_U16_END(Command);
@@ -78,5 +81,7 @@ static CommandName const command_names[CMD_COUNT] = {
{"save", CMD_SAVE},
{"undo", CMD_UNDO},
{"redo", CMD_REDO},
+ {"increase-text-size", CMD_TEXT_SIZE_INCREASE},
+ {"decrease-text-size", CMD_TEXT_SIZE_DECREASE}
};
diff --git a/config.c b/config.c
index 9cca619..4847aad 100644
--- a/config.c
+++ b/config.c
@@ -106,7 +106,7 @@ static u32 config_parse_key_combo(ConfigReader *cfg, char const *str) {
{"Tilde", "~", SDL_SCANCODE_GRAVE, 1}
};
- // @OPTIMIZE: sort key_names; do a binary search
+ // @OPTIMIZE: sort key_names (and split keyname1/2); do a binary search
for (size_t i = 0; i < arr_count(key_names); ++i) {
KeyName const *k = &key_names[i];
if (streq(str, k->keyname1) || (k->keyname2 && streq(str, k->keyname2))) {
@@ -286,6 +286,12 @@ void config_read(Ted *ted, char const *filename) {
} else {
config_err(cfg, "Invalid cursor blink time: %s.", value);
}
+ } else if (streq(key, "text-size")) {
+ if (is_integer && integer >= TEXT_SIZE_MIN && integer <= TEXT_SIZE_MAX) {
+ settings->text_size = (u16)integer;
+ } else {
+ config_err(cfg, "Invalid text size: %s.", value);
+ }
} else {
config_err(cfg, "Unrecognized core setting: %s.", key);
}
diff --git a/main.c b/main.c
index 41a9a98..8175ea0 100644
--- a/main.c
+++ b/main.c
@@ -18,22 +18,17 @@ no_warn_end
#define TED_PATH_MAX 256
-#include "command.h"
+#include "text.h"
#include "util.c"
-#include "filesystem.c"
-#include "colors.c"
-typedef struct {
- float cursor_blink_time_on, cursor_blink_time_off;
- u32 colors[COLOR_COUNT];
- u8 tab_width;
- u8 cursor_width;
- u8 undo_save_time;
-} Settings;
-#include "time.c"
-#include "unicode.h"
#define MATH_GL
#include "math.c"
-#include "text.h"
+
+#include "unicode.h"
+#include "command.h"
+#include "colors.h"
+#include "ted.h"
+#include "filesystem.c"
+#include "time.c"
#include "string32.c"
#include "arr.c"
#include "buffer.c"
@@ -57,38 +52,6 @@ static void die(char const *fmt, ...) {
exit(EXIT_FAILURE);
}
-// should the working directory be searched for files? set to true if the executable isn't "installed"
-static bool ted_search_cwd = false;
-#if _WIN32
-// @TODO
-#else
-static char const *const ted_global_data_dir = "/usr/share/ted";
-#endif
-
-// Check the various places a file could be, and return the full path.
-static Status ted_get_file(char const *name, char *out, size_t outsz) {
-#if _WIN32
- #error "@TODO(windows)"
-#else
- if (ted_search_cwd && fs_file_exists(name)) {
- // check in current working directory
- str_cpy(out, outsz, name);
- return true;
- }
-
- char *home = getenv("HOME");
- if (home) {
- str_printf(out, outsz, "%s/.local/share/ted/%s", home, name);
- if (!fs_file_exists(out)) {
- str_printf(out, outsz, "%s/%s", ted_global_data_dir, name);
- if (!fs_file_exists(out))
- return false;
- }
- }
- return true;
-#endif
-}
-
#if _WIN32
INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow) {
@@ -176,22 +139,13 @@ int main(int argc, char **argv) {
SDL_GL_SetSwapInterval(1); // vsync
- Font *font = NULL;
- {
- char font_filename[TED_PATH_MAX];
- if (ted_get_file("assets/font.ttf", font_filename, sizeof font_filename)) {
- font = text_font_load(font_filename, 16);
- if (!font) {
- die("Couldn't load font: %s", text_get_err());
- }
- } else {
- die("Couldn't find font file. There is probably a problem with your ted installation.");
- }
- }
+ ted_load_font(ted);
+ if (ted_haserr(ted))
+ die("Error loadng font: %s", ted_geterr(ted));
TextBuffer text_buffer;
TextBuffer *buffer = &text_buffer;
- buffer_create(buffer, font, settings);
+ buffer_create(buffer, ted);
ted->active_buffer = buffer;
char const *starting_filename = "Untitled";
@@ -220,6 +174,9 @@ int main(int argc, char **argv) {
Uint32 time_at_last_frame = SDL_GetTicks();
bool quit = false;
+ bool ctrl_down = false;
+ bool shift_down = false;
+ bool alt_down = false;
while (!quit) {
#if DEBUG
//printf("\033[H\033[2J");
@@ -227,14 +184,11 @@ int main(int argc, char **argv) {
SDL_Event event;
Uint8 const *keyboard_state = SDL_GetKeyboardState(NULL);
- bool ctrl_down = keyboard_state[SDL_SCANCODE_LCTRL] || keyboard_state[SDL_SCANCODE_RCTRL];
- bool shift_down = keyboard_state[SDL_SCANCODE_LSHIFT] || keyboard_state[SDL_SCANCODE_RSHIFT];
- bool alt_down = keyboard_state[SDL_SCANCODE_LALT] || keyboard_state[SDL_SCANCODE_RALT];
- u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT
- | (u32)shift_down << KEY_MODIFIER_SHIFT_BIT
- | (u32)alt_down << KEY_MODIFIER_ALT_BIT;
while (SDL_PollEvent(&event)) {
+ u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT
+ | (u32)shift_down << KEY_MODIFIER_SHIFT_BIT
+ | (u32)alt_down << KEY_MODIFIER_ALT_BIT;
// @TODO: make a function to handle text buffer events
switch (event.type) {
case SDL_QUIT:
@@ -279,6 +233,18 @@ int main(int argc, char **argv) {
break;
case SDL_KEYDOWN: {
SDL_Scancode scancode = event.key.keysym.scancode;
+ switch (scancode) {
+ case SDL_SCANCODE_LCTRL:
+ case SDL_SCANCODE_RCTRL:
+ ctrl_down = true; break;
+ case SDL_SCANCODE_LSHIFT:
+ case SDL_SCANCODE_RSHIFT:
+ shift_down = true; break;
+ case SDL_SCANCODE_LALT:
+ case SDL_SCANCODE_RALT:
+ alt_down = true; break;
+ default: break;
+ }
SDL_Keymod modifier = event.key.keysym.mod;
u32 key_combo = (u32)scancode << 3 |
(u32)((modifier & (KMOD_LCTRL|KMOD_RCTRL)) != 0) << KEY_MODIFIER_CTRL_BIT |
@@ -298,13 +264,37 @@ int main(int argc, char **argv) {
}
}
} break;
+ case SDL_KEYUP: {
+ SDL_Scancode scancode = event.key.keysym.scancode;
+ switch (scancode) {
+ case SDL_SCANCODE_LCTRL:
+ case SDL_SCANCODE_RCTRL:
+ ctrl_down = false; break;
+ case SDL_SCANCODE_LSHIFT:
+ case SDL_SCANCODE_RSHIFT:
+ shift_down = false; break;
+ case SDL_SCANCODE_LALT:
+ case SDL_SCANCODE_RALT:
+ alt_down = false; break;
+ default: break;
+ }
+ } break;
case SDL_TEXTINPUT: {
char *text = event.text.text;
- buffer_insert_utf8_at_cursor(buffer, text);
+ if (key_modifier == 0) // unfortunately, some key combinations like ctrl+minus still register as a "-" text input event
+ buffer_insert_utf8_at_cursor(buffer, text);
} break;
}
+
+ if (ted_haserr(ted)) {
+ die("%s", ted_geterr(ted));
+ }
}
+ u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT
+ | (u32)shift_down << KEY_MODIFIER_SHIFT_BIT
+ | (u32)alt_down << KEY_MODIFIER_ALT_BIT;
+
double frame_dt;
{
Uint32 time_this_frame = SDL_GetTicks();
@@ -351,7 +341,7 @@ int main(int argc, char **argv) {
float x1 = 50, y1 = 50, x2 = window_widthf-50, y2 = window_heightf-50;
buffer_render(buffer, x1, y1, x2, y2);
if (text_has_err()) {
- debug_println("Text error: %s\n", text_get_err());
+ die("Text error: %s\n", text_get_err());
break;
}
}
@@ -369,7 +359,7 @@ int main(int argc, char **argv) {
SDL_DestroyWindow(window);
SDL_Quit();
buffer_free(buffer);
- text_font_free(font);
+ text_font_free(ted->font);
free(ted);
#if _WIN32
for (int i = 0; i < argc; ++i)
diff --git a/settings.h b/settings.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/settings.h
diff --git a/ted-base.c b/ted-base.c
index 784bbe9..6ac9c5f 100644
--- a/ted-base.c
+++ b/ted-base.c
@@ -1,26 +1,3 @@
-typedef struct {
- u32 line_number; // config line number where this was set
- Command command; // this will be 0 (COMMAND_UNKNOWN) if there's no action for the key
- i64 argument;
-} KeyAction;
-
-#define SCANCODE_COUNT 0x120 // SDL scancodes should be less than this value.
-// a "key combo" is some subset of {control, shift, alt} + some key.
-#define KEY_COMBO_COUNT (SCANCODE_COUNT << 3)
-#define KEY_MODIFIER_CTRL_BIT 0
-#define KEY_MODIFIER_SHIFT_BIT 1
-#define KEY_MODIFIER_ALT_BIT 2
-#define KEY_MODIFIER_CTRL (1<<KEY_MODIFIER_CTRL_BIT)
-#define KEY_MODIFIER_SHIFT (1<<KEY_MODIFIER_SHIFT_BIT)
-#define KEY_MODIFIER_ALT (1<<KEY_MODIFIER_ALT_BIT)
-// ctrl+alt+c is encoded as SDL_SCANCODE_C << 3 | KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT
-
-typedef struct {
- TextBuffer *active_buffer;
- Settings settings;
- KeyAction key_actions[KEY_COMBO_COUNT];
- char error[256];
-} Ted;
// this is a macro so we get -Wformat warnings
#define ted_seterr(buffer, ...) \
@@ -56,3 +33,52 @@ static void *ted_realloc(Ted *ted, void *p, size_t new_size) {
return ret;
}
+// should the working directory be searched for files? set to true if the executable isn't "installed"
+static bool ted_search_cwd = false;
+#if _WIN32
+// @TODO
+#else
+static char const *const ted_global_data_dir = "/usr/share/ted";
+#endif
+
+// Check the various places a file could be, and return the full path.
+static Status ted_get_file(char const *name, char *out, size_t outsz) {
+#if _WIN32
+ #error "@TODO(windows)"
+#else
+ if (ted_search_cwd && fs_file_exists(name)) {
+ // check in current working directory
+ str_cpy(out, outsz, name);
+ return true;
+ }
+
+ char *home = getenv("HOME");
+ if (home) {
+ str_printf(out, outsz, "%s/.local/share/ted/%s", home, name);
+ if (!fs_file_exists(out)) {
+ str_printf(out, outsz, "%s/%s", ted_global_data_dir, name);
+ if (!fs_file_exists(out))
+ return false;
+ }
+ }
+ return true;
+#endif
+}
+
+static void ted_load_font(Ted *ted) {
+ char font_filename[TED_PATH_MAX];
+ if (ted_get_file("assets/font.ttf", font_filename, sizeof font_filename)) {
+ Font *font = text_font_load(font_filename, ted->settings.text_size);
+ if (font) {
+ if (ted->font) {
+ text_font_free(ted->font);
+ }
+ ted->font = font;
+ } else {
+ ted_seterr(ted, "Couldn't load font: %s", text_get_err());
+ text_clear_err();
+ }
+ } else {
+ ted_seterr(ted, "Couldn't find font file. There is probably a problem with your ted installation.");
+ }
+}
diff --git a/ted.cfg b/ted.cfg
index 80dab7f..6573872 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -9,6 +9,7 @@ cursor-blink-time-off = 0.3
# if you do a bunch of typing, then undo, it will generally
# undo the past this many seconds of editing.
undo-save-time = 6
+text-size = 16
[keyboard]
# motion and selection
@@ -54,6 +55,9 @@ Ctrl+s = :save
Ctrl+z = :undo
Ctrl+Shift+z = :redo
+Ctrl++ = 3 :increase-text-size
+Ctrl+- = 3 :decrease-text-size
+
[colors]
border = #a77
cursor-line-bg = #222
diff --git a/ted.h b/ted.h
new file mode 100644
index 0000000..0f5b72c
--- /dev/null
+++ b/ted.h
@@ -0,0 +1,74 @@
+#define TEXT_SIZE_MIN 6
+#define TEXT_SIZE_MAX 70
+
+typedef struct {
+ float cursor_blink_time_on, cursor_blink_time_off;
+ u32 colors[COLOR_COUNT];
+ u16 text_size;
+ u8 tab_width;
+ u8 cursor_width;
+ u8 undo_save_time;
+} Settings;
+
+#define SCANCODE_COUNT 0x120 // SDL scancodes should be less than this value.
+// a "key combo" is some subset of {control, shift, alt} + some key.
+#define KEY_COMBO_COUNT (SCANCODE_COUNT << 3)
+#define KEY_MODIFIER_CTRL_BIT 0
+#define KEY_MODIFIER_SHIFT_BIT 1
+#define KEY_MODIFIER_ALT_BIT 2
+#define KEY_MODIFIER_CTRL (1<<KEY_MODIFIER_CTRL_BIT)
+#define KEY_MODIFIER_SHIFT (1<<KEY_MODIFIER_SHIFT_BIT)
+#define KEY_MODIFIER_ALT (1<<KEY_MODIFIER_ALT_BIT)
+// ctrl+alt+c is encoded as SDL_SCANCODE_C << 3 | KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT
+
+typedef struct {
+ u32 line_number; // config line number where this was set
+ Command command; // this will be 0 (COMMAND_UNKNOWN) if there's no action for the key
+ i64 argument;
+} KeyAction;
+
+// a position in the buffer
+typedef struct {
+ u32 line;
+ u32 index; // index of character in line (not the same as column, since a tab is settings->tab_width columns)
+} BufferPos;
+
+typedef struct {
+ u32 len;
+ u32 capacity;
+ char32_t *str;
+} Line;
+
+// this refers to replacing prev_len characters (found in prev_text) at pos with new_len characters
+typedef struct BufferEdit {
+ BufferPos pos;
+ u32 new_len;
+ u32 prev_len;
+ char32_t *prev_text;
+ double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
+} BufferEdit;
+
+typedef struct {
+ char const *filename;
+ struct Ted *ted; // we keep a back-pointer to the ted instance so we don't have to pass it in to every buffer function
+ double scroll_x, scroll_y; // number of characters scrolled in the x/y direction
+ BufferPos cursor_pos;
+ BufferPos selection_pos; // if selection is true, the text between selection_pos and cursor_pos is selected.
+ bool selection;
+ bool store_undo_events; // set to false to disable undo events
+ float x1, y1, x2, y2;
+ u32 nlines;
+ u32 lines_capacity;
+ Line *lines;
+ char error[128];
+ BufferEdit *undo_history; // dynamic array of undo history
+ BufferEdit *redo_history; // dynamic array of redo history
+} TextBuffer;
+
+typedef struct Ted {
+ Font *font;
+ TextBuffer *active_buffer;
+ Settings settings;
+ KeyAction key_actions[KEY_COMBO_COUNT];
+ char error[256];
+} Ted;
diff --git a/text.c b/text.c
index 94c4a2c..3044ecb 100644
--- a/text.c
+++ b/text.c
@@ -47,10 +47,10 @@ static void text_set_err(char const *fmt, ...) {
}
}
-static void text_load_char_page(Font *font, int page) {
+static Status text_load_char_page(Font *font, int page) {
if (font->char_pages[page]) {
// already loaded
- return;
+ return true;
}
font->char_pages[page] = calloc(CHAR_PAGE_SIZE, sizeof *font->char_pages[page]);
for (int bitmap_width = 128, bitmap_height = 128; bitmap_width <= 4096; bitmap_width *= 2, bitmap_height *= 2) {
@@ -93,7 +93,9 @@ static void text_load_char_page(Font *font, int page) {
if (text_has_err()) {
free(font->char_pages[page]);
font->char_pages[page] = NULL;
+ return false;
}
+ return true;
}
Font *text_font_load(char const *ttf_filename, float font_size) {
@@ -114,8 +116,8 @@ Font *text_font_load(char const *ttf_filename, float font_size) {
if (bytes_read == file_size) {
font->char_height = font_size;
font->ttf_data = file_data;
- text_load_char_page(font, 0); // load page with Latin text, etc.
- { // calculate width of the character 'a'
+ if (text_load_char_page(font, 0)) { // load page with Latin text, etc.
+ // calculate width of the character 'a'
stbtt_aligned_quad q = {0};
float x = 0, y = 0;
stbtt_GetBakedQuad(font->char_pages[0], font->tex_widths[0], font->tex_heights[0],
@@ -158,11 +160,12 @@ static void text_render_with_page(Font *font, int page) {
// we were rendering chars from another page.
glEnd(); // stop doing that
}
- text_load_char_page(font, page); // load the page if necessary
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, font->textures[page]);
+ if (text_load_char_page(font, page)) { // load the page if necessary
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, font->textures[page]);
+ font->curr_page = page;
+ }
glBegin(GL_QUADS);
- font->curr_page = page;
}
}
diff --git a/util.c b/util.c
index 4041511..aa4a737 100644
--- a/util.c
+++ b/util.c
@@ -16,7 +16,6 @@ static bool util_is_power_of_2(u64 x) {
}
static void util_zero_memory(void *mem, size_t size) {
- extern void *memset(void *s, int c, size_t n);
memset(mem, 0, size);
}