summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Doxyfile23
-rw-r--r--base.h54
-rw-r--r--buffer.c3
-rw-r--r--colors.h6
-rw-r--r--command.h95
-rw-r--r--ds.h56
-rw-r--r--main.c4
-rw-r--r--os.h128
-rw-r--r--ted.h1325
-rw-r--r--text.h83
-rw-r--r--unicode.h49
-rw-r--r--util.h90
13 files changed, 1094 insertions, 823 deletions
diff --git a/.gitignore b/.gitignore
index e16f559..ebe7729 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,4 @@ UpgradeLog.htm
compile_commands.json
# clangd creates .cache on windows at least
.cache
+doc
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..a647a92
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,23 @@
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = ted
+PROJECT_BRIEF = "A text editor"
+PROJECT_LOGO = assets/icon.ico
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+OPTIMIZE_OUTPUT_FOR_C = YES
+MARKDOWN_SUPPORT = YES
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.h
+RECURSIVE = NO
+GENERATE_HTML = YES
+HTML_OUTPUT = .
+HTML_FILE_EXTENSION = .html
+GENERATE_LATEX = NO
+ENABLE_PREPROCESSING = YES
+MULTILINE_CPP_IS_BRIEF = YES
+AUTOLINK_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = YES
+EXTRACT_STATIC = YE
+COLLABORATION_GRAPH = NO
+EXCLUDE = lsp.h, keywords.h, pcre-inc.h, sdl-inc.h
diff --git a/base.h b/base.h
index a5e5299..a2ba470 100644
--- a/base.h
+++ b/base.h
@@ -1,5 +1,7 @@
-// basic types and macros.
-// this file is included almost everywhere.
+/// \file
+/// basic types and macros.
+///
+/// this file is included almost everywhere.
#ifndef BASE_H_
#define BASE_H_
@@ -90,21 +92,15 @@ typedef unsigned long ulong;
typedef long long llong;
typedef unsigned long long ullong;
-// allows
-// switch (c) {
-// case ANY_DIGIT:
-// ...
-// }
+/// allows
+/// ```
+/// switch (c) {
+/// case ANY_DIGIT:
+/// ...
+/// }
+/// ```
#define ANY_DIGIT '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
-#if __clang__
-#define ENUM_U8 typedef enum : u8
-#define ENUM_U8_END(name) name
-#else
-#define ENUM_U8 enum
-#define ENUM_U8_END(name) ; typedef u8 name
-#endif
-
#ifdef __GNUC__
#define WarnUnusedResult __attribute__((warn_unused_result))
#else
@@ -114,29 +110,23 @@ typedef unsigned long long ullong;
#if __GNUC__
#define ATTRIBUTE_PRINTF(fmt_idx, arg_idx) __attribute__ ((format(printf, fmt_idx, arg_idx)))
#else
+/// attribute for functions which are like `printf` (to give `-Wformat` warnings)
#define ATTRIBUTE_PRINTF(fmt_idx, arg_idx)
#endif
#if _MSC_VER > 1400
#define PRINTF_FORMAT_STRING _Printf_format_string_
#else
+/// needed to give format warnings for MSVC for custom functions
#define PRINTF_FORMAT_STRING
#endif
-// this type is an alias for bool, except that it
-// produces a warning if it's not used.
-// false = error, true = success
+/// this type is an alias for bool, except that it
+/// produces a warning if it's not used.
+/// false = error, true = success
#define Status bool WarnUnusedResult
#define arr_count(a) (sizeof (a) / sizeof *(a))
-
-// usage: if UNLIKELY (x > 2) ...
-#if __GNUC__
-#define UNLIKELY(x) (__builtin_expect(x,0))
-#else
-#define UNLIKELY(x) (x)
-#endif
-
#ifdef __GNUC__
#define no_warn_start _Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
@@ -183,7 +173,8 @@ static void print(const char *fmt, ...) {
// If you are adding new languages, DO NOT change the constant values
// of the previous languages. It will mess up config files which use :set-language!
typedef enum {
- LANG_NONE = 0, // avoid using this and use LANG_TEXT instead.
+ /// avoid using this and use LANG_TEXT instead.
+ LANG_NONE = 0,
LANG_C = 1,
LANG_CPP = 2,
LANG_RUST = 3,
@@ -191,16 +182,19 @@ typedef enum {
LANG_TEX = 5,
LANG_MARKDOWN = 6,
LANG_HTML = 7,
- LANG_CONFIG = 8, // .cfg files
+ /// .cfg files
+ LANG_CONFIG = 8,
LANG_JAVASCRIPT = 9,
LANG_JAVA = 10,
LANG_GO = 11,
- LANG_TED_CFG = 12, // like LANG_CONFIG, but with multiline strings.
+ /// like \ref LANG_CONFIG, but with multiline strings.
+ LANG_TED_CFG = 12,
LANG_TYPESCRIPT = 13,
LANG_JSON = 14,
LANG_XML = 15,
LANG_GLSL = 16,
- LANG_TEXT = 17, // plain text
+ /// plain text
+ LANG_TEXT = 17,
LANG_COUNT
} Language;
diff --git a/buffer.c b/buffer.c
index 8059c4e..f72ad9e 100644
--- a/buffer.c
+++ b/buffer.c
@@ -441,8 +441,7 @@ static BufferPos buffer_pos_advance(TextBuffer *buffer, BufferPos pos, size_t nc
}
-// returns "p2 - p1", that is, the number of characters between p1 and p2.
-static i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2) {
+i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2) {
assert(buffer_pos_valid(buffer, p1));
assert(buffer_pos_valid(buffer, p2));
diff --git a/colors.h b/colors.h
index 3d2d90f..9d82602 100644
--- a/colors.h
+++ b/colors.h
@@ -1,8 +1,12 @@
-// colors enum.
+/// \file
+/// colors enum.
#ifndef COLORS_H_
#define COLORS_H_
+/// colors enum.
+///
+/// See `ted.cfg` for what these mean.
typedef enum {
COLOR_UNKNOWN,
diff --git a/command.h b/command.h
index 3d1b98d..6e8a57b 100644
--- a/command.h
+++ b/command.h
@@ -1,53 +1,75 @@
-// command enum
+/// \file
+/// command enum
#ifndef COMMAND_H_
#define COMMAND_H_
-// `i | ARG_STRING` when used as an argument refers to `ted->strings[i]`
+/// `i | ARG_STRING` when used as an argument refers to `ted->strings[i]`
#define ARG_STRING 0x4000000000000000
+/// command enum
+///
+/// more documentation in `ted.cfg`.
typedef enum {
CMD_UNKNOWN,
- CMD_NOOP, // do nothing
+ /// do nothing
+ CMD_NOOP,
// movement and selection commands
- CMD_LEFT, // move cursor left
- CMD_RIGHT, // move cursor right
- CMD_UP, // move cursor up
- CMD_DOWN, // move cursor down
- CMD_SELECT_LEFT, // move cursor left, and select
+ /// move cursor left
+ CMD_LEFT,
+ /// move cursor right
+ CMD_RIGHT,
+ /// move cursor up
+ CMD_UP,
+ /// move cursor down
+ CMD_DOWN,
+ /// move cursor left, and select
+ CMD_SELECT_LEFT,
CMD_SELECT_RIGHT,
CMD_SELECT_UP,
CMD_SELECT_DOWN,
- CMD_LEFT_WORD, // move cursor left a word
+ /// move cursor left a word
+ CMD_LEFT_WORD,
CMD_RIGHT_WORD,
CMD_UP_BLANK_LINE,
CMD_DOWN_BLANK_LINE,
CMD_SELECT_LEFT_WORD,
CMD_SELECT_RIGHT_WORD,
- CMD_START_OF_LINE, // move cursor to start of line
- CMD_END_OF_LINE, // move cursor to end of line
- CMD_SELECT_START_OF_LINE, // select to start of line
- CMD_SELECT_END_OF_LINE, // select to end of line
- CMD_START_OF_FILE, // move cursor to start of buffer
- CMD_END_OF_FILE, // move cursor to end of buffer
+ /// move cursor to start of line
+ CMD_START_OF_LINE,
+ /// move cursor to end of line
+ CMD_END_OF_LINE,
+ /// select to start of line
+ CMD_SELECT_START_OF_LINE,
+ /// select to end of line
+ CMD_SELECT_END_OF_LINE,
+ /// move cursor to start of buffer
+ CMD_START_OF_FILE,
+ /// move cursor to end of buffer
+ CMD_END_OF_FILE,
CMD_SELECT_START_OF_FILE,
CMD_SELECT_END_OF_FILE,
- CMD_SELECT_ALL, // select entire buffer
+ /// select entire buffer
+ CMD_SELECT_ALL,
CMD_SELECT_PAGE_UP,
CMD_SELECT_PAGE_DOWN,
CMD_SELECT_UP_BLANK_LINE,
CMD_SELECT_DOWN_BLANK_LINE,
// insertion
- CMD_INSERT_TEXT, // insert text
- CMD_TAB, // insert '\t'
+ /// insert text
+ CMD_INSERT_TEXT,
+ /// insert `\t`
+ CMD_TAB,
CMD_BACKTAB,
- CMD_NEWLINE, // insert '\n' + autoindent -- also used to submit line buffers
+ /// insert `\n` + autoindent -- also used to submit line buffers
+ CMD_NEWLINE,
CMD_NEWLINE_BACK,
CMD_COMMENT_SELECTION,
// scrolling
- CMD_PAGE_UP, // move cursor up one page up (where one page is however tall the buffer is)
+ /// move cursor up one page up (where one page is however tall the buffer is)
+ CMD_PAGE_UP,
CMD_PAGE_DOWN,
// deletion
@@ -56,16 +78,20 @@ typedef enum {
CMD_BACKSPACE_WORD,
CMD_DELETE_WORD,
- CMD_OPEN, // open a file
- CMD_SAVE, // save current buffer
+ /// open a file
+ CMD_OPEN,
+ /// save current buffer
+ CMD_SAVE,
CMD_SAVE_AS,
- CMD_SAVE_ALL, // save all open buffers with unsaved changes
+ /// save all open buffers with unsaved changes
+ CMD_SAVE_ALL,
CMD_NEW,
CMD_UNDO,
CMD_REDO,
CMD_COMMAND_SELECTOR,
CMD_OPEN_CONFIG,
- CMD_RELOAD_ALL, // reload all buffers from file
+ /// reload all buffers from file
+ CMD_RELOAD_ALL,
CMD_QUIT,
// IDE features
@@ -73,7 +99,8 @@ typedef enum {
CMD_AUTOCOMPLETE,
CMD_AUTOCOMPLETE_BACK,
CMD_FIND_USAGES,
- CMD_GOTO_DEFINITION, // "go to definition of..." menu
+ /// "go to definition of..." menu
+ CMD_GOTO_DEFINITION,
CMD_GOTO_DEFINITION_AT_CURSOR,
CMD_GOTO_DECLARATION_AT_CURSOR,
CMD_GOTO_TYPE_DEFINITION_AT_CURSOR,
@@ -86,7 +113,8 @@ typedef enum {
CMD_FIND_REPLACE,
CMD_TAB_CLOSE,
- CMD_TAB_SWITCH, // argument = index of tab (starting at 0)
+ /// argument = index of tab (starting at 0)
+ CMD_TAB_SWITCH,
CMD_TAB_NEXT,
CMD_TAB_PREV,
CMD_TAB_MOVE_LEFT,
@@ -95,7 +123,8 @@ typedef enum {
CMD_TEXT_SIZE_INCREASE,
CMD_TEXT_SIZE_DECREASE,
- CMD_VIEW_ONLY, // toggle view-only mode
+ /// toggle view-only mode
+ CMD_VIEW_ONLY,
CMD_BUILD,
CMD_BUILD_PREV_ERROR,
@@ -103,15 +132,19 @@ typedef enum {
CMD_SHELL,
CMD_GENERATE_TAGS,
- CMD_GOTO_LINE, // open "goto line..." menu
+ /// open "goto line..." menu
+ CMD_GOTO_LINE,
CMD_SPLIT_HORIZONTAL,
CMD_SPLIT_VERTICAL,
CMD_SPLIT_JOIN,
- CMD_SPLIT_SWITCH, // switch to the other side of a split
- CMD_SPLIT_SWAP, // swap which side is which in a split.
+ /// switch to the other side of a split
+ CMD_SPLIT_SWITCH,
+ /// swap which side is which in a split.
+ CMD_SPLIT_SWAP,
- CMD_ESCAPE, // by default this is the escape key. closes menus, etc.
+ /// by default this is the escape key. closes menus, etc.
+ CMD_ESCAPE,
CMD_COUNT
} Command;
diff --git a/ds.h b/ds.h
index a588be7..dde3496 100644
--- a/ds.h
+++ b/ds.h
@@ -1,8 +1,7 @@
-#ifndef DS_H_
-#define DS_H_
+/*!
+\file
+\brief VARIOUS DATA STRUCTURES
-/*
-VARIOUS DATA STRUCTURES
- dynamic array
- string builder
- string hash table
@@ -13,7 +12,7 @@ any reasonable compiler will ignore the unused code.
functions in this file suffixed with _ are not meant to be used outside here, unless you
know what you're doing
-NOTE: even on 64-bit platforms, dynamic arrays can only hold ~2^32 elements.
+NOTE: even on 64-bit platforms, dynamic arrays can only hold ~2<sup>32</sup> elements.
IMPORTANT NOTE: If you are using this with structures containing `long double`s, do
#define ARR_LONG_DOUBLE
@@ -23,6 +22,9 @@ IMPORTANT NOTE: If you are using this with structures containing `long double`s,
which isnt important unless you're making a lot of arrays.)
*/
+#ifndef DS_H_
+#define DS_H_
+
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -208,19 +210,18 @@ static void *arr_copy_(const void *arr, size_t member_size) {
#endif
#define arr__join2(a,b) a##b
-#define arr__join(a,b) arr__join2(a,b) // macro used internally
-// if the array is not NULL, free it and set it to NULL
+/// macro used internally
+#define arr__join(a,b) arr__join2(a,b)
+/// if the array is not NULL, free it and set it to NULL
#define arr_free(a) do { if (a) { free(arr_hdr_(a)); (a) = NULL; } } while (0)
-// a nice alias
+/// a nice alias
#define arr_clear(a) arr_free(a)
-// add an item to the array - if allocation fails, the array will be freed and set to NULL.
-// (how this works: if we can successfully grow the array, increase the length and add the item.)
+/// add an item to the array - if allocation fails, the array will be freed and set to NULL.
+/// (how this works: if we can successfully grow the array, increase the length and add the item.)
#define arr_add(a, x) do { if (((a) = arr_cast_typeof(a) arr_grow1_((a), sizeof *(a)))) ((a)[arr_hdr_(a)->len++] = (x)); } while (0)
-// like arr_add, but instead of passing it the value, it returns a pointer to the value. returns NULL if allocation failed.
-// the added item will be zero-initialized.
+/// like arr_add, but instead of passing it the value, it returns a pointer to the value. returns NULL if allocation failed.
+/// the added item will be zero-initialized.
#define arr_addp(a) arr_cast_typeof(a) arr_add_ptr_((void **)&(a), sizeof *(a))
-// set the length of `a` to `n`, increasing the capacity if necessary.
-// the newly-added elements are zero-initialized.
#define arr_qsort(a, cmp) qsort((a), arr_len(a), sizeof *(a), (cmp))
#define arr_remove_last(a) do { assert(a); if (--arr_hdr_(a)->len == 0) arr_free(a); } while (0)
#define arr_remove(a, i) (void)((a) = arr_remove_((a), sizeof *(a), (i)))
@@ -234,15 +235,21 @@ static void *arr_copy_(const void *arr, size_t member_size) {
#define arr_copy(a) arr_cast_typeof(a) arr_copy_((a), sizeof *(a))
#define arr_foreach_ptr_end(a, type, var, end) type *end = (a) + arr_len(a); \
for (type *var = (a); var != end; ++var)
-// Iterate through each element of the array, setting var to a pointer to the element.
-// You can't use this like, e.g.:
-// if (something)
-// arr_foreach_ptr(a, int, i);
-// You'll get an error. You will need to use braces because it expands to multiple statements.
-// (we need to name the end pointer something unique, which is why there's that arr__join thing
-// we can't just declare it inside the for loop, because type could be something like char *.)
+/// Iterate through each element of the array, setting `var` to a pointer to the element.
+///
+/// You can't use this like, e.g.:
+/// ```
+/// if (something)
+/// arr_foreach_ptr(a, int, i)
+/// thing(*i);
+/// ```
+/// You'll get an error. You will need to use braces because it expands to multiple statements.
+/// (we need to name the end pointer something unique, which is why there's that `arr__join` thing
+/// we can't just declare it inside the for loop, because type could be something like `char *`.)
#define arr_foreach_ptr(a, type, var) arr_foreach_ptr_end(a, type, var, arr__join(_foreach_end,__LINE__))
-
+/// Reverse array.
+///
+/// You need to pass in the type because we don't have `typeof` in C yet (coming in C23 supposedly!)
#define arr_reverse(a, type) do { \
u64 _i, _len = arr_len(a); \
for (_i = 0; 2*_i < _len; ++_i) { \
@@ -255,9 +262,10 @@ static void *arr_copy_(const void *arr, size_t member_size) {
} \
} while (0)
-// Ensure that enough space is allocated for n elements.
+/// Ensure that enough space is allocated for `n` elements.
#define arr_reserve(a, n) arr_reserve_((void **)&(a), sizeof *(a), (n))
-// Similar to arr_reserve, but also sets the length of the array to n.
+/// set the length of `a` to `n`, increasing the capacity if necessary.
+/// the newly-added elements are zero-initialized.
#define arr_set_len(a, n) arr_set_len_((void **)&(a), sizeof *(a), (n))
#ifndef NDEBUG
diff --git a/main.c b/main.c
index f421ace..2cbe3ce 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
FUTURE FEATURES:
-- doxygen documentation for ted.h
- manual.md
- CSS highlighting
- option for separate colors for read/write highlights
@@ -25,6 +24,9 @@ FUTURE FEATURES:
- config variables
- bind key to multiple commands
- plugins?
+ - TED_PLUGIN macro defined before including ted.h
+ this can remove struct definitions to guarantee forwards compatibility
+ - language dynamic registration
- keyboard macros
- ctrl+9/0 to inc/dec number would be useful here
- with macros we can really test performance of buffer_insert_text_at_pos, etc. (which should ideally be fast)
diff --git a/os.h b/os.h
index a670a6b..6b9389a 100644
--- a/os.h
+++ b/os.h
@@ -1,4 +1,5 @@
-// a bunch of OS-dependent functions
+/// \file
+/// a bunch of OS-dependent functions
#ifndef OS_H_
#define OS_H_
@@ -22,45 +23,46 @@ typedef struct {
char name[];
} FsDirectoryEntry;
-// returns what kind of thing this is.
+/// returns what kind of thing this is.
FsType fs_path_type(const char *path);
FsPermission fs_path_permission(const char *path);
-// Does this file exist? Returns false for directories.
+/// Does this file exist? Returns false for directories.
bool fs_file_exists(const char *path);
-// Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist/out of memory.
-// When you're done with the entries, call fs_dir_entries_free (or call free on each entry, then on the whole array).
-// NOTE: The files/directories aren't returned in any particular order!
+/// Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist/out of memory.
+/// When you're done with the entries, call fs_dir_entries_free (or call free on each entry, then on the whole array).
+/// NOTE: The files/directories aren't returned in any particular order!
FsDirectoryEntry **fs_list_directory(const char *dirname);
-// Create the directory specified by `path`
-// Returns:
-// 1 if the directory was created successfully
-// 0 if the directory already exists
-// -1 if the path already exists, but it's not a directory, or if there's another error (e.g. don't have permission to create directory).
+/// Create the directory specified by `path`\n
+/// Returns:\n
+/// 1 if the directory was created successfully\n
+/// 0 if the directory already exists\n
+/// -1 if the path already exists, but it's not a directory, or if there's another error (e.g. don't have permission to create directory).\n
int fs_mkdir(const char *path);
-// Puts the current working directory into buf, including a null-terminator, writing at most buflen bytes.
-// Returns:
-// 1 if the working directory was inserted into buf successfully
-// 0 if buf is too short to hold the cwd
-// -1 if we can't get the cwd for whatever reason.
+// Puts the current working directory into buf, including a null-terminator, writing at most buflen bytes.\n
+// Returns:\n
+// 1 if the working directory was inserted into buf successfully\n
+// 0 if buf is too short to hold the cwd\n
+// -1 if we can't get the cwd for whatever reason.\n
int os_get_cwd(char *buf, size_t buflen);
-// Unlike ISO C rename() function, this will overwrite `newname` if it exists.
-// Returns:
-// >= 0 if successful
-// < 0 on error
+// Unlike ISO C rename() function, this will overwrite `newname` if it exists.\n
+// Returns:\n
+// >= 0 if successful\n
+// < 0 on error\n
int os_rename_overwrite(const char *oldname, const char *newname);
struct timespec time_last_modified(const char *filename);
struct timespec time_get(void);
-// sleep for a certain number of nanoseconds
+/// sleep for a certain number of nanoseconds
void time_sleep_ns(u64 ns);
-// free the entries generated by fs_list_directory.
+/// free the entries generated by fs_list_directory.
static void fs_dir_entries_free(FsDirectoryEntry **entries) {
for (int i = 0; entries[i]; ++i)
free(entries[i]);
free(entries);
}
+/// get current time in seconds since some arbitrary point
static double time_get_seconds(void) {
struct timespec t = time_get();
return (double)t.tv_sec
@@ -69,17 +71,17 @@ static double time_get_seconds(void) {
-// sleep for microseconds
+/// sleep for microseconds
static void time_sleep_us(u64 us) {
time_sleep_ns(us * 1000);
}
-// sleep for milliseconds
+/// sleep for milliseconds
static void time_sleep_ms(u64 ms) {
time_sleep_ns(ms * 1000000);
}
-// sleep for seconds
+/// sleep for seconds
static void time_sleep_s(u64 s) {
time_sleep_ns(s * 1000000000);
}
@@ -87,60 +89,70 @@ static void time_sleep_s(u64 s) {
typedef struct Process Process;
-// zero everything except what you're using
+/// zero everything except what you're using
typedef struct {
bool separate_stderr;
const char *working_directory;
+ /// for forwards compatibility
+ char _reserved[256];
} ProcessSettings;
typedef struct {
- // string like "exited with code 9"
+ /// string like "exited with code 9"
char message[62];
- // it might be possible that both signalled and exited are false,
- // if something weird happens.
+ /// it might be possible that both `signalled` and `exited` are false,
+ /// if something weird happens.
bool signalled;
bool exited;
+ /// only relevant if `exited = true`
int exit_code;
+ /// only relevant if `signalled = true`
int signal;
} ProcessExitInfo;
-// get process ID of this process
+/// get process ID of this process
int process_get_id(void);
-// execute the given command (like if it was passed to system()), creating a new Process object.
-// returns a valid process object on failure, but it will have an error, according to process_geterr
+/// execute the given command (like if it was passed to `system()`), creating a new \ref Process object.
+///
+/// returns a valid process object on failure, but it will have an error, according to \ref process_geterr
Process *process_run_ex(const char *command, const ProcessSettings *settings);
-// like process_run_ex, but with the default settings
+/// like \ref process_run_ex, but with the default settings
Process *process_run(const char *command);
-// returns the error last error produced, or NULL if there was no error.
+/// returns the error last error produced, or NULL if there was no error.
const char *process_geterr(Process *process);
-// write to stdin
-// returns:
-// -2 on error
-// or a non-negative number indicating the number of bytes written.
-// Currently, this does a blocking write.
+/// write to stdin
+///
+/// returns -2 on error,
+/// or a non-negative number indicating the number of bytes written.
+/// Currently, this does a blocking write.
long long process_write(Process *process, const char *data, size_t size);
-// read from stdout+stderr
-// returns:
-// -2 on error
-// -1 if no data is available right now
-// 0 on end of file
-// or a positive number indicating the number of bytes read to data (at most size)
-// This does a nonblocking read.
+/// read from stdout+stderr.
+///
+/// returns:\n
+/// -2 on error\n
+/// -1 if no data is available right now\n
+/// 0 on end of file\n
+/// or a positive number indicating the number of bytes read to data (at most size)\n
+/// This does a nonblocking read.
long long process_read(Process *process, char *data, size_t size);
-// like process_read, but reads stderr.
-// this function ALWAYS RETURNS -2 if separate_stderr is not specified in the ProcessSettings.
-// if separate_stderr is false, then both stdout and stderr will be sent via process_read.
+/// like \ref process_read, but reads stderr.
+///
+/// this function ALWAYS RETURNS -2 if `separate_stderr` is not specified in the \ref ProcessSettings.
+/// if `separate_stderr` is false, then both stdout and stderr will be sent via \ref process_read.
long long process_read_stderr(Process *process, char *data, size_t size);
-// Checks if the process has exited. Returns:
-// -1 if the process returned a non-zero exit code, or got a signal.
-// 1 if the process exited successfully
-// 0 if the process hasn't exited.
-// If the process has exited, *info will be filled out with details.
-// if the process is no longer running, *process will be freed and set to NULL.
+/// Checks if the process has exited.
+///
+/// Returns:\n
+/// -1 if the process returned a non-zero exit code, or got a signal.\n
+/// 1 if the process exited successfully\n
+/// 0 if the process hasn't exited.\n
+/// If the process has exited, `*info` will be filled out with details.
+/// if the process is no longer running, `*process` will be freed and set to NULL.
int process_check_status(Process **process, ProcessExitInfo *info);
-// kills process if still running
-// this also frees any resources used by `*process`.
-// *process will be set to NULL.
+/// kills process if still running
+///
+/// this also frees any resources used by `*process`.
+/// `*process` will be set to NULL.
void process_kill(Process **process);
#endif // OS_H_
diff --git a/ted.h b/ted.h
index 74d8f3d..cec54a4 100644
--- a/ted.h
+++ b/ted.h
@@ -1,9 +1,20 @@
-// the main header file for ted.
-// this contains almost all of the function declarations.
+/// \file
+/// the main header file for ted.
+///
+/// this contains almost all of the function declarations.
+
+
+/// \mainpage ted doxygen documentation
+///
+/// See "files" above. You probably want to look at \ref ted.h.
#ifndef TED_H_
#define TED_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "base.h"
#include "util.h"
#include "os.h"
@@ -16,20 +27,27 @@
#include "lib/glcorearb.h"
#include "sdl-inc.h"
+/// Version number
#define TED_VERSION "2.0"
+/// Version string
#define TED_VERSION_FULL "ted v. " TED_VERSION
-#define TED_PATH_MAX 256
-#define TED_CFG "ted.cfg" // config filename
+/// Maximum path size ted handles.
+#define TED_PATH_MAX 1024
+/// Config filename
+#define TED_CFG "ted.cfg"
+/// Minimum text size
#define TEXT_SIZE_MIN 6
+/// Maximum text size
#define TEXT_SIZE_MAX 70
-// max number of LSPs running at once
+/// max number of LSPs running at once
#define TED_LSP_MAX 200
-typedef u8 SyntaxState;
+/// Current state of syntax highlighting.
+typedef u32 SyntaxState;
-// types of syntax highlighting
-ENUM_U8 {
+/// types of syntax highlighting
+enum SyntaxCharType {
SYNTAX_NORMAL,
SYNTAX_KEYWORD,
SYNTAX_BUILTIN,
@@ -38,59 +56,76 @@ ENUM_U8 {
SYNTAX_STRING,
SYNTAX_CHARACTER,
SYNTAX_CONSTANT,
-} ENUM_U8_END(SyntaxCharType);
+};
+/// Type of syntax highlighting.
+typedef u8 SyntaxCharType;
-#define SYNTAX_MATH SYNTAX_STRING // for tex
-#define SYNTAX_CODE SYNTAX_PREPROCESSOR // for markdown
-#define SYNTAX_LINK SYNTAX_CONSTANT // for markdown
+/// for tex
+#define SYNTAX_MATH SYNTAX_STRING
+/// for markdown
+#define SYNTAX_CODE SYNTAX_PREPROCESSOR
+/// for markdown
+#define SYNTAX_LINK SYNTAX_CONSTANT
-// special keycodes for mouse X1 & X2 buttons.
+/// special keycodes for mouse X1 & X2 buttons.
enum {
KEYCODE_X1 = 1<<20,
KEYCODE_X2
};
-// a "key combo" is some subset of {control, shift, alt} + some key.
+/// see \ref KEY_COMBO
#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
+/// see \ref KEY_COMBO
+enum {
+ KEY_MODIFIER_CTRL_BIT,
+ KEY_MODIFIER_SHIFT_BIT,
+ KEY_MODIFIER_ALT_BIT
+};
+/// see \ref KEY_COMBO
#define KEY_MODIFIER_CTRL ((u32)1<<KEY_MODIFIER_CTRL_BIT)
+/// see \ref KEY_COMBO
#define KEY_MODIFIER_SHIFT ((u32)1<<KEY_MODIFIER_SHIFT_BIT)
+/// see \ref KEY_COMBO
#define KEY_MODIFIER_ALT ((u32)1<<KEY_MODIFIER_ALT_BIT)
-// annoyingly SDL sets bit 30 for some keycodes
+/// Create "key combo" from modifier and key.
+///
+/// a "key combo" is some subset of {control, shift, alt} + some key.
#define KEY_COMBO(modifier, key) ((u32)(modifier) \
| ((u32)(key >> 30) << 3)\
- | ((u32)(key) & ~(1u<<30)) << 4)
+ | ((u32)(key) & ~(1u<<30)) << 4) // annoyingly SDL sets bit 30 for some keycodes
-// what happens when we press this key combo
+/// Thing to do when a key combo is pressed.
typedef struct {
u32 key_combo;
Command command;
i64 argument;
} KeyAction;
-// a SettingsContext is a context where a specific set of settings are applied.
-// this corresponds to [PATH//LANGUAGE.(section)] in config files
+/// A SettingsContext is a context where a specific set of settings are applied.
+/// this corresponds to `[PATH//LANGUAGE.(section)]` in config files.
typedef struct {
- Language language; // these settings apply to this language.
- char *path; // these settings apply to all paths which start with this string, or all paths if path=NULL
+ /// The settings apply to this language.
+ Language language;
+ /// The settings apply to all paths which start with this string, or all paths if path=NULL
+ char *path;
} SettingsContext;
-// need to use reference counting for this because of Settings:
-// We copy parent settings to children
-// e.g.
-// [core]
-// bg-texture = "blablabla.png"
-// [Javascript.core]
-// some random shit
-// the main Settings' bg_texture will get copied to javascript's Settings,
-// so we need to be extra careful about when we delete textures.
+/// Need to use reference counting for textures because of Settings:
+/// We copy parent settings to children
+/// e.g.
+/// ```
+/// [core]
+/// bg-texture = "blablabla.png"
+/// [Javascript.core]
+/// some random shit
+/// ```
+/// the main Settings' bg_texture will get copied to javascript's Settings,
+/// so we need to be extra careful about when we delete textures.
typedef struct {
u32 ref_count;
GLuint texture;
} GlRcTexture;
-// reference-counted shader-array-buffer combo.
+/// Reference-counted shader-array-buffer combo.
typedef struct {
u32 ref_count;
GLuint shader;
@@ -99,11 +134,11 @@ typedef struct {
} GlRcSAB;
-// all of ted's settings
+/// All of ted's settings
+///
+/// NOTE: to add more options to ted, add fields here,
+/// and change the settings_<type> global constant near the top of config.c
typedef struct {
- // NOTE: to add more options to ted, add fields here,
- // and change the settings_<type> global constant near the top of config.c
-
SettingsContext context;
u32 colors[COLOR_COUNT];
float cursor_blink_time_on, cursor_blink_time_off;
@@ -143,30 +178,36 @@ typedef struct {
u8 tags_max_depth;
GlRcSAB *bg_shader;
GlRcTexture *bg_texture;
+ /// Comma-separated list of file names which identify the project root
char root_identifiers[4096];
+ /// LSP server command
char lsp[512];
+ /// LSP "configuration" JSON
char lsp_configuration[4096];
+ /// Build command. If non-empty, this overrides running `cargo build` if `Cargo.toml` exists, etc.
char build_command[1024];
+ /// Default build command for if `Cargo.toml`, `Makefile`, etc. do not exist.
char build_default_command[1024];
- // [i] = comma-separated string of file extensions for language i, or NULL for none
+ /// `[i]` = comma-separated string of file extensions for language `i`, or `NULL` for none
char *language_extensions[LANG_COUNT];
- KeyAction *key_actions; // dynamic array, sorted by KEY_COMBO(modifier, key)
+ /// dynamic array, sorted by KEY_COMBO(modifier, key)
+ KeyAction *key_actions;
} Settings;
-// a position in the buffer
+/// 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;
-// a single line in a buffer
+/// A single line in a buffer
typedef struct {
SyntaxState syntax;
u32 len;
char32_t *str;
} Line;
-// sections of ted.cfg
+/// Sections of `ted.cfg`
typedef enum {
SECTION_NONE,
SECTION_CORE,
@@ -175,18 +216,20 @@ typedef enum {
SECTION_EXTENSIONS
} ConfigSection;
-// this structure is used temporarily when loading settings
-// it's needed because we want more specific contexts to be dealt with last.
+/// This structure is used temporarily when loading settings
+/// It's needed because we want more specific contexts to be dealt with last.
typedef struct {
- int index; // index in order of which part was read first.
+ /// index in order of which part was read first.
+ int index;
SettingsContext context;
ConfigSection section;
char *file;
u32 line;
+ /// contents of this config part
char *text;
} ConfigPart;
-// this refers to replacing prev_len characters (found in prev_text) at pos with new_len characters
+/// This refers to replacing prev_len characters (found in prev_text) at pos with new_len characters
typedef struct {
bool chain; // should this + the next edit be treated as one?
BufferPos pos;
@@ -196,132 +239,180 @@ typedef struct {
double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
} BufferEdit;
-// a buffer - this includes line buffers, unnamed buffers, the build buffer, etc.
+/// A buffer - this includes line buffers, unnamed buffers, the build buffer, etc.
typedef struct {
- char *path; // NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers)
- 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
- double last_write_time; // last write time to `path`.
- i16 manual_language; // 1 + the language the buffer has been manually set to, or 0 if it hasn't been manually set to anything
+ /// NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers)
+ char *path;
+ /// we keep a back-pointer to the ted instance so we don't have to pass it in to every buffer function
+ struct Ted *ted;
+ /// number of characters scrolled in the x/y direction
+ double scroll_x, scroll_y;
+ /// last write time to `path`
+ double last_write_time;
+ /// 1 + the language the buffer has been manually set to, or 0 if it hasn't been manually set to anything
+ i16 manual_language;
+ /// position of cursor
BufferPos cursor_pos;
- BufferPos selection_pos; // if selection is true, the text between selection_pos and cursor_pos is selected.
- bool is_line_buffer; // "line buffers" are buffers which can only have one line of text (used for inputs)
- bool selection; // is anything selected?
- bool store_undo_events; // set to false to disable undo events
- // This is set to true whenever a change is made to the buffer, and never set to false by buffer_ functions.
- // (Distinct from buffer_unsaved_changes)
+ /// if `selection` is true, the text between `selection_pos` and `cursor_pos` is selected.
+ BufferPos selection_pos;
+ /// "line buffers" are buffers which can only have one line of text (used for inputs)
+ bool is_line_buffer;
+ /// is anything selected?
+ bool selection;
+ /// set to false to disable undo events
+ bool store_undo_events;
+ /// This is set to true whenever a change is made to the buffer, and never set to false by buffer_ functions.
+ /// (Distinct from \ref buffer_unsaved_changes)
bool modified;
+ /// will the next undo event be chained with the ones after?
bool will_chain_edits;
- bool chaining_edits; // are we chaining undo events together?
+ /// will the next undo event be chained with the previous one?
+ bool chaining_edits;
+ /// view-only mode
bool view_only;
- bool line_buffer_submitted; // (line buffers only) set to true when submitted. you have to reset it to false.
- // If set to true, buffer will be scrolled to the cursor position next frame.
- // This is to fix the problem that x1,y1,x2,y2 are not updated until the buffer is rendered.
+ /// (line buffers only) set to true when submitted. you have to reset it to false.
+ bool line_buffer_submitted;
+ /// If set to true, buffer will be scrolled to the cursor position next frame.
+ /// This is to fix the problem that x1,y1,x2,y2 are not updated until the buffer is rendered.
bool center_cursor_next_frame;
- float x1, y1, x2, y2; // buffer's rectangle on screen
+ /// buffer's rectangle on screen
+ float x1, y1, x2, y2;
+ /// number of lines in buffer
u32 nlines;
+ /// capacity of `lines`
u32 lines_capacity;
- // which LSP this document is open in
+ /// which LSP this document is open in
LSPID lsp_opened_in;
- u32 undo_history_write_pos; // where in the undo history was the last write? used by buffer_unsaved_changes
- u32 first_line_on_screen, last_line_on_screen; // which lines are on screen? updated when buffer_render is called.
+ /// where in the undo history was the last write? used by \ref buffer_unsaved_changes
+ u32 undo_history_write_pos;
+ /// which lines are on screen? updated when \ref buffer_render is called.
+ u32 first_line_on_screen, last_line_on_screen;
// to cache syntax highlighting properly, it is important to keep track of the
// first and last line modified since last frame.
u32 frame_earliest_line_modified;
+ /// see \ref frame_earliest_line_modified.
u32 frame_latest_line_modified;
+ /// lines
Line *lines;
+ /// last error
char error[256];
- BufferEdit *undo_history; // dynamic array of undo history
- BufferEdit *redo_history; // dynamic array of redo history
+ /// dynamic array of undo history
+ BufferEdit *undo_history;
+ /// dynamic array of redo history
+ BufferEdit *redo_history;
} TextBuffer;
typedef enum {
+ /// No menu is open
MENU_NONE,
+ /// "Open file"
MENU_OPEN,
+ /// "Save file as"
MENU_SAVE_AS,
- MENU_WARN_UNSAVED, // warn about unsaved changes
- MENU_ASK_RELOAD, // prompt about whether to reload file which has ben changed by another program
+ /// "X has unsaved changes"
+ MENU_WARN_UNSAVED,
+ /// "X has been changed by another program"
+ MENU_ASK_RELOAD,
+ /// "Go to definition of..."
MENU_GOTO_DEFINITION,
+ /// "Go to line"
MENU_GOTO_LINE,
+ /// "Command palette"
MENU_COMMAND_SELECTOR,
- MENU_SHELL, // run a shell command
+ /// "Run a shell command"
+ MENU_SHELL,
} Menu;
-
-// an entry in a selector menu (e.g. the "open" menu)
+/// an entry in a selector menu (e.g. the "open" menu)
typedef struct {
+ /// label
const char *name;
- // if not NULL, this will show on the right side of the entry.
+ /// if not NULL, this will show on the right side of the entry.
const char *detail;
+ /// color to draw text in
u32 color;
- // use this for whatever you want
+ /// use this for whatever you want
u64 userdata;
} SelectorEntry;
-// a selector menu (e.g. the "open" menu)
+/// a selector menu (e.g. the "open" menu)
typedef struct {
SelectorEntry *entries;
u32 n_entries;
Rect bounds;
- u32 cursor; // index where the selector thing is
+ /// index where the selector thing is
+ u32 cursor;
float scroll;
- // whether or not we should let the user select entries using a cursor.
+ /// whether or not we should let the user select entries using a cursor.
bool enable_cursor;
} Selector;
-// file entries for file selectors
+/// file entries for file selectors
typedef struct {
- char *name; // just the file name
- char *path; // full path
+ /// just the file name
+ char *name;
+ /// full path
+ char *path;
FsType type;
} FileEntry;
-// a selector menu for files (e.g. the "open" menu)
+/// a selector menu for files (e.g. the "open" menu)
typedef struct {
Selector sel;
Rect bounds;
u32 n_entries;
FileEntry *entries;
char cwd[TED_PATH_MAX];
- bool create_menu; // this is for creating files, not opening files
+ /// indicates that this is for creating files, not opening files
+ bool create_menu;
} FileSelector;
-// options for a pop-up menu
+/// options for a pop-up menu
typedef enum {
POPUP_NONE,
+ /// "Yes" button
POPUP_YES = 1<<1,
+ /// "No" button
POPUP_NO = 1<<2,
+ /// "Cancel" button
POPUP_CANCEL = 1<<3,
} PopupOption;
-// pop-up with "yes" and "no" buttons
+/// pop-up with "yes" and "no" buttons
#define POPUP_YES_NO (POPUP_YES | POPUP_NO)
-// pop-up with "yes", "no", and "cancel" buttons
+/// pop-up with "yes", "no", and "cancel" buttons
#define POPUP_YES_NO_CANCEL (POPUP_YES | POPUP_NO | POPUP_CANCEL)
-// a node is a collection of tabs OR a split of two nodes
+/// A node is a collection of tabs OR a split of two nodes
typedef struct {
- u16 *tabs; // dynamic array of indices into ted->buffers, or NULL if this is a split
- float split_pos; // number from 0 to 1 indicating where the split is.
- u16 active_tab; // index of active tab in tabs.
- bool split_vertical; // is the split vertical? if false, this split looks like a|b
- u16 split_a; // split left/upper half; index into ted->nodes
- u16 split_b; // split right/lower half
+ /// dynamic array of indices into ted->buffers, or `NULL` if this is a split
+ u16 *tabs;
+ /// number from 0 to 1 indicating where the split is.
+ float split_pos;
+ /// index of active tab in `tabs`.
+ u16 active_tab;
+ /// is the split vertical? if false, this split looks like a|b
+ bool split_vertical;
+ /// split left/upper half; index into `ted->nodes`
+ u16 split_a;
+ /// split right/lower half
+ u16 split_b;
} Node;
-// max number of buffers open at one time
+/// max number of buffers open at one time
#define TED_MAX_BUFFERS 256
-// max number of nodes open at one time
+/// max number of nodes open at one time
#define TED_MAX_NODES 256
-// max tabs per node
+/// max tabs per node
#define TED_MAX_TABS 100
-// max strings in all config files
+/// max strings in all config files
#define TED_MAX_STRINGS 1000
+/// "find" menu result
typedef struct {
BufferPos start;
BufferPos end;
@@ -330,10 +421,11 @@ typedef struct {
typedef struct {
char *path;
BufferPos pos;
- u32 build_output_line; // which line in the build output corresponds to this error
+ /// which line in the build output corresponds to this error
+ u32 build_output_line;
} BuildError;
-// LSPSymbolKinds are translated to these. this is a much coarser categorization
+/// `LSPSymbolKind`s are translated to these. this is a much coarser categorization
typedef enum {
SYMBOL_OTHER,
SYMBOL_FUNCTION,
@@ -344,109 +436,121 @@ typedef enum {
SYMBOL_KEYWORD
} SymbolKind;
-// a single autocompletion suggestion
+/// a single autocompletion suggestion
typedef struct {
char *label;
char *filter;
char *text;
- char *detail; // this can be NULL!
- char *documentation; // this can be NULL!
+ /// this can be NULL!
+ char *detail;
+ /// this can be NULL!
+ char *documentation;
bool deprecated;
SymbolKind kind;
} Autocompletion;
enum {
- // autocomplete/signature help was manually triggered
+ /// autocomplete/signature help was manually triggered
TRIGGER_INVOKED = 0x12000,
- // autocomplete list needs to be updated because more characters were typed
+ /// autocomplete list needs to be updated because more characters were typed
TRIGGER_INCOMPLETE = 0x12001,
- // signtaure help needs to be updated because the cursor was moved or
- // the buffer's contents changed.
+ /// signtaure help needs to be updated because the cursor was moved or
+ /// the buffer's contents changed.
TRIGGER_CONTENT_CHANGE = 0x12002,
};
-// data needed for autocompletion
+/// data needed for autocompletion
typedef struct {
- bool open; // is the autocomplete window open?
- bool is_list_complete; // should the completions array be updated when more characters are typed?
+ /// is the autocomplete window open?
+ bool open;
+ /// should the completions array be updated when more characters are typed?
+ bool is_list_complete;
- // what trigger caused the last request for completions:
- // either a character code (for trigger characters),
- // or one of the TRIGGER_* constants above
+ /// what trigger caused the last request for completions:
+ /// either a character code (for trigger characters),
+ /// or one of the `TRIGGER_*` constants above
uint32_t trigger;
LSPServerRequestID last_request;
- // when we sent the request to the LSP for completions
- // (this is used to figure out when we should display "Loading...")
+ /// when we sent the request to the LSP for completions
+ /// (this is used to figure out when we should display "Loading...")
double last_request_time;
- Autocompletion *completions; // dynamic array of all completions
- u32 *suggested; // dynamic array of completions to be suggested (indices into completions)
- BufferPos last_pos; // position of cursor last time completions were generated. if this changes, we need to recompute completions.
- i32 cursor; // which completion is currently selected (index into suggested)
+ /// dynamic array of all completions
+ Autocompletion *completions;
+ /// dynamic array of completions to be suggested (indices into completions)
+ u32 *suggested;
+ /// position of cursor last time completions were generated. if this changes, we need to recompute completions.
+ BufferPos last_pos;
+ /// which completion is currently selected (index into suggested)
+ i32 cursor;
i32 scroll;
- // was the last request for phantom completion?
+ /// was the last request for phantom completion?
bool last_request_phantom;
- // current phantom completion to be displayed
+ /// current phantom completion to be displayed
char *phantom;
-
- Rect rect; // rectangle where the autocomplete menu is (needed to avoid interpreting autocomplete clicks as other clicks)
+ /// rectangle where the autocomplete menu is (needed to avoid interpreting autocomplete clicks as other clicks)
+ Rect rect;
} Autocomplete;
-// data needed for finding usages
+/// data needed for finding usages
typedef struct {
LSPServerRequestID last_request;
double last_request_time;
} Usages;
-// a single signature in the signature help.
+/// a single signature in the signature help.
typedef struct {
- // displayed normal
+ /// displayed normal
char *label_pre;
- // displayed bold
+ /// displayed bold
char *label_active;
- // displayed normal
+ /// displayed normal
char *label_post;
} Signature;
-// max # of signatures to display at a time.
+/// max number of signatures to display at a time.
#define SIGNATURE_HELP_MAX 5
-// "signature help" (LSP) is thing that shows the current parameter, etc.
+/// "signature help" (LSP) is thing that shows the current parameter, etc.
typedef struct {
LSPServerRequestID last_request;
- // should we resend a signature help request this frame?
+ /// should we resend a signature help request this frame?
bool retrigger;
- // if signature_count = 0, signature help is closed
+ /// if signature_count = 0, signature help is closed
u16 signature_count;
Signature signatures[SIGNATURE_HELP_MAX];
} SignatureHelp;
-// "hover" information from LSP server
+/// "hover" information from LSP server
typedef struct {
LSPServerRequestID last_request;
- // is some hover info being displayed?
+ /// is some hover info being displayed?
bool open;
- // text to display
+ /// text to display
char *text;
- // where the hover data is coming from.
- // we use this to check if we need to refresh it.
+ /// where the hover data is coming from.
+ /// we use this to check if we need to refresh it.
LSPDocumentPosition requested_position;
+ /// range in document to highlight
LSPRange range;
- double time; // how long the cursor has been hovering for
+ /// how long the cursor has been hovering for
+ double time;
} Hover;
-// symbol information for the definitions menu
+/// symbol information for the definitions menu
typedef struct {
char *name;
char *detail;
u32 color;
+ /// is this from a LSP server (as opposed to ctags)?
bool from_lsp;
- LSPDocumentPosition position; // only set if from_lsp = true
+ /// only set if `from_lsp = true`
+ LSPDocumentPosition position;
} SymbolInfo;
-// determines which thing associated with a symbol to go to
+/// determines which thing associated with a symbol to go to
typedef enum {
GOTO_DECLARATION,
GOTO_DEFINITION,
@@ -455,82 +559,108 @@ typedef enum {
} GotoType;
typedef struct {
- // information about last LSP request sent
LSPServerRequestID last_request;
- double last_request_time;
-
- char *last_request_query; // last query string which we sent a request for
- Selector selector; // for "go to definition of..." menu
- SymbolInfo *all_definitions; // an array of all definitions (gotten from workspace/symbols) for "go to definition" menu
+ double last_request_time;
+ /// last query string which we sent a request for
+ char *last_request_query;
+ /// for "go to definition of..." menu
+ Selector selector;
+ /// an array of all definitions (gotten from workspace/symbols) for "go to definition" menu
+ SymbolInfo *all_definitions;
} Definitions;
-// "highlight" information from LSP server
+/// "highlight" information from LSP server
typedef struct {
- LSPHighlight *highlights;
LSPServerRequestID last_request;
LSPDocumentPosition requested_position;
+ LSPHighlight *highlights;
} Highlights;
-// more severe message types should have higher numbers.
-// they will override less severe messages.
+/// more severe message types should have higher numbers.
+/// they will override less severe messages.
typedef enum {
MESSAGE_INFO,
MESSAGE_WARNING,
MESSAGE_ERROR
} MessageType;
-// (almost) all data used by the ted application
+/// (almost) all data used by the ted application
typedef struct Ted {
+ /// all running LSP servers
LSP *lsps[TED_LSP_MAX + 1];
- // current time (see time_get_seconds), as of the start of this frame
+ /// current time (see time_get_seconds), as of the start of this frame
double frame_time;
SDL_Window *window;
Font *font_bold;
Font *font;
TextBuffer *active_buffer;
- // buffer we are currently drag-to-selecting in, if any
+ /// buffer we are currently drag-to-selecting in, if any
TextBuffer *drag_buffer;
- // while a menu or something is open, there is no active buffer. when the menu is closed,
- // the old active buffer needs to be restored. that's what this stores.
+ /// while a menu or something is open, there is no active buffer. when the menu is closed,
+ /// the old active buffer needs to be restored. that's what this stores.
TextBuffer *prev_active_buffer;
Node *active_node;
- Settings *all_settings; // dynamic array of Settings. use Settings.context to figure out which one to use.
- Settings *default_settings; // settings to use when no buffer is open
+ /// dynamic array of Settings. use Settings.context to figure out which one to use.
+ Settings *all_settings;
+ /// settings to use when no buffer is open
+ Settings *default_settings;
float window_width, window_height;
- u32 key_modifier; // which of shift, alt, ctrl are down right now.
+ /// which of shift, alt, ctrl are down right now.
+ u32 key_modifier;
vec2 mouse_pos;
u32 mouse_state;
- u8 nmouse_clicks[4]; // nmouse_clicks[i] = length of mouse_clicks[i]
- vec2 mouse_clicks[4][32]; // mouse_clicks[SDL_BUTTON_RIGHT], for example, is all the right mouse-clicks that have happened this frame
- // number of times mouse was clicked at each position
+ /// `nmouse_clicks[i]` = length of `mouse_clicks[i]`
+ u8 nmouse_clicks[4];
+ /// `mouse_clicks[SDL_BUTTON_RIGHT]`, for example, is all the right mouse-clicks that have happened this frame
+ vec2 mouse_clicks[4][32];
+ /// number of times mouse was clicked at each position
u8 mouse_click_times[4][32];
u8 nmouse_releases[4];
vec2 mouse_releases[4][32];
- int scroll_total_x, scroll_total_y; // total amount scrolled in the x and y direction this frame
- Menu menu; // currently open menu, or MENU_NONE if no menu is open.
+ /// total amount scrolled this frame
+ int scroll_total_x, scroll_total_y;
+ /// currently open menu, or \ref MENU_NONE if no menu is open.
+ Menu menu;
FileSelector file_selector;
Selector command_selector;
- TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus
- TextBuffer find_buffer; // use for "find" term in find/find+replace
- TextBuffer replace_buffer; // "replace" for find+replace
- TextBuffer build_buffer; // buffer for build output (view only)
- TextBuffer argument_buffer; // used for command selector
- double cursor_error_time; // time which the cursor error animation started (cursor turns red, e.g. when there's no autocomplete suggestion)
- bool search_start_cwd; // should start_cwd be searched for files? set to true if the executable isn't "installed"
+ /// general-purpose line buffer for inputs -- used for menus
+ TextBuffer line_buffer;
+ /// use for "find" term in find/find+replace
+ TextBuffer find_buffer;
+ /// "replace" for find+replace
+ TextBuffer replace_buffer;
+ /// buffer for build output (view only)
+ TextBuffer build_buffer;
+ /// used for command selector
+ TextBuffer argument_buffer;
+ /// time which the cursor error animation started (cursor turns red, e.g. when there's no autocomplete suggestion)
+ double cursor_error_time;
+ /// should start_cwd be searched for files? set to true if the executable isn't "installed"
+ bool search_start_cwd;
+ /// CWD `ted` was started in
char start_cwd[TED_PATH_MAX];
- bool quit; // if set to true, the window will close next frame. NOTE: this doesn't check for unsaved changes!!
- bool find; // is the find or find+replace menu open?
- bool replace; // is the find+replace menu open?
- bool find_regex, find_case_sensitive; // find options
- u32 find_flags; // flags used last time search term was compiled
+ /// if set to true, the window will close next frame. NOTE: this doesn't check for unsaved changes!!
+ bool quit;
+ /// is the find or find+replace menu open?
+ bool find;
+ /// is the find+replace menu open?
+ bool replace;
+ /// find options
+ bool find_regex, find_case_sensitive;
+ /// flags used last time search term was compiled
+ u32 find_flags;
struct pcre2_real_code_32 *find_code;
struct pcre2_real_match_data_32 *find_match_data;
FindResult *find_results;
- bool find_invalid_pattern; // invalid regex?
- Command warn_unsaved; // if non-zero, the user is trying to execute this command, but there are unsaved changes
- bool build_shown; // are we showing the build output?
- bool building; // is the build process running?
+ /// invalid regex?
+ bool find_invalid_pattern;
+ /// if non-zero, the user is trying to execute this command, but there are unsaved changes
+ Command warn_unsaved;
+ /// are we showing the build output?
+ bool build_shown;
+ /// is the build process running?
+ bool building;
Autocomplete autocomplete;
SignatureHelp signature_help;
Hover hover;
@@ -540,421 +670,444 @@ typedef struct Ted {
FILE *log;
- BuildError *build_errors; // dynamic array of build errors
- u32 build_error; // build error we are currently "on"
+ /// dynamic array of build errors
+ BuildError *build_errors;
+ /// build error we are currently "on"
+ u32 build_error;
- // used by menus to keep track of the scroll position so we can return to it.
+ /// used by menus to keep track of the scroll position so we can return to it.
vec2d prev_active_buffer_scroll;
SDL_Cursor *cursor_arrow, *cursor_ibeam, *cursor_wait,
*cursor_resize_h, *cursor_resize_v, *cursor_hand, *cursor_move;
- // which cursor to use this frame
- // this should be set to one of the cursor_* members above, or NULL for no cursor
+ /// which cursor to use this frame
+ /// this should be set to one of the cursor_* members above, or NULL for no cursor
SDL_Cursor *cursor;
- // node containing tab user is dragging around, NULL if user is not dragging a tab
+ /// node containing tab user is dragging around, NULL if user is not dragging a tab
Node *dragging_tab_node;
- // index in dragging_tab_node->tabs
+ /// index in dragging_tab_node->tabs
u16 dragging_tab_idx;
- vec2 dragging_tab_origin; // where the tab is being dragged from (i.e. mouse pos at start of drag action)
+ /// where the tab is being dragged from (i.e. mouse pos at start of drag action)
+ vec2 dragging_tab_origin;
- // if not NULL, points to the node whose split the user is currently resizing.
+ /// if not `NULL`, points to the node whose split the user is currently resizing.
Node *resizing_split;
- char **shell_history; // dynamic array of history of commands run with :shell (UTF-8)
- u32 shell_history_pos; // for keeping track of where we are in the shell history.
+ /// dynamic array of history of commands run with :shell (UTF-8)
+ char **shell_history;
+ /// for keeping track of where we are in the shell history.
+ u32 shell_history_pos;
// points to a selector if any is open, otherwise NULL.
Selector *selector_open;
- float build_output_height; // what % of the screen the build output takes up
+ /// what % of the screen the build output takes up
+ float build_output_height;
bool resizing_build_output;
- double last_save_time; // last time a save command was executed. used for bg-shaders.
+ /// last time a save command was executed. used for bg-shaders.
+ double last_save_time;
Process *build_process;
- // When we read the stdout from the build process, the tail end of the read could be an
- // incomplete UTF-8 code point. This is where we store that "tail end" until more
- // data is available. (This is up to 3 bytes, null terminated)
+ /// When we read the stdout from the build process, the tail end of the read could be an
+ /// incomplete UTF-8 code point. This is where we store that "tail end" until more
+ /// data is available. (This is up to 3 bytes, null terminated)
char build_incomplete_codepoint[4];
- char **build_queue; // allows execution of multiple commands -- needed for tags generation
- char warn_unsaved_names[TED_PATH_MAX]; // comma-separated list of files with unsaved changes (only applicable if warn_unsaved != 0)
- char warn_overwrite[TED_PATH_MAX]; // file name user is trying to overwrite
- char ask_reload[TED_PATH_MAX]; // file name which we want to reload
+ /// allows execution of multiple commands -- needed for tags generation
+ char **build_queue;
+ /// comma-separated list of files with unsaved changes (only applicable if warn_unsaved != 0)
+ char warn_unsaved_names[TED_PATH_MAX];
+ /// file name user is trying to overwrite
+ char warn_overwrite[TED_PATH_MAX];
+ /// file name which we want to reload
+ char ask_reload[TED_PATH_MAX];
char local_data_dir[TED_PATH_MAX];
char global_data_dir[TED_PATH_MAX];
+ /// home directory
char home[TED_PATH_MAX];
- char cwd[TED_PATH_MAX]; // current working directory
- char build_dir[TED_PATH_MAX]; // directory where we run the build command
- char tags_dir[TED_PATH_MAX]; // where we are reading tags from
+ /// current working directory
+ char cwd[TED_PATH_MAX];
+ /// directory where we run the build command
+ char build_dir[TED_PATH_MAX];
+ /// where we are reading tags from
+ char tags_dir[TED_PATH_MAX];
bool nodes_used[TED_MAX_NODES];
- // nodes[0] is always the "root node", if any buffers are open.
+ /// `nodes[0]` is always the "root node", if any buffers are open.
Node nodes[TED_MAX_NODES];
- // NOTE: the buffer at index 0 is reserved as a "null buffer" and should not be used.
+ /// NOTE: the buffer at index 0 is reserved as a "null buffer" and should not be used.
bool buffers_used[TED_MAX_BUFFERS];
TextBuffer buffers[TED_MAX_BUFFERS];
- // config file strings
+ /// number of config file strings
u32 nstrings;
+ /// config file strings
char *strings[TED_MAX_STRINGS];
char window_title[256];
- // little box used to display errors and info.
- double message_time; // time message box was opened
- MessageType message_type;
+ /// little box used to display errors and info.
char message[512];
+ /// time message box was opened
+ double message_time;
+ MessageType message_type;
MessageType message_shown_type;
char message_shown[512];
} Ted;
// === buffer.c ===
+/// Does this buffer have an error?
bool buffer_has_error(TextBuffer *buffer);
+/// get buffer error
const char *buffer_get_error(TextBuffer *buffer);
+/// clear buffer error
void buffer_clear_error(TextBuffer *buffer);
-// clear undo and redo history
+/// clear undo and redo history
void buffer_clear_undo_redo(TextBuffer *buffer);
-// is this buffer empty?
+/// is this buffer empty?
bool buffer_empty(TextBuffer *buffer);
-// returns the buffer's filename (not full path), or "Untitled" if this buffer is untitled.
+/// returns the buffer's filename (not full path), or "Untitled" if this buffer is untitled.
const char *buffer_display_filename(TextBuffer *buffer);
-// does this buffer contained a named file (i.e. not a line buffer, not the build buffer, not untitled)
+/// does this buffer contained a named file (i.e. not a line buffer, not the build buffer, not untitled)
bool buffer_is_named_file(TextBuffer *buffer);
-// create a new empty buffer with no file name
+/// create a new empty buffer with no file name
void buffer_create(TextBuffer *buffer, Ted *ted);
-// create a new empty line buffer
+/// create a new empty line buffer
void line_buffer_create(TextBuffer *buffer, Ted *ted);
-// does this buffer have unsaved changes?
+/// does this buffer have unsaved changes?
bool buffer_unsaved_changes(TextBuffer *buffer);
-// returns the character at position pos, or 0 if pos is invalid
+/// returns the character at position pos, or 0 if pos is invalid
char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos pos);
-// returns the character before position pos, or 0 if pos is invalid or at the start of a line
+/// returns the character before position pos, or 0 if pos is invalid or at the start of a line
char32_t buffer_char_before_pos(TextBuffer *buffer, BufferPos pos);
-// returns the character after position pos, or 0 if pos is invalid or at the end of a line
+/// returns the character after position pos, or 0 if pos is invalid or at the end of a line
char32_t buffer_char_after_pos(TextBuffer *buffer, BufferPos pos);
-// returns the character to the left of the cursor, or 0 if the cursor at the start of the line.
+/// returns the character to the left of the cursor, or 0 if the cursor at the start of the line.
char32_t buffer_char_before_cursor(TextBuffer *buffer);
-// returns the character to the right of the cursor, 0 if cursor is at end of line
+/// returns the character to the right of the cursor, 0 if cursor is at end of line
char32_t buffer_char_after_cursor(TextBuffer *buffer);
-// buffer position of start of file
+/// buffer position of start of file
BufferPos buffer_pos_start_of_file(TextBuffer *buffer);
-// buffer position of end of file
+/// buffer position of end of file
BufferPos buffer_pos_end_of_file(TextBuffer *buffer);
-// ensures that `p` refers to a valid position, moving it if needed.
+/// ensures that `p` refers to a valid position, moving it if needed.
void buffer_pos_validate(TextBuffer *buffer, BufferPos *p);
-// is this a valid buffer position?
+/// is this a valid buffer position?
bool buffer_pos_valid(TextBuffer *buffer, BufferPos p);
Language buffer_language(TextBuffer *buffer);
-// clip the rectangle so it's all inside the buffer. returns true if there's any rectangle left.
+/// clip the rectangle so it's all inside the buffer. returns true if there's any rectangle left.
bool buffer_clip_rect(TextBuffer *buffer, Rect *r);
-// get LSP server which deals with this buffer
+/// get LSP server which deals with this buffer
LSP *buffer_lsp(TextBuffer *buffer);
-// Get the settings used for this buffer.
+/// Get the settings used for this buffer.
Settings *buffer_settings(TextBuffer *buffer);
-// Get tab width for this buffer
+/// Get tab width for this buffer
u8 buffer_tab_width(TextBuffer *buffer);
-// Get whether or not to indent with spaces for this buffer.
+/// Get whether or not to indent with spaces for this buffer.
bool buffer_indent_with_spaces(TextBuffer *buffer);
-// NOTE: this string will be invalidated when the line is edited!!!
-// only use it briefly!!
+/// NOTE: this string will be invalidated when the line is edited!!!
+/// only use it briefly!!
String32 buffer_get_line(TextBuffer *buffer, u32 line_number);
-// get at most `nchars` characters starting from position `pos`.
-// returns the number of characters actually available.
-// you can pass NULL for text if you just want to know how many
-// characters *could* be accessed before the end of the file.
+/// get at most `nchars` characters starting from position `pos`.
+/// returns the number of characters actually available.
+/// you can pass NULL for text if you just want to know how many
+/// characters *could* be accessed before the end of the file.
size_t buffer_get_text_at_pos(TextBuffer *buffer, BufferPos pos, char32_t *text, size_t nchars);
-// returns a UTF-32 string of at most `nchars` code points from `buffer` starting at `pos`
-// the string should be passed to str32_free.
+/// returns a UTF-32 string of at most `nchars` code points from `buffer` starting at `pos`
+/// the string should be passed to str32_free.
String32 buffer_get_str32_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars);
-// get UTF-8 string at position, up to `nchars` code points (NOT bytes).
-// the resulting string should be freed.
+/// get UTF-8 string at position, up to `nchars` code points (NOT bytes).
+/// the resulting string should be freed.
char *buffer_get_utf8_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars);
-// Puts a UTF-8 string containing the contents of the buffer into out.
-// Returns the number of bytes, including a null terminator.
-// To use this function, first pass NULL for out to get the number of bytes you need to allocate.
+/// Puts a UTF-8 string containing the contents of the buffer into out.
+/// Returns the number of bytes, including a null terminator.
+/// To use this function, first pass NULL for out to get the number of bytes you need to allocate.
size_t buffer_contents_utf8(TextBuffer *buffer, char *out);
-// Returns a UTF-8 string containing the contents of `buffer`.
-// The return value should be freed..
+/// Returns a UTF-8 string containing the contents of `buffer`.
+/// The return value should be freed..
char *buffer_contents_utf8_alloc(TextBuffer *buffer);
-// perform a series of checks to make sure the buffer doesn't have any invalid values
+/// perform a series of checks to make sure the buffer doesn't have any invalid values
void buffer_check_valid(TextBuffer *buffer);
-// free all resources used by the buffer
+/// free all resources used by the buffer
void buffer_free(TextBuffer *buffer);
-// clear buffer contents
+/// clear buffer contents
void buffer_clear(TextBuffer *buffer);
-// returns the length of the `line_number`th line (0-indexed),
-// or 0 if `line_number` is out of range.
+/// returns the length of the `line_number`th line (0-indexed),
+/// or 0 if `line_number` is out of range.
u32 buffer_line_len(TextBuffer *buffer, u32 line_number);
-// returns the number of lines of text in the buffer into *lines (if not NULL),
-// and the number of columns of text, i.e. the number of columns in the longest line displayed, into *cols (if not NULL)
+/// returns the number of lines of text in the buffer into *lines (if not NULL),
+/// and the number of columns of text, i.e. the number of columns in the longest line displayed, into *cols (if not NULL)
void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns);
-// returns the number of rows of text that can fit in the buffer
+/// returns the number of rows of text that can fit in the buffer
float buffer_display_lines(TextBuffer *buffer);
-// returns the number of columns of text that can fit in the buffer
+/// returns the number of columns of text that can fit in the buffer
float buffer_display_cols(TextBuffer *buffer);
void buffer_scroll(TextBuffer *buffer, double dx, double dy);
-// returns the screen position of the character at the given position in the buffer.
+/// returns the screen position of the character at the given position in the buffer.
vec2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos);
-// convert pixel coordinates to a position in the buffer, selecting the closest character.
-// returns false if the position is not inside the buffer, but still sets *pos to the closest character.
+/// convert pixel coordinates to a position in the buffer, selecting the closest character.
+/// returns false if the position is not inside the buffer, but still sets *pos to the closest character.
bool buffer_pixels_to_pos(TextBuffer *buffer, vec2 pixel_coords, BufferPos *pos);
-// scroll to `pos`, scrolling as little as possible while maintaining scrolloff.
+/// scroll to `pos`, scrolling as little as possible while maintaining scrolloff.
void buffer_scroll_to_pos(TextBuffer *buffer, BufferPos pos);
-// scroll in such a way that this position is in the center of the screen
+/// scroll in such a way that this position is in the center of the screen
void buffer_scroll_center_pos(TextBuffer *buffer, BufferPos pos);
void buffer_scroll_to_cursor(TextBuffer *buffer);
-// scroll so that the cursor is in the center of the buffer's rectangle.
+/// scroll so that the cursor is in the center of the buffer's rectangle.
void buffer_center_cursor(TextBuffer *buffer);
-// returns the number of characters successfully moved by.
+/// returns the number of characters successfully moved by.
i64 buffer_pos_move_left(TextBuffer *buffer, BufferPos *pos, i64 by);
-// returns the number of characters successfully moved by.
+/// returns the number of characters successfully moved by.
i64 buffer_pos_move_right(TextBuffer *buffer, BufferPos *pos, i64 by);
-// returns the number of lines successfully moved by.
+/// returns the number of lines successfully moved by.
i64 buffer_pos_move_up(TextBuffer *buffer, BufferPos *pos, i64 by);
-// returns the number of lines successfully moved by.
+/// returns the number of lines successfully moved by.
i64 buffer_pos_move_down(TextBuffer *buffer, BufferPos *pos, i64 by);
void buffer_cursor_move_to_pos(TextBuffer *buffer, BufferPos pos);
-// returns the number of characters successfully moved by.
+/// returns the number of characters successfully moved by.
i64 buffer_cursor_move_left(TextBuffer *buffer, i64 by);
-// returns the number of characters successfully moved by.
+/// returns the number of characters successfully moved by.
i64 buffer_cursor_move_right(TextBuffer *buffer, i64 by);
-// returns the number of lines successfully moved by.
+/// returns the number of lines successfully moved by.
i64 buffer_cursor_move_up(TextBuffer *buffer, i64 by);
-// returns the number of lines successfully moved by.
+/// returns the number of lines successfully moved by.
i64 buffer_cursor_move_down(TextBuffer *buffer, i64 by);
-// returns the number of blank lines successfully moved by.
+/// returns the number of blank lines successfully moved by.
i64 buffer_pos_move_up_blank_lines(TextBuffer *buffer, BufferPos *pos, i64 by);
-// returns the number of blank lines successfully moved by.
+/// returns the number of blank lines successfully moved by.
i64 buffer_pos_move_down_blank_lines(TextBuffer *buffer, BufferPos *pos, i64 by);
-// returns the number of blank lines successfully moved by.
+/// returns the number of blank lines successfully moved by.
i64 buffer_cursor_move_up_blank_lines(TextBuffer *buffer, i64 by);
-// returns the number of blank lines successfully moved by.
+/// returns the number of blank lines successfully moved by.
i64 buffer_cursor_move_down_blank_lines(TextBuffer *buffer, i64 by);
-// returns the number of words successfully moved by.
+/// returns the number of words successfully moved by.
i64 buffer_pos_move_words(TextBuffer *buffer, BufferPos *pos, i64 nwords);
-// returns the number of words successfully moved by.
+/// returns the number of words successfully moved by.
i64 buffer_pos_move_left_words(TextBuffer *buffer, BufferPos *pos, i64 nwords);
-// returns the number of words successfully moved by.
+/// returns the number of words successfully moved by.
i64 buffer_pos_move_right_words(TextBuffer *buffer, BufferPos *pos, i64 nwords);
-// returns the number of words successfully moved by.
+/// returns the number of words successfully moved by.
i64 buffer_cursor_move_left_words(TextBuffer *buffer, i64 nwords);
-// returns the number of words successfully moved by.
+/// returns the number of words successfully moved by.
i64 buffer_cursor_move_right_words(TextBuffer *buffer, i64 nwords);
-// Returns a string of word characters (see is32_word) around the position,
-// or an empty string if neither of the characters to the left and right of the cursor are word characters.
-// NOTE: The string is invalidated when the buffer is changed!!!
-// The return value should NOT be freed.
+/// Returns a string of word characters (see is32_word) around the position,
+/// or an empty string if neither of the characters to the left and right of the cursor are word characters.
+/// NOTE: The string is invalidated when the buffer is changed!!!
+/// The return value should NOT be freed.
String32 buffer_word_at_pos(TextBuffer *buffer, BufferPos pos);
-// Get the word at the cursor.
-// NOTE: The string is invalidated when the buffer is changed!!!
-// The return value should NOT be freed.
+/// Get the word at the cursor.
+/// NOTE: The string is invalidated when the buffer is changed!!!
+/// The return value should NOT be freed.
String32 buffer_word_at_cursor(TextBuffer *buffer);
-// Get a UTF-8 string consisting of the word at the cursor.
-// The return value should be freed.
+/// Get a UTF-8 string consisting of the word at the cursor.
+/// The return value should be freed.
char *buffer_word_at_cursor_utf8(TextBuffer *buffer);
-// Buffer position corresponding to the start of line `line` (0-indexed).
+/// Buffer position corresponding to the start of line `line` (0-indexed).
BufferPos buffer_pos_start_of_line(TextBuffer *buffer, u32 line);
-// Buffer position corresponding to the end of line `line` (0-indexed).
+/// Buffer position corresponding to the end of line `line` (0-indexed).
BufferPos buffer_pos_end_of_line(TextBuffer *buffer, u32 line);
-// Move cursor to the start of the line, like the Home key does.
+/// Move cursor to the start of the line, like the Home key does.
void buffer_cursor_move_to_start_of_line(TextBuffer *buffer);
-// Move cursor to the end of the line, like the End key does.
+/// Move cursor to the end of the line, like the End key does.
void buffer_cursor_move_to_end_of_line(TextBuffer *buffer);
-// Move cursor to the start of the file, like Ctrl+Home does.
+/// Move cursor to the start of the file, like Ctrl+Home does.
void buffer_cursor_move_to_start_of_file(TextBuffer *buffer);
-// Move cursor to the end of the file, like Ctrl+End does.
+/// Move cursor to the end of the file, like Ctrl+End does.
void buffer_cursor_move_to_end_of_file(TextBuffer *buffer);
-// Get the LSPDocumentID corresponding to the file this buffer contains.
-// The return value is only useful if buffer_lsp(buffer) != NULL.
+/// Get the LSPDocumentID corresponding to the file this buffer contains.
+/// The return value is only useful if buffer_lsp(buffer) != NULL.
LSPDocumentID buffer_lsp_document_id(TextBuffer *buffer);
-// Get LSPPosition corresponding to position in buffer.
+/// Get LSPPosition corresponding to position in buffer.
LSPPosition buffer_pos_to_lsp_position(TextBuffer *buffer, BufferPos pos);
-// Get LSPDocumentPosition corresponding to position in buffer.
+/// Get LSPDocumentPosition corresponding to position in buffer.
LSPDocumentPosition buffer_pos_to_lsp_document_position(TextBuffer *buffer, BufferPos pos);
-// Convert LSPPosition to BufferPos.
+/// Convert LSPPosition to BufferPos.
BufferPos buffer_pos_from_lsp(TextBuffer *buffer, LSPPosition lsp_pos);
-// Get the cursor position as an LSPPosition.
+/// Get the cursor position as an LSPPosition.
LSPPosition buffer_cursor_pos_as_lsp_position(TextBuffer *buffer);
-// Get the cursor position as an LSPDocumentPosition.
+/// Get the cursor position as an LSPDocumentPosition.
LSPDocumentPosition buffer_cursor_pos_as_lsp_document_position(TextBuffer *buffer);
-// Put text at a position. All text insertion should eventually go through this function.
+/// Put text at a position. All text insertion should eventually go through this function.
BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 str);
-// Insert a single character at a position.
+/// Insert a single character at a position.
void buffer_insert_char_at_pos(TextBuffer *buffer, BufferPos pos, char32_t c);
-// Set the selection to between `buffer->cursor_pos` and `pos`,
-// and move the cursor to `pos`.
+/// Set the selection to between `buffer->cursor_pos` and `pos`,
+/// and move the cursor to `pos`.
void buffer_select_to_pos(TextBuffer *buffer, BufferPos pos);
-// Like shift+left, move cursor `nchars` chars to the left, selecting everything in between.
+/// Like shift+left, move cursor `nchars` chars to the left, selecting everything in between.
void buffer_select_left(TextBuffer *buffer, i64 nchars);
-// Like shift+right, move cursor `nchars` chars to the right, selecting everything in between.
+/// Like shift+right, move cursor `nchars` chars to the right, selecting everything in between.
void buffer_select_right(TextBuffer *buffer, i64 nchars);
-// Like shift+down, move cursor `nchars` lines down, selecting everything in between.
+/// Like shift+down, move cursor `nchars` lines down, selecting everything in between.
void buffer_select_down(TextBuffer *buffer, i64 nchars);
-// Like shift+up, move cursor `nchars` lines up, selecting everything in between.
+/// Like shift+up, move cursor `nchars` lines up, selecting everything in between.
void buffer_select_up(TextBuffer *buffer, i64 nchars);
-// Move the cursor `by` lines down, selecting everything in between.
+/// Move the cursor `by` lines down, selecting everything in between.
void buffer_select_down_blank_lines(TextBuffer *buffer, i64 by);
-// Move the cursor `by` lines up, selecting everything in between.
+/// Move the cursor `by` lines up, selecting everything in between.
void buffer_select_up_blank_lines(TextBuffer *buffer, i64 by);
-// Move the cursor `nwords` words left, selecting everything in between.
+/// Move the cursor `nwords` words left, selecting everything in between.
void buffer_select_left_words(TextBuffer *buffer, i64 nwords);
-// Move the cursor `nwords` words right, selecting everything in between.
+/// Move the cursor `nwords` words right, selecting everything in between.
void buffer_select_right_words(TextBuffer *buffer, i64 nwords);
-// Like Shift+Home, move cursor to start of line and select everything in between.
+/// Like Shift+Home, move cursor to start of line and select everything in between.
void buffer_select_to_start_of_line(TextBuffer *buffer);
-// Like Shift+End, move cursor to end of line and select everything in between.
+/// Like Shift+End, move cursor to end of line and select everything in between.
void buffer_select_to_end_of_line(TextBuffer *buffer);
-// Like Ctrl+Shift+Home, move cursor to start of file and select everything in between.
+/// Like Ctrl+Shift+Home, move cursor to start of file and select everything in between.
void buffer_select_to_start_of_file(TextBuffer *buffer);
-// Like Ctrl+Shift+End, move cursor to end of file and select everything in between.
+/// Like Ctrl+Shift+End, move cursor to end of file and select everything in between.
void buffer_select_to_end_of_file(TextBuffer *buffer);
-// select the word the cursor is inside of
+/// select the word the cursor is inside of
void buffer_select_word(TextBuffer *buffer);
-// select the line the cursor is currently on
+/// select the line the cursor is currently on
void buffer_select_line(TextBuffer *buffer);
-// select all of the buffer's contents
+/// select all of the buffer's contents
void buffer_select_all(TextBuffer *buffer);
-// Remove current selection.
+/// Remove current selection.
void buffer_deselect(TextBuffer *buffer);
-// Scroll up by `npages` pages
+/// Scroll up by `npages` pages
void buffer_page_up(TextBuffer *buffer, i64 npages);
-// Scroll down by `npages` pages
+/// Scroll down by `npages` pages
void buffer_page_down(TextBuffer *buffer, i64 npages);
-// Scroll up by `npages` pages, selecting everything in between
+/// Scroll up by `npages` pages, selecting everything in between
void buffer_select_page_up(TextBuffer *buffer, i64 npages);
-// Scroll down by `npages` pages, selecting everything in between
+/// Scroll down by `npages` pages, selecting everything in between
void buffer_select_page_down(TextBuffer *buffer, i64 npages);
-// Delete `nchars` characters starting from `pos`.
-// All text deletion should eventually go through this function.
+/// Delete `nchars` characters starting from `pos`.
+/// All text deletion should eventually go through this function.
void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars);
-// Delete characters between the two positions.
-// The order of `p1` and `p2` is irrelevant.
+/// Delete characters between the two positions.
+/// The order of `p1` and `p2` is irrelevant.
i64 buffer_delete_chars_between(TextBuffer *buffer, BufferPos p1, BufferPos p2);
-// Delete current selection.
+/// Delete current selection.
i64 buffer_delete_selection(TextBuffer *buffer);
-// Insert UTF-32 text at the cursor, and move the cursor to the end of it.
+/// Insert UTF-32 text at the cursor, and move the cursor to the end of it.
void buffer_insert_text_at_cursor(TextBuffer *buffer, String32 str);
-// Insert a single character at the cursor, and move the cursor past it.
+/// Insert a single character at the cursor, and move the cursor past it.
void buffer_insert_char_at_cursor(TextBuffer *buffer, char32_t c);
-// Insert UTF-8 text at the cursor, and move the cursor to the end of it.
+/// Insert UTF-8 text at the cursor, and move the cursor to the end of it.
void buffer_insert_utf8_at_cursor(TextBuffer *buffer, const char *utf8);
-// Insert a "tab" at the cursor position, and move the cursor past it.
-// This inserts spaces if ted is configured to indent with spaces.
+/// Insert a "tab" at the cursor position, and move the cursor past it.
+/// This inserts spaces if ted is configured to indent with spaces.
void buffer_insert_tab_at_cursor(TextBuffer *buffer);
-// Insert a newline at the cursor position.
-// If `buffer` is a line buffer, this "submits" the buffer.
-// If not, this auto-indents the next line, and moves the cursor to it.
+/// Insert a newline at the cursor position.
+/// If `buffer` is a line buffer, this "submits" the buffer.
+/// If not, this auto-indents the next line, and moves the cursor to it.
void buffer_newline(TextBuffer *buffer);
-// Delete `nchars` characters after the cursor.
+/// Delete `nchars` characters after the cursor.
void buffer_delete_chars_at_cursor(TextBuffer *buffer, i64 nchars);
-// Delete `nchars` characters before *pos, and set *pos to just before the deleted characters.
-// Returns the number of characters actually deleted.
+/// Delete `nchars` characters before *pos, and set *pos to just before the deleted characters.
+/// Returns the number of characters actually deleted.
i64 buffer_backspace_at_pos(TextBuffer *buffer, BufferPos *pos, i64 nchars);
-// Delete `nchars` characters before the cursor position, and set the cursor position accordingly.
-// Returns the number of characters actually deleted.
+/// Delete `nchars` characters before the cursor position, and set the cursor position accordingly.
+/// Returns the number of characters actually deleted.
i64 buffer_backspace_at_cursor(TextBuffer *buffer, i64 nchars);
-// Delete `nwords` words after the position.
+/// Delete `nwords` words after the position.
void buffer_delete_words_at_pos(TextBuffer *buffer, BufferPos pos, i64 nwords);
-// Delete `nwords` words after the cursor.
+/// Delete `nwords` words after the cursor.
void buffer_delete_words_at_cursor(TextBuffer *buffer, i64 nwords);
-// Delete `nwords` words before *pos, and set *pos to just before the deleted words.
-// Returns the number of words actually deleted.
+/// Delete `nwords` words before *pos, and set *pos to just before the deleted words.
+/// Returns the number of words actually deleted.
void buffer_backspace_words_at_pos(TextBuffer *buffer, BufferPos *pos, i64 nwords);
-// Delete `nwords` words before the cursor position, and set the cursor position accordingly.
-// Returns the number of words actually deleted.
+/// Delete `nwords` words before the cursor position, and set the cursor position accordingly.
+/// Returns the number of words actually deleted.
void buffer_backspace_words_at_cursor(TextBuffer *buffer, i64 nwords);
-// Undo `ntimes` times
+/// Undo `ntimes` times
void buffer_undo(TextBuffer *buffer, i64 ntimes);
-// Redo `ntimes` times
+/// Redo `ntimes` times
void buffer_redo(TextBuffer *buffer, i64 ntimes);
-// Start a new "edit chain". Undoing once after an edit chain will undo everything in the chain.
+/// Start a new "edit chain". Undoing once after an edit chain will undo everything in the chain.
void buffer_start_edit_chain(TextBuffer *buffer);
-// End the edit chain.
+/// End the edit chain.
void buffer_end_edit_chain(TextBuffer *buffer);
-// Copy the current selection to the clipboard.
+/// Copy the current selection to the clipboard.
void buffer_copy(TextBuffer *buffer);
-// Copy the current selection to the clipboard, and delete it.
+/// Copy the current selection to the clipboard, and delete it.
void buffer_cut(TextBuffer *buffer);
-// Insert the clipboard contents at the cursor position.
+/// Insert the clipboard contents at the cursor position.
void buffer_paste(TextBuffer *buffer);
-// Load the file `path`. If `path` is not an absolute path,
-// this function will fail.
+/// Load the file `path`. If `path` is not an absolute path,
+/// this function will fail.
bool buffer_load_file(TextBuffer *buffer, const char *path);
-// Reloads the file loaded in the buffer.
+/// Reloads the file loaded in the buffer.
void buffer_reload(TextBuffer *buffer);
-// has this buffer been changed by another program since last save?
+/// has this buffer been changed by another program since last save?
bool buffer_externally_changed(TextBuffer *buffer);
-// Clear `buffer`, and set its path to `path`.
-// if `path` is NULL, this will turn `buffer` into an untitled buffer.
+/// Clear `buffer`, and set its path to `path`.
+/// if `path` is NULL, this will turn `buffer` into an untitled buffer.
void buffer_new_file(TextBuffer *buffer, const char *path);
-// Save the buffer to its current filename. This will rewrite the entire file,
-// even if there are no unsaved changes.
+/// Save the buffer to its current filename. This will rewrite the entire file,
+/// even if there are no unsaved changes.
bool buffer_save(TextBuffer *buffer);
-// save, but with a different path
+/// save, but with a different path
bool buffer_save_as(TextBuffer *buffer, const char *new_filename);
-// index of first line that will be displayed on screen
+/// index of first line that will be displayed on screen
u32 buffer_first_rendered_line(TextBuffer *buffer);
-// index of last line that will be displayed on screen
+/// index of last line that will be displayed on screen
u32 buffer_last_rendered_line(TextBuffer *buffer);
-// go to the definition/declaration/etc of the word at the cursor.
+/// go to the definition/declaration/etc of the word at the cursor.
void buffer_goto_word_at_cursor(TextBuffer *buffer, GotoType type);
-// process a mouse click.
-// returns true if the event was consumed.
+/// process a mouse click.
+/// returns true if the event was consumed.
bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times);
-// render the buffer in the given rectangle
+/// render the buffer in the given rectangle
void buffer_render(TextBuffer *buffer, Rect r);
-// indent the given lines
+/// indent the given lines
void buffer_indent_lines(TextBuffer *buffer, u32 first_line, u32 last_line);
-// de-indent the given lines
+/// de-indent the given lines
void buffer_dedent_lines(TextBuffer *buffer, u32 first_line, u32 last_line);
-// indent the selected lines
+/// indent the selected lines
void buffer_indent_selection(TextBuffer *buffer);
-// de-indent the selected lines
+/// de-indent the selected lines
void buffer_dedent_selection(TextBuffer *buffer);
-// indent the line the cursor is on
+/// indent the line the cursor is on
void buffer_indent_cursor_line(TextBuffer *buffer);
-// de-indent the line the cursor is on
+/// de-indent the line the cursor is on
void buffer_dedent_cursor_line(TextBuffer *buffer);
-// comment the lines from `first_line` to `last_line`
+/// comment the lines from `first_line` to `last_line`
void buffer_comment_lines(TextBuffer *buffer, u32 first_line, u32 last_line);
-// uncomment the lines from `first_line` to `last_line`
+/// uncomment the lines from `first_line` to `last_line`
void buffer_uncomment_lines(TextBuffer *buffer, u32 first_line, u32 last_line);
-// comment the lines from `first_line` to `last_line`, or uncomment them if they're all commented.
+/// comment the lines from `first_line` to `last_line`, or uncomment them if they're all commented.
void buffer_toggle_comment_lines(TextBuffer *buffer, u32 first_line, u32 last_line);
-// comment the selected lines, or uncomment them if they're all commented
+/// comment the selected lines, or uncomment them if they're all commented
void buffer_toggle_comment_selection(TextBuffer *buffer);
-// make sure to call gl_geometry_draw after this
+/// make sure to call \ref gl_geometry_draw after this
void buffer_highlight_lsp_range(TextBuffer *buffer, LSPRange range);
-// returns true if p1 and p2 are equal
+/// returns true if `p1` and `p2` are equal
bool buffer_pos_eq(BufferPos p1, BufferPos p2);
-
-// returns:
-// -1 if p1 comes before p2
-// +1 if p1 comes after p2
-// 0 if p1 = p2
-// faster than buffer_pos_diff (constant time)
+/// returns `-1` if `p1` comes before `p2`
+///
+/// `+1` if `p1` comes after `p2`
+///
+/// `0` if `p1` = `p2`
+///
+/// faster than \ref buffer_pos_diff (constant time)
int buffer_pos_cmp(BufferPos p1, BufferPos p2);
+/// returns "`p2 - p1`", that is, the number of characters between `p1` and `p2`.
+i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2);
// === build.c ===
-// clear build errors and stop
+/// clear build errors and stop
void build_stop(Ted *ted);
-// call before adding anything to the build queue
+/// call before adding anything to the build queue
void build_queue_start(Ted *ted);
-// add a command to the build queue. call build_queue_start before this.
+/// add a command to the build queue. call build_queue_start before this.
void build_queue_command(Ted *ted, const char *command);
-// call this after calling build_queue_start, build_queue_command.
-// make sure you set ted->build_dir before running this!
+/// call this after calling build_queue_start, build_queue_command.
+/// make sure you set ted->build_dir before running this!
void build_queue_finish(Ted *ted);
-// set up the build output buffer.
+/// set up the build output buffer.
void build_setup_buffer(Ted *ted);
-// run a single command in the build window.
-// make sure you set ted->build_dir before running this!
+/// run a single command in the build window.
+/// make sure you set ted->build_dir before running this!
void build_start_with_command(Ted *ted, const char *command);
-// figure out which build command to run, and run it.
+/// figure out which build command to run, and run it.
void build_start(Ted *ted);
-// go to next build error
+/// go to next build error
void build_next_error(Ted *ted);
-// go to previous build error
+/// go to previous build error
void build_prev_error(Ted *ted);
-// find build errors in build buffer.
+/// find build errors in build buffer.
void build_check_for_errors(Ted *ted);
void build_frame(Ted *ted, float x1, float y1, float x2, float y2);
@@ -963,12 +1116,12 @@ void color_init(void);
ColorSetting color_setting_from_str(const char *str);
const char *color_setting_to_str(ColorSetting s);
Status color_from_str(const char *str, u32 *color);
-// which color setting should be used for the given symbol kind.
-// this is the color used in the autocomplete selector, for example.
+/// which color setting should be used for the given symbol kind.
+/// this is the color used in the autocomplete selector, for example.
ColorSetting color_for_symbol_kind(SymbolKind kind);
-// perform SRC_ALPHA, ONE_MINUS_SRC_ALPHA blending with `bg` and `fg`.
+/// perform SRC_ALPHA, ONE_MINUS_SRC_ALPHA blending with `bg` and `fg`.
u32 color_blend(u32 bg, u32 fg);
-// multiply color's alpha value by `opacity`.
+/// multiply color's alpha value by `opacity`.
u32 color_apply_opacity(u32 color, float opacity);
// === command.c ===
@@ -978,60 +1131,63 @@ const char *command_to_str(Command c);
void command_execute(Ted *ted, Command c, i64 argument);
// === config.c ===
-// first, we read all config files, then we parse them.
-// this is because we want less specific settings (e.g. settings applied
-// to all languages instead of one particular language) to be applied first,
-// then more specific settings are based off of those.
-// EXAMPLE:
-// ---config file 1---
-// [Javascript.core]
-// syntax-highlighting = off
-// (inherits tab-width = 4)
-// [CSS.core]
-// tab-width = 2 (overrides tab-width = 4)
-// ---config file 2---
-// [core]
-// tab-width = 4
+/// first, we read all config files, then we parse them.
+/// this is because we want less specific settings (e.g. settings applied
+/// to all languages instead of one particular language) to be applied first,
+/// then more specific settings are based off of those.
+///
+/// EXAMPLE:
+/// ```
+/// ---config file 1---
+/// [Javascript.core]
+/// syntax-highlighting = off
+/// (inherits tab-width = 4)
+/// [CSS.core]
+/// tab-width = 2 (overrides tab-width = 4)
+/// ---config file 2---
+/// [core]
+/// tab-width = 4
+/// ```
void config_read(Ted *ted, ConfigPart **pparts, const char *filename);
void config_parse(Ted *ted, ConfigPart **pparts);
void config_free(Ted *ted);
-// returns the best guess for the root directory of the project containing `path`
-// (which should be an absolute path).
-// the return value should be freed.
+/// returns the best guess for the root directory of the project containing `path`
+/// (which should be an absolute path).
+/// the return value should be freed.
char *settings_get_root_dir(Settings *settings, const char *path);
-// how well does this settings context fit the given path and language?
-// the context with the highest score will be chosen.
+/// how well does this settings context fit the given path and language?
+/// the context with the highest score will be chosen.
long context_score(const char *path, Language lang, const SettingsContext *context);
// === find.c ===
-// which buffer will be searched?
+/// which buffer will be searched?
TextBuffer *find_search_buffer(Ted *ted);
-// height of the find/find+replace menu in pixels
+/// height of the find/find+replace menu in pixels
float find_menu_height(Ted *ted);
-// update find results.
-// if `force` is true, the results will be updated even if the pattern & flags have not been changed.
+/// update find results.
+/// if `force` is true, the results will be updated even if the pattern & flags have not been changed.
void find_update(Ted *ted, bool force);
-// replace the match we are currently highlighting, or do nothing if there is no highlighted match
+/// replace the match we are currently highlighting, or do nothing if there is no highlighted match
void find_replace(Ted *ted);
-// go to next find result
+/// go to next find result
void find_next(Ted *ted);
-// go to previous find result
+/// go to previous find result
void find_prev(Ted *ted);
-// replace all matches
+/// replace all matches
void find_replace_all(Ted *ted);
void find_menu_frame(Ted *ted, Rect menu_bounds);
-// open the find/find+replace menu.
+/// open the find/find+replace menu.
void find_open(Ted *ted, bool replace);
-// close the find/find+replace menu.
+/// close the find/find+replace menu.
void find_close(Ted *ted);
// === gl.c ===
-// set by main()
+/// set by main()
extern float gl_window_width, gl_window_height;
-// set by main()
+/// set by main()
extern int gl_version_major, gl_version_minor;
-// macro trickery to avoid having to write everything multiple times
+/// macro trickery to avoid having to write every GL function multiple times
#define gl_for_each_proc(do)\
do(DRAWARRAYS, DrawArrays)\
do(GENTEXTURES, GenTextures)\
@@ -1092,74 +1248,74 @@ extern int gl_version_major, gl_version_minor;
gl_for_each_proc(gl_declare_proc)
#undef gl_declare_proc
-// get addresses of GL functions
+/// get addresses of GL functions
void gl_get_procs(void);
-// create a new reference-counted shader-array-buffer object.
+/// create a new reference-counted shader-array-buffer object.
GlRcSAB *gl_rc_sab_new(GLuint shader, GLuint array, GLuint buffer);
-// increase reference count on `s`.
+/// increase reference count on `s`.
void gl_rc_sab_incref(GlRcSAB *s);
-// decrease reference count on `*ps`, and set `*ps` to NULL if the reference count is 0.
+/// decrease reference count on `*ps`, and set `*ps` to NULL if the reference count is 0.
void gl_rc_sab_decref(GlRcSAB **ps);
-// create a new reference-counted texture.
+/// create a new reference-counted texture.
GlRcTexture *gl_rc_texture_new(GLuint texture);
-// increase reference count on `t`.
+/// increase reference count on `t`.
void gl_rc_texture_incref(GlRcTexture *t);
-// decrease reference count on `*t`, and set `*t` to NULL if the reference count is 0.
+/// decrease reference count on `*t`, and set `*t` to NULL if the reference count is 0.
void gl_rc_texture_decref(GlRcTexture **pt);
-// create and compile a shader
+/// create and compile a shader
GLuint gl_compile_shader(char error_buf[256], const char *code, GLenum shader_type);
-// create new shader program from shaders
+/// create new shader program from shaders
GLuint gl_link_program(char error_buf[256], GLuint *shaders, size_t count);
-// create a shader program from vertex shader and fragment shader source
+/// create a shader program from vertex shader and fragment shader source
GLuint gl_compile_and_link_shaders(char error_buf[256], const char *vshader_code, const char *fshader_code);
-// prints a debug message if `attrib` is not found
+/// prints a debug message if `attrib` is not found
GLuint gl_attrib_location(GLuint program, const char *attrib);
-// prints a debug message if `uniform` is not found
+/// prints a debug message if `uniform` is not found
GLint gl_uniform_location(GLuint program, const char *uniform);
-// initialize geometry stuff
+/// initialize geometry stuff
void gl_geometry_init(void);
-// queue a filled rectangle with the given color.
+/// queue a filled rectangle with the given color.
void gl_geometry_rect(Rect r, u32 color_rgba);
-// queue the border of a rectangle with the given color.
+/// queue the border of a rectangle with the given color.
void gl_geometry_rect_border(Rect r, float border_thickness, u32 color);
-// draw all queued geometry
+/// draw all queued geometry
void gl_geometry_draw(void);
-// create an OpenGL texture object from an image file.
+/// create an OpenGL texture object from an image file.
GLuint gl_load_texture_from_image(const char *path);
// === ide-autocomplete.c ===
-// open autocomplete
-// trigger should either be a character (e.g. '.') or one of the TRIGGER_* constants.
+/// open autocomplete
+/// trigger should either be a character (e.g. '.') or one of the TRIGGER_* constants.
void autocomplete_open(Ted *ted, uint32_t trigger);
void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response);
-// select the completion the cursor is on,
-// or select the phantom completion if there is one.
+/// select the completion the cursor is on,
+/// or select the phantom completion if there is one.
void autocomplete_select_completion(Ted *ted);
-// scroll completion list
+/// scroll completion list
void autocomplete_scroll(Ted *ted, i32 by);
-// move cursor to next completion
+/// move cursor to next completion
void autocomplete_next(Ted *ted);
-// move cursor to previous completion
+/// move cursor to previous completion
void autocomplete_prev(Ted *ted);
-// close completion menu
+/// close completion menu
void autocomplete_close(Ted *ted);
void autocomplete_frame(Ted *ted);
// === ide-definitions.c ===
-// go to the definition of `name`.
-// if `lsp` is NULL, tags will be used.
-// Note: the document position is required for LSP requests because of overloading (where the name
-// alone isn't sufficient)
+/// go to the definition of `name`.
+/// if `lsp` is NULL, tags will be used.
+/// Note: the document position is required for LSP requests because of overloading (where the name
+/// alone isn't sufficient)
void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos, GotoType type);
-// cancel the last go-to-definition / find symbols request.
+/// cancel the last go-to-definition / find symbols request.
void definition_cancel_lookup(Ted *ted);
void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response);
-// open the definitions menu
+/// open the definitions menu
void definitions_selector_open(Ted *ted);
-// update the definitions menu
+/// update the definitions menu
void definitions_selector_update(Ted *ted);
void definitions_selector_render(Ted *ted, Rect bounds);
-// close the definitions menu
+/// close the definitions menu
void definitions_selector_close(Ted *ted);
void definitions_frame(Ted *ted);
@@ -1174,10 +1330,10 @@ void hover_process_lsp_response(Ted *ted, LSPResponse *response);
void hover_frame(Ted *ted, double dt);
// === ide-signature-help.c ===
-// figure out new signature help
+/// figure out new signature help
void signature_help_retrigger(Ted *ted);
-// open signature help. `trigger` should either be the trigger character (e.g. ',')
-// or one of the TRIGGER_* constants.
+/// open signature help. `trigger` should either be the trigger character (e.g. ',')
+/// or one of the TRIGGER_* constants.
void signature_help_open(Ted *ted, uint32_t trigger);
bool signature_help_is_open(Ted *ted);
void signature_help_close(Ted *ted);
@@ -1185,9 +1341,9 @@ void signature_help_process_lsp_response(Ted *ted, const LSPResponse *response);
void signature_help_frame(Ted *ted);
// === ide-usages.c ===
-// cancel the last "find usages" request
+/// cancel the last "find usages" request
void usages_cancel_lookup(Ted *ted);
-// find usages for word under the cursor in the active buffer.
+/// find usages for word under the cursor in the active buffer.
void usages_find(Ted *ted);
void usages_process_lsp_response(Ted *ted, const LSPResponse *response);
void usages_frame(Ted *ted);
@@ -1195,49 +1351,49 @@ void usages_frame(Ted *ted);
// === menu.c ===
void menu_close(Ted *ted);
void menu_open(Ted *ted, Menu menu);
-// process a :escape command (by default this happens when the escape key is pressed)
+/// process a :escape command (by default this happens when the escape key is pressed)
void menu_escape(Ted *ted);
-// get width of menu in pixels
+/// get width of menu in pixels
float menu_get_width(Ted *ted);
-// get rectangle which menu takes up
+/// get rectangle which menu takes up
Rect menu_rect(Ted *ted);
void menu_update(Ted *ted);
void menu_render(Ted *ted);
-// move to next/previous command
+/// move to next/previous command
void menu_shell_move(Ted *ted, int direction);
-// move to previous command
+/// move to previous command
void menu_shell_up(Ted *ted);
-// move to next command
+/// move to next command
void menu_shell_down(Ted *ted);
// === node.c ===
void node_switch_to_tab(Ted *ted, Node *node, u16 new_tab_index);
-// go to the `n`th next tab (e.g. `n=1` goes to the next tab)
-// going past the end of the tabs will "wrap around" to the first one.
+/// go to the `n`th next tab (e.g. `n=1` goes to the next tab)
+/// going past the end of the tabs will "wrap around" to the first one.
void node_tab_next(Ted *ted, Node *node, i64 n);
-// go to the `n`th previous tab (e.g. `n=1` goes to the previous tab)
-// going before the first tab will "wrap around" to the last one.
+/// go to the `n`th previous tab (e.g. `n=1` goes to the previous tab)
+/// going before the first tab will "wrap around" to the last one.
void node_tab_prev(Ted *ted, Node *node, i64 n);
-// switch to a specific tab. if `tab` is out of range, nothing happens.
+/// switch to a specific tab. if `tab` is out of range, nothing happens.
void node_tab_switch(Ted *ted, Node *node, i64 tab);
-// swap the position of two tabs
+/// swap the position of two tabs
void node_tabs_swap(Node *node, u16 tab1, u16 tab2);
void node_free(Node *node);
-// returns index of parent in ted->nodes, or -1 if this is the root node.
+/// returns index of parent in ted->nodes, or -1 if this is the root node.
i32 node_parent(Ted *ted, u16 node_idx);
-// join this node with its sibling
+/// join this node with its sibling
void node_join(Ted *ted, Node *node);
-// close a node, WITHOUT checking for unsaved changes
+/// close a node, WITHOUT checking for unsaved changes
void node_close(Ted *ted, u16 node_idx);
-// close tab, WITHOUT checking for unsaved changes!
-// returns true if the node is still open
+/// close tab, WITHOUT checking for unsaved changes!
+/// returns true if the node is still open
bool node_tab_close(Ted *ted, Node *node, u16 index);
void node_frame(Ted *ted, Node *node, Rect r);
-// make a split
+/// make a split
void node_split(Ted *ted, Node *node, bool vertical);
-// switch to the other side of the current split.
+/// switch to the other side of the current split.
void node_split_switch(Ted *ted);
-// swap the two sides of the current split.
+/// swap the two sides of the current split.
void node_split_swap(Ted *ted);
// === session.c ===
@@ -1247,169 +1403,174 @@ void session_read(Ted *ted);
// === syntax.c ===
Language language_from_str(const char *str);
const char *language_to_str(Language language);
-// string which should be put before comments in the given language
+/// string which should be put before comments in the given language
const char *language_comment_start(Language l);
-// string which should be put after comments in the given language
+/// string which should be put after comments in the given language
const char *language_comment_end(Language l);
-// get the color setting associated with the given syntax highlighting type
+/// get the color setting associated with the given syntax highlighting type
ColorSetting syntax_char_type_to_color_setting(SyntaxCharType t);
-// returns ')' for '(', etc., or 0 if c is not an opening bracket
+/// returns ')' for '(', etc., or 0 if c is not an opening bracket
char32_t syntax_matching_bracket(Language lang, char32_t c);
-// returns true for opening brackets, false for closing brackets/non-brackets
+/// returns true for opening brackets, false for closing brackets/non-brackets
bool syntax_is_opening_bracket(Language lang, char32_t c);
-// This is the main syntax highlighting function. It will determine which colors to use for each character.
-// Rather than returning colors, it returns a character type (e.g. comment) which can be converted to a color.
-// To highlight multiple lines, start out with a zeroed SyntaxState, and pass a pointer to it each time.
-// You can set char_types to NULL if you just want to advance the state, and don't care about the character types.
+/// This is the main syntax highlighting function. It will determine which colors to use for each character.
+/// Rather than returning colors, it returns a character type (e.g. comment) which can be converted to a color.
+/// To highlight multiple lines, start out with a zeroed SyntaxState, and pass a pointer to it each time.
+/// You can set char_types to NULL if you just want to advance the state, and don't care about the character types.
void syntax_highlight(SyntaxState *state, Language lang, const char32_t *line, u32 line_len, SyntaxCharType *char_types);
// === tags.c ===
void tags_generate(Ted *ted, bool run_in_build_window);
-// find all tags beginning with the given prefix, returning them into `*out`, writing at most out_size entries.
-// you may pass NULL for `out`, in which case just the number of matching tags is returned
-// (still maxing out at `out_size`).
-// each element in `out` should be freed when you're done with them.
+/// find all tags beginning with the given prefix, returning them into `*out`, writing at most out_size entries.
+/// you may pass NULL for `out`, in which case just the number of matching tags is returned
+/// (still maxing out at `out_size`).
+/// each element in `out` should be freed when you're done with them.
size_t tags_beginning_with(Ted *ted, const char *prefix, char **out, size_t out_size, bool error_if_tags_does_not_exist);
-// go to the definition of the given tag
+/// go to the definition of the given tag
bool tag_goto(Ted *ted, const char *tag);
-// get all tags in the tags file as SymbolInfos.
+/// get all tags in the tags file as SymbolInfos.
SymbolInfo *tags_get_symbols(Ted *ted);
// === ted.c ===
-// for fatal errors
+/// for fatal errors
void die(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
-// display a message to the user
+/// display a message to the user
void ted_set_message(Ted *ted, MessageType type, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4);
-// display an error to the user
+/// display an error to the user
void ted_error(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
-// display a warning to the user
+/// display a warning to the user
void ted_warn(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
-// display information to the user
+/// display information to the user
void ted_info(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
-// for information that should be logged
+/// for information that should be logged
void ted_log(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
-// set error to "out of memory" message.
+/// set error to "out of memory" message.
void ted_out_of_mem(Ted *ted);
-// allocate memory, producing an error message and returning NULL on failure
+/// allocate memory, producing an error message and returning NULL on failure
void *ted_malloc(Ted *ted, size_t size);
-// allocate memory, producing an error message and returning NULL on failure
+/// allocate memory, producing an error message and returning NULL on failure
void *ted_calloc(Ted *ted, size_t n, size_t size);
-// allocate memory, producing an error message and returning NULL on failure
+/// allocate memory, producing an error message and returning NULL on failure
void *ted_realloc(Ted *ted, void *p, size_t new_size);
-// Check the various places a ted data file could be
-// (i.e. look for it in the local and global data directories),
-// and return the full path.
+/// Check the various places a ted data file could be
+/// (i.e. look for it in the local and global data directories),
+/// and return the full path.
Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz);
-// get full path relative to ted->cwd.
+/// get full path relative to ted->cwd.
void ted_path_full(Ted *ted, const char *relpath, char *abspath, size_t abspath_size);
-// set ted->active_buffer to something nice
+/// set ted->active_buffer to something nice
void ted_reset_active_buffer(Ted *ted);
-// set ted's error message to the buffer's error.
+/// set ted's error message to the buffer's error.
void ted_error_from_buffer(Ted *ted, TextBuffer *buffer);
-// Returns the buffer containing the file at `path`, or NULL if there is none.
+/// Returns the buffer containing the file at `path`, or NULL if there is none.
TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path);
-// save all buffers
+/// save all buffers
bool ted_save_all(Ted *ted);
-// reload all buffers from their files
+/// reload all buffers from their files
void ted_reload_all(Ted *ted);
-// Load all the fonts ted will use.
+/// Load all the fonts ted will use.
void ted_load_fonts(Ted *ted);
-// Get likely root directory of project containing `path`.
-// The returned value should be freed.
+/// Get likely root directory of project containing `path`.
+/// The returned value should be freed.
char *ted_get_root_dir_of(Ted *ted, const char *path);
-// Get the root directory of the project containing the active buffer's file,
-// or `ted->cwd` if no file is open.
-// The returned value should be freed.
+/// Get the root directory of the project containing the active buffer's file,
+/// or `ted->cwd` if no file is open.
+/// The returned value should be freed.
char *ted_get_root_dir(Ted *ted);
-// the settings of the active buffer, or the default settings if there is no active buffer
+/// the settings of the active buffer, or the default settings if there is no active buffer
Settings *ted_active_settings(Ted *ted);
-// Get the settings for a file at the given path in the given language.
+/// Get the settings for a file at the given path in the given language.
Settings *ted_get_settings(Ted *ted, const char *path, Language language);
-// Get LSP by ID. Returns NULL if there is no LSP with that ID.
+/// Get LSP by ID. Returns NULL if there is no LSP with that ID.
LSP *ted_get_lsp_by_id(Ted *ted, LSPID id);
-// Get LSP which should be used for the given path and language.
-// If no running LSP server would cover the path and language, a new one is
-// started if possible.
-// Returns NULL on failure (e.g. there is no LSP server
-// specified for the given path and language).
+/// Get LSP which should be used for the given path and language.
+/// If no running LSP server would cover the path and language, a new one is
+/// started if possible.
+/// Returns NULL on failure (e.g. there is no LSP server
+/// specified for the given path and language).
LSP *ted_get_lsp(Ted *ted, const char *path, Language language);
-// Get the LSP of the active buffer/ted->cwd.
-// Returns NULL if there is no such server.
+/// Get the LSP of the active buffer/ted->cwd.
+/// Returns NULL if there is no such server.
LSP *ted_active_lsp(Ted *ted);
-// get the value of the given color setting, according to `ted_active_settings(ted)`.
+/// get the value of the given color setting, according to `ted_active_settings(ted)`.
u32 ted_active_color(Ted *ted, ColorSetting color);
-// open the given file, or switch to it if it's already open.
-// returns true on success.
+/// open the given file, or switch to it if it's already open.
+/// returns true on success.
bool ted_open_file(Ted *ted, const char *filename);
-// create a new buffer for the file `filename`, or open it if it's already open.
-// if `filename` is NULL, this creates an untitled buffer.
-// returns true on success.
+/// create a new buffer for the file `filename`, or open it if it's already open.
+/// if `filename` is NULL, this creates an untitled buffer.
+/// returns true on success.
bool ted_new_file(Ted *ted, const char *filename);
-// returns the index of an available buffer, or -1 if none are available
+/// returns the index of an available buffer, or -1 if none are available
i32 ted_new_buffer(Ted *ted);
-// Returns the index of an available node, or -1 if none are available
+/// Returns the index of an available node, or -1 if none are available
i32 ted_new_node(Ted *ted);
-// Opposite of ted_new_buffer
-// Make sure you set active_buffer to something else if you delete it!
+/// Opposite of ted_new_buffer
+/// Make sure you set active_buffer to something else if you delete it!
void ted_delete_buffer(Ted *ted, u16 index);
-// save all changes to all buffers with unsaved changes.
+/// save all changes to all buffers with unsaved changes.
bool ted_save_all(Ted *ted);
-// sets the active buffer to this buffer, and updates active_node, etc. accordingly
-// you can pass NULL to buffer to make it so no buffer is active.
+/// sets the active buffer to this buffer, and updates active_node, etc. accordingly
+/// you can pass NULL to buffer to make it so no buffer is active.
void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer);
-// switch to this node
+/// switch to this node
void ted_node_switch(Ted *ted, Node *node);
-// load ted.cfg files
+/// load ted.cfg files
void ted_load_configs(Ted *ted, bool reloading);
-// handle a key press
+/// handle a key press
void ted_press_key(Ted *ted, SDL_Keycode keycode, SDL_Keymod modifier);
-// get the buffer and buffer position where the mouse is.
-// returns false if the mouse is not in a buffer.
+/// get the buffer and buffer position where the mouse is.
+/// returns false if the mouse is not in a buffer.
Status ted_get_mouse_buffer_pos(Ted *ted, TextBuffer **pbuffer, BufferPos *ppos);
-// make the cursor red for a bit to indicate an error (e.g. no autocompletions)
+/// make the cursor red for a bit to indicate an error (e.g. no autocompletions)
void ted_flash_error_cursor(Ted *ted);
-// go to `path` at line `line` and index `index`, opening a new buffer if necessary.
-// if `is_lsp` is set to true, `index` is interpreted as a UTF-16 offset rather than a UTF-32 offset.
+/// go to `path` at line `line` and index `index`, opening a new buffer if necessary.
+/// if `is_lsp` is set to true, `index` is interpreted as a UTF-16 offset rather than a UTF-32 offset.
void ted_go_to_position(Ted *ted, const char *path, u32 line, u32 index, bool is_lsp);
-// go to this LSP document position, opening a new buffer containing the file if necessary.
+/// go to this LSP document position, opening a new buffer containing the file if necessary.
void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition position);
-// cancel this LSP request. also zeroes *request
-// if *request is zeroed, this does nothing.
+/// cancel this LSP request. also zeroes *request
+/// if *request is zeroed, this does nothing.
void ted_cancel_lsp_request(Ted *ted, LSPServerRequestID *request);
-// how tall is a line buffer?
+/// how tall is a line buffer?
float ted_line_buffer_height(Ted *ted);
-// check for orphaned nodes and node cycles
+/// check for orphaned nodes and node cycles
void ted_check_for_node_problems(Ted *ted);
-// convert LSPWindowMessageType to MessageType
+/// convert LSPWindowMessageType to MessageType
MessageType ted_message_type_from_lsp(LSPWindowMessageType type);
-// get colors to use for message box
+/// get colors to use for message box
void ted_color_settings_for_message_type(MessageType type, ColorSetting *bg_color, ColorSetting *border_color);
// === ui.c ===
-// move selector cursor up by `n` entries
+/// move selector cursor up by `n` entries
void selector_up(Ted *ted, Selector *s, i64 n);
-// move selector cursor down by `n` entries
+/// move selector cursor down by `n` entries
void selector_down(Ted *ted, Selector *s, i64 n);
-// sort entries alphabetically
+/// sort entries alphabetically
void selector_sort_entries_by_name(Selector *s);
-// returns a null-terminated UTF-8 string of the entry selected, or NULL if none was.
-// also, sel->cursor will be set to the index of the entry, even if the mouse was used.
-// you should call free() on the return value.
+/// returns a null-terminated UTF-8 string of the entry selected, or NULL if none was.
+/// also, sel->cursor will be set to the index of the entry, even if the mouse was used.
+/// you should call free() on the return value.
char *selector_update(Ted *ted, Selector *s);
-// NOTE: also renders the line buffer
+/// NOTE: also renders the line buffer
void selector_render(Ted *ted, Selector *s);
void file_selector_free(FileSelector *fs);
-// returns the name of the selected file, or NULL if none was selected.
-// the returned pointer should be freed.
+/// returns the name of the selected file, or NULL if none was selected.
+/// the returned pointer should be freed.
char *file_selector_update(Ted *ted, FileSelector *fs);
void file_selector_render(Ted *ted, FileSelector *fs);
vec2 button_get_size(Ted *ted, const char *text);
void button_render(Ted *ted, Rect button, const char *text, u32 color);
-// returns true if the button was clicked on.
+/// returns true if the button was clicked on.
bool button_update(Ted *ted, Rect button);
-// returns selected option, or POPUP_NONE if none was selected
+/// returns selected option, or POPUP_NONE if none was selected
PopupOption popup_update(Ted *ted, u32 options);
void popup_render(Ted *ted, u32 options, const char *title, const char *body);
vec2 checkbox_frame(Ted *ted, bool *value, const char *label, vec2 pos);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif
diff --git a/text.h b/text.h
index 2d7429d..31997d7 100644
--- a/text.h
+++ b/text.h
@@ -1,11 +1,16 @@
-// A text-rendering interface.
-// Example usage:
-// Font *font = text_font_load("font.ttf", 18);
-// if (font) {
-// text_utf8(font, "Hello", 5, 5, 0xFF0000FF);
-// text_utf8(font, "Goodbye", 5, 100, 0x00FF00FF);
-// text_render(font);
-// }
+/// \file
+/// A text-rendering interface.
+///
+/// Example usage:
+///
+/// ```
+/// Font *font = text_font_load("font.ttf", 18);
+/// if (font) {
+/// text_utf8(font, "Hello", 5, 5, 0xFF0000FF);
+/// text_utf8(font, "Goodbye", 5, 100, 0x00FF00FF);
+/// text_render(font);
+/// }
+/// ```
#ifndef TEXT_H_
#define TEXT_H_
@@ -13,24 +18,34 @@
#include "base.h"
#include "util.h"
+/// a font
typedef struct Font Font;
+/// text render state.
+///
+/// do not construct this directly instead use \ref text_render_state_default.
typedef struct {
- // should the text actually be rendered (set to false to get text size)
+ /// should the text actually be rendered (set to false to get text size)
bool render;
- bool wrap; // should the text wrap around to min_x when it reaches max_x? NOTE: this is character-by-character wrapping, not word wrap
-
+ /// should the text wrap around to min_x when it reaches max_x? NOTE: this is character-by-character wrapping, not word wrap
+ bool wrap;
+ /// where to draw
double x, y;
- // points where the text should be cut off
+ /// points where the text should be cut off
float min_x, max_x, min_y, max_y;
- // [0] = r, [1] = g, [2] = b, [3] = a.
+ /// `[0] = r, [1] = g, [2] = b, [3] = a`.
float color[4];
- // largest x & y achieved (for computing size)
+ /// largest x achieved (for computing size)
double x_largest;
+ /// largest y achieved (for computing size)
double y_largest;
+
+ /// used for forwards-compatibility
+ char _reserved[64];
} TextRenderState;
+/// text anchor
typedef enum {
ANCHOR_TOP_LEFT,
ANCHOR_TOP_MIDDLE,
@@ -43,38 +58,48 @@ typedef enum {
ANCHOR_BOTTOM_RIGHT,
} Anchor;
+/// returns false on error.
bool text_init(void);
+/// is there error?
bool text_has_err(void);
-// Get the current error. Errors will NOT be overwritten with newer errors.
+/// Get the current error. Errors will NOT be overwritten with newer errors.
const char *text_get_err(void);
-// Clear the current error.
+/// Clear the current error.
void text_clear_err(void);
-// Load a TTF font found in ttf_filename with the given font size (character pixel height)
+/// Load a TTF font found in ttf_filename with the given font size (character pixel height)
Font *text_font_load(const char *ttf_filename, float font_size);
-// Height of a character of this font in pixels.
+/// Height of a character of this font in pixels.
float text_font_char_height(Font *font);
-// Width of the character 'a' of this font in pixels.
-// This is meant to be only used for monospace fonts.
+/// Width of the character 'a' of this font in pixels.
+/// This is meant to be only used for monospace fonts.
float text_font_char_width(Font *font);
-// Force text to advance by text_font_char_width(font) pixels per character (actually, per code point).
+/// Force text to advance by text_font_char_width(font) pixels per character (actually, per code point).
void text_font_set_force_monospace(Font *font, bool force);
-// Get the dimensions of some text.
+/// Get the dimensions of some text.
void text_get_size(Font *font, const char *text, float *width, float *height);
+/// Get the dimensions of some text.
vec2 text_get_size_vec2(Font *font, const char *text);
+/// Get the dimensions of some text.
void text_get_size32(Font *font, const char32_t *text, u64 len, float *width, float *height);
+/// Draw some text.
void text_utf8(Font *font, const char *text, double x, double y, u32 color);
+/// Draw some text with an anchor.
void text_utf8_anchored(Font *font, const char *text, double x, double y, u32 color, Anchor anchor);
+/// Draw a single character.
void text_char_with_state(Font *font, TextRenderState *state, char32_t c);
+/// Draw some UTF-8 text with a \ref TextRenderState.
void text_utf8_with_state(Font *font, TextRenderState *state, const char *str);
-// Free memory used by font.
+/// Free memory used by font.
void text_font_free(Font *font);
+/// Render all text drawn with \ref text_utf8, etc.
void text_render(Font *font);
-
-// The "default" text rendering state - everything you need to just render text normally.
-// This lets you do stuff like:
-// TextRenderState state = text_render_state_default;
-// (set a few options)
-// text_render_with_state(font, &state, ...)
+/// The "default" text rendering state - everything you need to just render text normally.
+/// This lets you do stuff like:
+/// ```
+/// TextRenderState state = text_render_state_default;
+/// (set a few options)
+/// text_render_with_state(font, &state, ...)
+/// ```
extern const TextRenderState text_render_state_default;
#endif
diff --git a/unicode.h b/unicode.h
index 2b686df..1e517c4 100644
--- a/unicode.h
+++ b/unicode.h
@@ -1,10 +1,14 @@
-// functions for dealing with UTF-8/UTF-16/UTF-32.
-// this file is entirely self-contained.
+/// \file
+/// functions for dealing with UTF-8/UTF-16/UTF-32.
+///
+/// this file is entirely self-contained.
#ifndef UNICODE_H_
#define UNICODE_H_
+/// useful for "this character couldn't be rendered / is invalid UTF-8"
#define UNICODE_BOX_CHARACTER 0x2610
-#define UNICODE_CODE_POINTS 0x110000 // number of Unicode code points
+/// number of Unicode code points
+#define UNICODE_CODE_POINTS 0x110000
#include <stddef.h>
#include <stdint.h>
@@ -19,15 +23,16 @@ static bool unicode_is_continuation_byte(uint8_t byte) {
return (byte & 0xC0) == 0x80;
}
-// A lot like mbrtoc32. Doesn't depend on the locale though, for one thing.
-// *c will be filled with the next UTF-8 code point in `str`. `bytes` refers to the maximum
-// number of bytes that can be read from `str` (note: this function will never read past a null
-// byte, even if `bytes` indicates that it could).
-// Returns:
-// 0 - if a null character was encountered or if `bytes == 0`
-// (size_t)-1 - on invalid UTF-8
-// (size_t)-2 - on incomplete code point (str should be longer)
-// other - the number of bytes read from `str`.
+/// A lot like mbrtoc32. Doesn't depend on the locale though, for one thing.
+///
+/// *c will be filled with the next UTF-8 code point in `str`. `bytes` refers to the maximum
+/// number of bytes that can be read from `str` (note: this function will never read past a null
+/// byte, even if `bytes` indicates that it could).
+/// Returns:\n
+/// `0` - if a null character was encountered or if `bytes == 0`\n
+/// `(size_t)-1` - on invalid UTF-8\n
+/// `(size_t)-2` - on incomplete code point (str should be longer)\n
+/// other - the number of bytes read from `str`.
static size_t unicode_utf8_to_utf32(uint32_t *c, const char *str, size_t bytes) {
*c = 0;
if (bytes == 0) {
@@ -121,10 +126,11 @@ static size_t unicode_utf8_to_utf32(uint32_t *c, const char *str, size_t bytes)
}
}
-// A lot like c32rtomb
-// Converts a UTF-32 codepoint to a UTF-8 string. Writes at most 4 bytes to s.
-// NOTE: It is YOUR JOB to null-terminate your string if the UTF-32 isn't null-terminated!
-// Returns the number of bytes written to s, or (size_t)-1 on invalid UTF-32.
+/// A lot like c32rtomb
+///
+/// Converts a UTF-32 codepoint to a UTF-8 string. Writes at most 4 bytes to s.
+/// NOTE: It is YOUR JOB to null-terminate your string if the UTF-32 isn't null-terminated!
+/// Returns the number of bytes written to `s`, or `(size_t)-1` on invalid UTF-32.
static size_t unicode_utf32_to_utf8(char *s, uint32_t c32) {
uint8_t *p = (uint8_t *)s;
if (c32 <= 0x7F) {
@@ -162,7 +168,8 @@ static size_t unicode_utf32_to_utf8(char *s, uint32_t c32) {
// get the number of UTF-16 codepoints needed to encode `str`.
-// returns (size_t)-1 on bad UTF-8
+///
+// returns `(size_t)-1` on bad UTF-8
static size_t unicode_utf16_len(const char *str) {
size_t len = 0;
uint32_t c = 0;
@@ -179,9 +186,11 @@ static size_t unicode_utf16_len(const char *str) {
return len;
}
-// returns the UTF-8 offset from `str` which corresponds to a UTF-16 offset of utf16_offset (rounds down if utf16_offset is in the middle of a codepoint).
-// returns strlen(str) if utf16_offset == unicode_utf16_len(str)
-// returns (size_t)-1 on bad UTF-8, or if utf16_offset > unicode_utf16_len(str)
+/// returns the UTF-8 offset from `str` which corresponds to a UTF-16 offset of
+/// `utf16_offset` (rounds down if `utf16_offset` is in the middle of a codepoint).
+///
+/// returns `strlen(str)` if `utf16_offset == unicode_utf16_len(str)`
+/// returns `(size_t)-1` on bad UTF-8, or if `utf16_offset > unicode_utf16_len(str)`
static size_t unicode_utf16_to_utf8_offset(const char *str, size_t utf16_offset) {
size_t offset = 0;
uint32_t c = 0;
diff --git a/util.h b/util.h
index 4b043ba..0f8ca55 100644
--- a/util.h
+++ b/util.h
@@ -1,15 +1,15 @@
-// C utility functions
-// these utilities should be self-contained
+/// \file
+/// C utility functions
#ifndef UTIL_H_
#define UTIL_H_
#include "base.h"
-// like snprintf, but not screwed up on windows
+/// like snprintf, but not screwed up on old versions of windows
#define str_printf(str, size, ...) (str)[(size) - 1] = '\0', snprintf((str), (size) - 1, __VA_ARGS__)
-// like snprintf, but the size is taken to be the length of the array str.
-// first, check that str is actually an array
+/// like snprintf, but the size is taken to be the length of the array str.
+/// first, check that str is actually an array
#define strbuf_printf(str, ...) assert(sizeof str != 4 && sizeof str != 8), \
str_printf(str, sizeof str, __VA_ARGS__)
#define str_catf(str, size, ...) str_printf((str) + strlen(str), (size) - strlen(str), __VA_ARGS__)
@@ -42,14 +42,14 @@ typedef struct {
vec2 pos, size;
} Rect;
-// UTF-32 string
+/// UTF-32 string
typedef struct {
char32_t *str;
size_t len;
} String32;
-// ctype functions for 32-bit chars.
+/// ctype functions for 32-bit chars.
bool is32_word(char32_t c);
bool is32_space(char32_t c);
bool is32_alpha(char32_t c);
@@ -57,75 +57,75 @@ bool is32_alnum(char32_t c);
bool is32_digit(char32_t c);
bool is32_graph(char32_t c);
bool is_a_tty(FILE *out);
-// terminal colors. if `out` is a TTY, these will return the appropriate escape sequences.
-// if `out` is not a TTY, these will return "".
+/// terminal colors. if `out` is a TTY, these will return the appropriate escape sequences.
+/// if `out` is not a TTY, these will return "".
const char *term_italics(FILE *out);
const char *term_bold(FILE *out);
const char *term_yellow(FILE *out);
const char *term_clear(FILE *out);
-// number of 1 bits in x.
+/// number of 1 bits in x.
u8 util_popcount(u64 x);
-// count leading zeroes. if x == 0, this always returns 32 (not undefined behavior).
+/// count leading zeroes. if x == 0, this always returns 32 (not undefined behavior).
u8 util_count_leading_zeroes32(u32 x);
-// is x a power of 2?
+/// is x a power of 2?
bool util_is_power_of_2(u64 x);
-// like memchr, but 32-bit.
+/// like memchr, but 32-bit.
char32_t *util_mem32chr(char32_t *s, char32_t c, size_t n);
-// like memchr, but 32-bit, and constant.
+/// like memchr, but 32-bit, and constant.
const char32_t *util_mem32chr_const(const char32_t *s, char32_t c, size_t n);
-// does `str` have this prefix?
+/// does `str` have this prefix?
bool str_has_prefix(const char *str, const char *prefix);
-// like str_has_prefix, but for paths. "ab/cd" is a path-prefix of "ab/cd/ef", but not "ab/cde".
-// also handles the fact that \ and / are the same on windows
+/// like str_has_prefix, but for paths. "ab/cd" is a path-prefix of "ab/cd/ef", but not "ab/cde".
+/// also handles the fact that \ and / are the same on windows
bool str_has_path_prefix(const char *path, const char *prefix);
-// are these two strings equal?
+/// are these two strings equal?
bool streq(const char *a, const char *b);
-// equivalent to the POSIX function strnlen
+/// equivalent to the POSIX function strnlen
size_t strn_len(const char *src, size_t n);
-// equivalent to the POSIX function strndup
+/// equivalent to the POSIX function strndup
char *strn_dup(const char *src, size_t n);
-// equivalent to the POSIX function strdup
+/// equivalent to the POSIX function strdup
char *str_dup(const char *src);
-// a safer version of strncat. `dst_sz` includes a null-terminator.
+/// a safer version of strncat. `dst_sz` includes a null-terminator.
void strn_cat(char *dst, size_t dst_sz, const char *src, size_t src_len);
-// a safer version of strcat. `dst_sz` includes a null-terminator.
+/// a safer version of strcat. `dst_sz` includes a null-terminator.
void str_cat(char *dst, size_t dst_sz, const char *src);
-// a safer version of strncpy. `dst_sz` includes a null-terminator.
+/// a safer version of strncpy. `dst_sz` includes a null-terminator.
void strn_cpy(char *dst, size_t dst_sz, const char *src, size_t src_len);
-// a safer version of strcpy. `dst_sz` includes a null-terminator.
+/// a safer version of strcpy. `dst_sz` includes a null-terminator.
void str_cpy(char *dst, size_t dst_sz, const char *src);
-// equivalent to GNU function asprintf (like sprintf, but allocates the string with malloc).
+/// equivalent to GNU function asprintf (like sprintf, but allocates the string with malloc).
char *a_sprintf(const char *fmt, ...);
-// print some bytes. useful for debugging.
+/// print some bytes. useful for debugging.
void print_bytes(const u8 *bytes, size_t n);
-// like strstr, but case-insensitive
-// currently this uses a "naive" string searching algorithm so
-// it may be O(len(haystack) * len(needle)) for certain strings.
+/// like strstr, but case-insensitive
+/// currently this uses a "naive" string searching algorithm so
+/// it may be O(len(haystack) * len(needle)) for certain strings.
char *strstr_case_insensitive(const char *haystack, const char *needle);
-// like strcmp, but case-insensitive
+/// like strcmp, but case-insensitive
int strcmp_case_insensitive(const char *a, const char *b);
-// like streq, but case-insensitive
+/// like streq, but case-insensitive
bool streq_case_insensitive(const char *a, const char *b);
-// function to be passed into qsort for case insensitive sorting
+/// function to be passed into qsort for case insensitive sorting
int str_qsort_case_insensitive_cmp(const void *av, const void *bv);
-// the actual file name part of the path; get rid of the containing directory.
-// NOTE: the returned string is part of path, so you don't need to free it or anything.
+/// the actual file name part of the path; get rid of the containing directory.
+/// NOTE: the returned string is part of path, so you don't need to free it or anything.
const char *path_filename(const char *path);
-// is this an absolute path?
+/// is this an absolute path?
bool path_is_absolute(const char *path);
-// assuming `dir` is an absolute path, returns the absolute path of `relpath`, relative to `dir`.
+/// assuming `dir` is an absolute path, returns the absolute path of `relpath`, relative to `dir`.
void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size);
-// returns true if the paths are the same.
-// handles the fact that paths are case insensitive on windows and that \ is the same as /.
-// a symbolic link is considered different from the file it points to, as are two hard
-// links to the same file.
+/// returns true if the paths are the same.
+/// handles the fact that paths are case insensitive on windows and that \ is the same as /.
+/// a symbolic link is considered different from the file it points to, as are two hard
+/// links to the same file.
bool paths_eq(const char *path1, const char *path2);
-// equivalent to POSIX function chdir.
+/// equivalent to POSIX function chdir.
void change_directory(const char *path);
-// copy file from src to dest
-// returns true on success
+/// copy file from src to dest
+/// returns true on success
bool copy_file(const char *src, const char *dst);
-// like qsort, but with a context object which gets passed to the comparison function
+/// like qsort, but with a context object which gets passed to the comparison function
void qsort_with_context(void *base, size_t nmemb, size_t size,
int (*compar)(void *, const void *, const void *),
void *arg);