static void build_start(Ted *ted) { chdir(ted->cwd); #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); arr_foreach_ptr(ted->build_errors, BuildError, err) { free(err->filename); } 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; // check for errors for (u32 line_idx = 0; line_idx < buffer->nlines; ++line_idx) { Line *line = &buffer->lines[line_idx]; if (line->len < 3) { continue; } bool is_error = true; u32 i = 0; char32_t *str = line->str; u32 len = line->len; // we have something like main.c:5 // get file name while (i < len) { if (str[i] == ':') break; if (!is32_alnum(str[i]) && str[i] != '/' && str[i] != '.' && str[i] != '\\') { is_error = false; break; } ++i; } if (i >= len) is_error = false; if (is_error) { u32 filename_len = i; u32 line_number_len = 0; ++i; while (i < len) { if (str[i] == ':') break; if (str[i] < '0' || str[i] > '9') { is_error = false; break; } ++i; ++line_number_len; } if (i >= len) is_error = false; if (line_number_len == 0) is_error = false; if (is_error) { char *line_number_str = str32_to_utf8_cstr(str32(str + filename_len + 1, line_number_len)); if (line_number_str) { int line_number = atoi(line_number_str); free(line_number_str); char *filename = str32_to_utf8_cstr(str32(str, filename_len)); if (filename) { char full_path[TED_PATH_MAX]; ted_full_path(ted, filename, full_path, sizeof full_path); printf("File %s line %d\n",full_path,line_number); } } } } } } buffer->view_only = true; } buffer_render(buffer, rect4(x1, y1, x2, y2)); }