summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-02-16 12:33:11 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-02-16 12:33:11 -0500
commit824c4ff4be5a0bf55b6644fed06fcfe2248c4301 (patch)
tree0eb56394e769e23005a9f03ffea0557c2577e542
parent4bde24cb63313f636ac72b449f54d68515efe485 (diff)
started getting :build to work
-rw-r--r--buffer.c21
-rw-r--r--build.c96
-rw-r--r--command.c9
-rw-r--r--command.h3
-rw-r--r--find.c6
-rw-r--r--main.c73
-rw-r--r--process-posix.c2
-rw-r--r--string32.c2
-rw-r--r--ted.cfg2
-rw-r--r--ted.h8
-rw-r--r--text.c2
-rw-r--r--unicode.h9
-rw-r--r--util.c2
13 files changed, 164 insertions, 71 deletions
diff --git a/buffer.c b/buffer.c
index 332a8a2..eeadff0 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1291,6 +1291,11 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
return b;
}
+void buffer_insert_char_at_pos(TextBuffer *buffer, BufferPos pos, char32_t c) {
+ String32 s = {&c, 1};
+ buffer_insert_text_at_pos(buffer, pos, s);
+}
+
// Select (or add to selection) everything between the cursor and pos, and move the cursor to pos
void buffer_select_to_pos(TextBuffer *buffer, BufferPos pos) {
if (!buffer->selection)
@@ -1812,7 +1817,7 @@ Status buffer_load_file(TextBuffer *buffer, char const *filename) {
// null character
c = 0;
++p;
- } else if (n == (size_t)(-1)) {
+ } else if (n >= (size_t)(-2)) {
// invalid UTF-8
success = false;
buffer_seterr(buffer, "Invalid UTF-8 (position: %td).", p - file_contents);
@@ -1905,7 +1910,8 @@ bool buffer_externally_changed(TextBuffer *buffer) {
void buffer_new_file(TextBuffer *buffer, char const *filename) {
buffer_clear(buffer);
- buffer->filename = buffer_strdup(buffer, filename);
+ if (filename)
+ buffer->filename = buffer_strdup(buffer, filename);
buffer->lines_capacity = 4;
buffer->lines = buffer_calloc(buffer, buffer->lines_capacity, sizeof *buffer->lines);
buffer->nlines = 1;
@@ -2045,6 +2051,8 @@ void buffer_render(TextBuffer *buffer, Rect r) {
float render_start_y = y1 - (float)(buffer->scroll_y - start_line) * char_height; // where the 1st line is rendered
+ bool render_cursor = buffer == ted->active_buffer;
+
// line numbering
if (!buffer->is_line_buffer && settings->line_numbers) {
float line_number_width = ndigits_u64(buffer->nlines) * char_width + padding;
@@ -2054,7 +2062,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
text_state.max_y = y2;
float y = render_start_y;
- u32 cursor_line = buffer->cursor_pos.line;
+ u32 cursor_line = render_cursor ? buffer->cursor_pos.line : U32_MAX;
for (u32 line = start_line; line < nlines; ++line) {
char str[32] = {0};
strbuf_printf(str, U32_FMT, line + 1); // convert line number to string
@@ -2082,9 +2090,8 @@ void buffer_render(TextBuffer *buffer, Rect r) {
// the rectangle that the cursor is rendered as
Rect cursor_rect = rect(cursor_display_pos, V2(settings->cursor_width, char_height));
-
- // highlight line cursor is on
- {
+ if (render_cursor) {
+ // highlight line cursor is on
Rect hl_rect = rect(V2(x1, cursor_display_pos.y), V2(x2-x1-1, char_height));
buffer_clip_rect(buffer, &hl_rect);
gl_geometry_rect(hl_rect, colors[COLOR_CURSOR_LINE_BG]);
@@ -2226,7 +2233,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
text_render(font);
- if (buffer == ted->active_buffer) {
+ if (render_cursor) {
// render cursor
float time_on = settings->cursor_blink_time_on;
float time_off = settings->cursor_blink_time_off;
diff --git a/build.c b/build.c
new file mode 100644
index 0000000..0afee56
--- /dev/null
+++ b/build.c
@@ -0,0 +1,96 @@
+static void build_start(Ted *ted) {
+#if __unix__
+ char *program = "/bin/sh";
+ char *argv[] = {
+ program, "-c", "make", NULL
+ };
+#else
+ #error "TODO"
+#endif
+
+ process_exec(&ted->build_process, program, argv);
+ ted->building = true;
+ ted->build_shown = true;
+ buffer_new_file(&ted->build_buffer, NULL);
+ ted->build_buffer.store_undo_events = false;
+ ted->build_buffer.view_only = true;
+}
+
+static void build_stop(Ted *ted) {
+ if (ted->building)
+ process_kill(&ted->build_process);
+ ted->building = false;
+ ted->build_shown = false;
+}
+
+static void build_frame(Ted *ted, float x1, float y1, float x2, float y2) {
+ TextBuffer *buffer = &ted->build_buffer;
+ Process *process = &ted->build_process;
+ assert(ted->build_shown);
+ char buf[256];
+ if (ted->building) {
+ buffer->view_only = false; // disable view only temporarily so we can edit it
+ bool any_text_inserted = false;
+ while (1) {
+ char incomplete[4];
+ memcpy(ted->build_incomplete_codepoint, incomplete, sizeof incomplete);
+ *ted->build_incomplete_codepoint = 0;
+
+ i64 bytes_read = (i64)process_read(process, buf + 3, sizeof buf - 3);
+ if (bytes_read == -2) {
+ ted_seterr(ted, "Error reading command output: %s.", process_geterr(process));
+ build_stop(ted);
+ break;
+ } else if (bytes_read == -1) {
+ // no data right now.
+ break;
+ } else if (bytes_read == 0) {
+ // end of file
+ break;
+ } else {
+ any_text_inserted = true;
+ // got some data.
+ char *p = buf + 3 - strlen(incomplete);
+ char *end = buf + 3 + bytes_read;
+ // start off data with incomplete code point from last time
+ memcpy(p, incomplete, strlen(incomplete));
+ while (p != end) {
+ char32_t c = 0;
+ size_t ret = unicode_utf8_to_utf32(&c, p, (size_t)(end - p));
+ if (ret == (size_t)-1) {
+ // invalid UTF-8. skip this byte.
+ ++p;
+ } else if (ret == (size_t)-2) {
+ // incomplete UTF-8
+ size_t leftovers = (size_t)(end - p);
+ assert(leftovers < 4);
+ memcpy(ted->build_incomplete_codepoint, p, leftovers);
+ ted->build_incomplete_codepoint[leftovers] = '\0';
+ p = end;
+ } else {
+ if (ret == 0) ret = 1;
+ // got a code point
+ buffer_insert_char_at_pos(buffer, buffer_end_of_file(buffer), c);
+ p += ret;
+ }
+ }
+ }
+ }
+
+ if (any_text_inserted) {
+ buffer->cursor_pos = buffer_end_of_file(buffer);
+ buffer_scroll_to_cursor(buffer);
+ }
+
+ char message[64];
+ int status = process_check_status(process, message, sizeof message);
+ if (status == 0) {
+ // hasn't exited yet
+ } else {
+ buffer_insert_utf8_at_cursor(buffer, message);
+ ted->building = false;
+ }
+ buffer->view_only = true;
+ }
+ buffer_render(buffer, rect4(x1, y1, x2, y2));
+}
diff --git a/command.c b/command.c
index 0153c64..01a7a88 100644
--- a/command.c
+++ b/command.c
@@ -297,9 +297,18 @@ void command_execute(Ted *ted, Command c, i64 argument) {
menu_escape(ted);
} else if (ted->find) {
find_close(ted);
+ } else if (ted->build_shown) {
+ build_stop(ted);
} else if (buffer) {
buffer_disable_selection(buffer);
}
break;
+
+ case CMD_BUILD:
+ if (ted->building) {
+ build_stop(ted);
+ }
+ build_start(ted);
+ break;
}
}
diff --git a/command.h b/command.h
index 965d568..1e15886 100644
--- a/command.h
+++ b/command.h
@@ -65,6 +65,8 @@ ENUM_U16 {
CMD_VIEW_ONLY, // toggle view-only mode
+ CMD_BUILD,
+
CMD_ESCAPE, // by default this is the escape key. closes menus, etc.
CMD_COUNT
@@ -128,6 +130,7 @@ static CommandName const command_names[CMD_COUNT] = {
{"increase-text-size", CMD_TEXT_SIZE_INCREASE},
{"decrease-text-size", CMD_TEXT_SIZE_DECREASE},
{"view-only", CMD_VIEW_ONLY},
+ {"build", CMD_BUILD},
{"escape", CMD_ESCAPE},
};
diff --git a/find.c b/find.c
index 31eb898..2612577 100644
--- a/find.c
+++ b/find.c
@@ -292,15 +292,13 @@ static void find_replace_all(Ted *ted) {
}
}
-static void find_menu_frame(Ted *ted) {
+static void find_menu_frame(Ted *ted, float x1, float y1, float x2, float y2) {
Font *font = ted->font, *font_bold = ted->font_bold;
float const char_height = text_font_char_height(font),
char_height_bold = text_font_char_height(font_bold);
Settings const *settings = &ted->settings;
float const padding = settings->padding;
- float const menu_height = find_menu_height(ted);
- float const window_width = ted->window_width, window_height = ted->window_height;
u32 const *colors = settings->colors;
bool const replace = ted->replace;
@@ -311,8 +309,6 @@ static void find_menu_frame(Ted *ted) {
u32 last_rendered_line = buffer_last_rendered_line(buffer);
- float x1 = padding, y1 = window_height - menu_height + padding, x2 = window_width - padding, y2 = window_height - padding;
-
Rect menu_bounds = rect4(x1, y1, x2, y2);
x1 += padding;
diff --git a/main.c b/main.c
index d2f7e2f..f2f5ec7 100644
--- a/main.c
+++ b/main.c
@@ -66,6 +66,7 @@ no_warn_end
#include "find.c"
#include "node.c"
#include "menu.c"
+#include "build.c"
#include "command.c"
#include "config.c"
@@ -146,52 +147,6 @@ int main(int argc, char **argv) {
#endif
setlocale(LC_ALL, ""); // allow unicode
-
- char *program = "/usr/bin/sleep";
- char *args[] = {program, "5", NULL};
- Process process = {0}, *proc = &process;
-
- if (!process_exec(proc, program, args)) {
- printf("Error: %s\n", process_geterr(proc));
- return EXIT_FAILURE;
- }
- #if 0
- {
- i64 bytes = 0;
- char buf[256];
- while (1) {
- bytes = process_read(proc, buf, sizeof buf);
- if (bytes == -2) {
- printf("Error: %s\n", process_geterr(proc));
- } else if (bytes == -1) {
- usleep(1000);
- } else if (bytes == 0) {
- break;
- } else {
- fwrite(buf, 1, (size_t)bytes, stdout);
- }
- }
- }
- #endif
- #if 1
- {
- char message[256];
- while (1) {
- int status = process_check_status(proc, message, sizeof message);
- if (status == -1) {
- printf("%s!!!\n",message);
- break;
- } else if (status == +1) {
- printf("%s\n", message);
- break;
- } else {
- usleep(1000);
- }
- }
- }
- #endif
- return 0;
-
// read command-line arguments
char const *starting_filename = NULL;
switch (argc) {
@@ -373,8 +328,8 @@ int main(int argc, char **argv) {
}
line_buffer_create(&ted->find_buffer, ted);
line_buffer_create(&ted->replace_buffer, ted);
-
-
+ buffer_create(&ted->build_buffer, ted);
+
{
u16 buffer_index = (u16)ted_new_buffer(ted);
assert(buffer_index == 0);
@@ -627,13 +582,24 @@ int main(int argc, char **argv) {
Font *font = ted->font;
if (ted->active_node) {
- float x1 = 25, y1 = 25, x2 = window_width-25, y2 = window_height-25;
+ float const padding = settings->padding;
+ float x1 = padding, y = window_height-padding, x2 = window_width-padding;
Node *node = ted->root;
- if (ted->find) y2 -= find_menu_height(ted);
- node_frame(ted, node, rect4(x1, y1, x2, y2));
if (ted->find) {
- find_menu_frame(ted);
+ float y2 = y;
+ y -= find_menu_height(ted);
+ find_menu_frame(ted, x1, y, x2, y2);
+ y -= padding;
}
+ if (ted->build_shown) {
+ float y2 = y;
+ y -= 0.3f * ted->window_height;
+ build_frame(ted, x1, y, x2, y2);
+ y -= padding;
+ }
+
+ float y1 = padding;
+ node_frame(ted, node, rect4(x1, y1, x2, y));
} else {
text_utf8_anchored(font, "Press Ctrl+O to open a file or Ctrl+N to create a new one.",
window_width * 0.5f, window_height * 0.5f, colors[COLOR_TEXT_SECONDARY], ANCHOR_MIDDLE);
@@ -738,6 +704,8 @@ int main(int argc, char **argv) {
}
+ build_stop(ted);
+
if (ted->menu)
menu_close(ted); // free any memory used by the current menu
@@ -757,6 +725,7 @@ int main(int argc, char **argv) {
buffer_free(&ted->line_buffer);
buffer_free(&ted->find_buffer);
buffer_free(&ted->replace_buffer);
+ buffer_free(&ted->build_buffer);
text_font_free(ted->font);
text_font_free(ted->font_bold);
settings_free(&ted->settings);
diff --git a/process-posix.c b/process-posix.c
index da0448d..9be7e10 100644
--- a/process-posix.c
+++ b/process-posix.c
@@ -10,6 +10,8 @@ struct Process {
};
bool process_exec(Process *proc, char const *program, char **argv) {
+ memset(proc, 0, sizeof *proc);
+
bool success = false;
int pipefd[2];
diff --git a/string32.c b/string32.c
index fb1399e..09874bc 100644
--- a/string32.c
+++ b/string32.c
@@ -36,7 +36,7 @@ String32 str32_from_utf8(char const *utf8) {
char32_t c = 0;
size_t n = unicode_utf8_to_utf32(&c, utf8_p, (size_t)(utf8_end - utf8_p));
if (n == 0 // null character. this shouldn't happen.
- || n == (size_t)(-1) // invalid UTF-8
+ || n >= (size_t)(-2) // invalid UTF-8
) {
free(widestr);
widestr = wide_p = NULL;
diff --git a/ted.cfg b/ted.cfg
index 695bcdb..f222c37 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -111,6 +111,8 @@ Ctrl+- = 3 :decrease-text-size
Ctrl+Alt+Shift+v = :view-only
+F4 = :build
+
Escape = :escape
[colors]
diff --git a/ted.h b/ted.h
index 0341ec1..32a41c1 100644
--- a/ted.h
+++ b/ted.h
@@ -225,6 +225,7 @@ typedef struct Ted {
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)
double error_time; // time error box was opened (in seconds -- see time_get_seconds)
KeyAction key_actions[KEY_COMBO_COUNT];
bool search_cwd; // should the working directory be searched for files? set to true if the executable isn't "installed"
@@ -238,6 +239,13 @@ typedef struct Ted {
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?
+ 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)
+ char build_incomplete_codepoint[4];
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
diff --git a/text.c b/text.c
index aeb17ea..1096e8c 100644
--- a/text.c
+++ b/text.c
@@ -323,7 +323,7 @@ void text_utf8_with_state(Font *font, TextRenderState *state, char const *str) {
size_t ret = unicode_utf8_to_utf32(&c, str, (size_t)(end - str));
if (ret == 0) {
break;
- } else if (ret == (size_t)-1) {
+ } else if (ret >= (size_t)-2) {
// invalid UTF-8
text_char_with_state(font, state, '?');
++str;
diff --git a/unicode.h b/unicode.h
index 53941d2..211efd6 100644
--- a/unicode.h
+++ b/unicode.h
@@ -14,7 +14,8 @@ static bool unicode_is_start_of_code_point(u8 byte) {
// number of bytes that can be read from `str`.
// Returns:
// 0 - if a NULL character was encountered
-// (size_t)-1 - on invalid UTF-8 / incomplete code point
+// (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`.
static size_t unicode_utf8_to_utf32(char32_t *c, char const *str, size_t bytes) {
if (bytes == 0) {
@@ -39,7 +40,7 @@ static size_t unicode_utf8_to_utf32(char32_t *c, char const *str, size_t bytes)
} else {
// incomplete code point
*c = 0;
- return (size_t)-1;
+ return (size_t)-2;
}
}
if ((first_byte & 0xF0) == 0xE0) {
@@ -63,7 +64,7 @@ static size_t unicode_utf8_to_utf32(char32_t *c, char const *str, size_t bytes)
} else {
// incomplete
*c = 0;
- return (size_t)-1;
+ return (size_t)-2;
}
}
if ((first_byte & 0xF8) == 0xF0) {
@@ -90,7 +91,7 @@ static size_t unicode_utf8_to_utf32(char32_t *c, char const *str, size_t bytes)
} else {
// incomplete
*c = 0;
- return (size_t)-1;
+ return (size_t)-2;
}
}
// invalid UTF-8
diff --git a/util.c b/util.c
index 73f1e02..0e07b25 100644
--- a/util.c
+++ b/util.c
@@ -164,7 +164,7 @@ static char *stristr(char const *haystack, char const *needle) {
char32_t pchar = 0, qchar = 0;
size_t bytes_p = unicode_utf8_to_utf32(&pchar, p, (size_t)(haystack_end - p));
size_t bytes_q = unicode_utf8_to_utf32(&qchar, q, (size_t)(needle_end - q));
- if (bytes_p == (size_t)-1 || bytes_q == (size_t)-1) return NULL; // invalid UTF-8
+ if (bytes_p >= (size_t)-2 || bytes_q >= (size_t)-2) return NULL; // invalid UTF-8
bool same = pchar == qchar;
if (pchar < WINT_MAX && qchar < WINT_MAX) // on Windows, there is no way of finding the lower-case version of a codepoint outside the BMP. ):
same = towlower((wint_t)pchar) == towlower((wint_t)qchar);