se

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 626ebd15fe0b810817d949e5785f3ffa7f04faed
parent 9d120485062d6cf0ce9075543f46000b984f7f23
Author: Samdal <samdal@protonmail.com>
Date:   Thu, 29 Jun 2023 20:05:08 +0200

reformatting idk

Diffstat:
Mbuffer.c | 1380++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mbuffer.h | 147+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mextensions/syntax/gd.h | 146++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mextensions/syntax/handy_defines.h | 30+++++++++++++++---------------
Mextensions/syntax/syntax.h | 1049++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mse.c | 546+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mseek.c | 560++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mseek.h | 4++--
Mutf8.c | 116++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mx.c | 2574++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mx.h | 74+++++++++++++++++++++++++++++++++++++-------------------------------------
11 files changed, 3316 insertions(+), 3310 deletions(-)

diff --git a/buffer.c b/buffer.c @@ -33,16 +33,16 @@ static int available_buffer_slots = 0; static void recursive_mkdir(char *path) { - if (!path || !strlen(path)) - return; - char *sep = strrchr(path, '/'); - if(sep) { - *sep = '\0'; - recursive_mkdir(path); - *sep = '/'; - } - if(mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) && errno != EEXIST) - fprintf(stderr, "error while trying to create '%s'\n%s\n", path, strerror(errno)); + if (!path || !strlen(path)) + return; + char *sep = strrchr(path, '/'); + if(sep) { + *sep = '\0'; + recursive_mkdir(path); + *sep = '/'; + } + if(mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) && errno != EEXIST) + fprintf(stderr, "error while trying to create '%s'\n%s\n", path, strerror(errno)); } @@ -51,79 +51,79 @@ static int open_seproj(struct file_buffer fb); int open_seproj(struct file_buffer fb) { - int first = -1; + int first = -1; - char* path = file_path_get_path(fb.file_path); - chdir(path); - int offset = -1; + char* path = file_path_get_path(fb.file_path); + chdir(path); + int offset = -1; - while((offset = fb_seek_char(&fb, offset+1, ' ')) >= 0) - fb_change(&fb, "\n", 1, offset, 0); + while((offset = fb_seek_char(&fb, offset+1, ' ')) >= 0) + fb_change(&fb, "\n", 1, offset, 0); - offset = -1; - while((offset = fb_seek_char(&fb, offset+1, '\n')) >= 0) { - char* line = fb_get_line_at_offset(&fb, offset); - if (strlen(line) && !is_file_type(line, ".seproj")) { - if (first < 0) - first = fb_new_entry(line); - else - fb_new_entry(line); + offset = -1; + while((offset = fb_seek_char(&fb, offset+1, '\n')) >= 0) { + char* line = fb_get_line_at_offset(&fb, offset); + if (strlen(line) && !is_file_type(line, ".seproj")) { + if (first < 0) + first = fb_new_entry(line); + else + fb_new_entry(line); + } + free(line); } - free(line); - } - if (first < 0) - first = fb_new_entry(NULL); - writef_to_status_bar("opened project %s", path); - free(path); + if (first < 0) + first = fb_new_entry(NULL); + writef_to_status_bar("opened project %s", path); + free(path); - fb_destroy(&fb); - return first; + fb_destroy(&fb); + return first; } void fb_write_to_filepath(struct file_buffer* fb) { - if (!fb->file_path) - return; - soft_assert(fb->contents, return;); - FILE* file = fopen(fb->file_path, "w"); - soft_assert(file, return;); + if (!fb->file_path) + return; + soft_assert(fb->contents, return;); + FILE* file = fopen(fb->file_path, "w"); + soft_assert(file, return;); - if (fb->mode & FB_UTF8_SIGNED) - fwrite("\xEF\xBB\xBF", 1, 3, file); - fwrite(fb->contents, sizeof(char), fb->len, file); - writef_to_status_bar("saved buffer to %s", fb->file_path); + if (fb->mode & FB_UTF8_SIGNED) + fwrite("\xEF\xBB\xBF", 1, 3, file); + fwrite(fb->contents, sizeof(char), fb->len, file); + writef_to_status_bar("saved buffer to %s", fb->file_path); - fclose(file); - call_extension(fb_written_to_file, fb); + fclose(file); + call_extension(fb_written_to_file, fb); } int destroy_fb_entry(struct window_split_node* node, struct window_split_node* root) { - // do not allow deletion of the lst file buffer - int n = 0; - for(; n < available_buffer_slots; n++) - if (file_buffers[n].contents && n != node->wb.fb_index) - break; - if (n >= available_buffer_slots) { - writef_to_status_bar("can't delete last buffer"); - return 0; - } + // do not allow deletion of the lst file buffer + int n = 0; + for(; n < available_buffer_slots; n++) + if (file_buffers[n].contents && n != node->wb.fb_index) + break; + if (n >= available_buffer_slots) { + writef_to_status_bar("can't delete last buffer"); + return 0; + } - if (window_other_nodes_contain_fb(node, root)) { - node->wb.fb_index++; - node->wb = wb_new(node->wb.fb_index); - writef_to_status_bar("swapped buffer"); - return 0; - } - fb_destroy(get_fb(&node->wb)); + if (window_other_nodes_contain_fb(node, root)) { + node->wb.fb_index++; + node->wb = wb_new(node->wb.fb_index); + writef_to_status_bar("swapped buffer"); + return 0; + } + fb_destroy(get_fb(&node->wb)); - node->wb = wb_new(node->wb.fb_index); + node->wb = wb_new(node->wb.fb_index); - return 1; + return 1; } @@ -131,487 +131,487 @@ destroy_fb_entry(struct window_split_node* node, struct window_split_node* root) struct file_buffer* get_fb(struct window_buffer* wb) { - soft_assert(wb, wb = focused_window;); - soft_assert(file_buffers, fb_new_entry(NULL);); + soft_assert(wb, wb = focused_window;); + soft_assert(file_buffers, fb_new_entry(NULL);); - if (wb->fb_index < 0) - wb->fb_index = available_buffer_slots-1; - else if (wb->fb_index >= available_buffer_slots) - wb->fb_index = 0; + if (wb->fb_index < 0) + wb->fb_index = available_buffer_slots-1; + else if (wb->fb_index >= available_buffer_slots) + wb->fb_index = 0; - if (!file_buffers[wb->fb_index].contents) { - for(int n = wb->fb_index; n < available_buffer_slots; n++) { - if (file_buffers[n].contents) { - wb->fb_index = n; - return &file_buffers[n]; - } - } - for(int n = 0; n < available_buffer_slots; n++) { - if (file_buffers[n].contents) { - wb->fb_index = n; - return &file_buffers[n]; - } + if (!file_buffers[wb->fb_index].contents) { + for(int n = wb->fb_index; n < available_buffer_slots; n++) { + if (file_buffers[n].contents) { + wb->fb_index = n; + return &file_buffers[n]; + } + } + for(int n = 0; n < available_buffer_slots; n++) { + if (file_buffers[n].contents) { + wb->fb_index = n; + return &file_buffers[n]; + } + } + } else { + soft_assert(file_buffers[wb->fb_index].contents, ); + return &file_buffers[wb->fb_index]; } - } else { - soft_assert(file_buffers[wb->fb_index].contents, ); - return &file_buffers[wb->fb_index]; - } - wb->fb_index = fb_new_entry(NULL); - writef_to_status_bar("all buffers were somehow deleted, creating new one"); - status_bar_bg = warning_color; - return get_fb(wb); + wb->fb_index = fb_new_entry(NULL); + writef_to_status_bar("all buffers were somehow deleted, creating new one"); + status_bar_bg = warning_color; + return get_fb(wb); } int fb_delete_selection(struct file_buffer* fb) { - if (fb->mode & FB_SELECTION_ON) { - fb_remove_selection(fb); - wb_move_cursor_to_selection_start(focused_window); - fb->mode &= ~(FB_SELECTION_ON); - return 1; - } - return 0; + if (fb->mode & FB_SELECTION_ON) { + fb_remove_selection(fb); + wb_move_cursor_to_selection_start(focused_window); + fb->mode &= ~(FB_SELECTION_ON); + return 1; + } + return 0; } struct file_buffer fb_new(const char* file_path) { - struct file_buffer fb = {0}; - fb.file_path = xmalloc(PATH_MAX); + struct file_buffer fb = {0}; + fb.file_path = xmalloc(PATH_MAX); + + char* res = realpath(file_path, fb.file_path); + if (!res) { + char* path = file_path_get_path(file_path); + recursive_mkdir(path); + free(path); + + FILE *new_file = fopen(file_path, "wb"); + fclose(new_file); + realpath(file_path, fb.file_path); + remove(file_path); + + writef_to_status_bar("opened new file %s", fb.file_path); + } else if (path_is_folder(fb.file_path)) { + int len = strlen(fb.file_path); + if (fb.file_path[len-1] != '/' && len < PATH_MAX-1) { + fb.file_path[len] = '/'; + fb.file_path[len+1] = '\0'; + } + } else { + FILE *file = fopen(fb.file_path, "rb"); + if (file) { + fseek(file, 0L, SEEK_END); + long readsize = ftell(file); + rewind(file); + + if (readsize > (long)1.048576e+7) { + fclose(file); + die("you are opening a huge file(>10MiB), not allowed"); + return fb; + // TODO: don't crash + } + + fb.len = readsize; + fb.capacity = readsize + 100; + + fb.contents = xmalloc(fb.capacity); + fb.contents[0] = 0; + + char bom[4] = {0}; + fread(bom, 1, 3, file); + if (strcmp(bom, "\xEF\xBB\xBF")) + rewind(file); + else + fb.mode |= FB_UTF8_SIGNED; + fread(fb.contents, 1, readsize, file); + fclose(file); + + fb.syntax_index = -1; + } + } - char* res = realpath(file_path, fb.file_path); - if (!res) { - char* path = file_path_get_path(file_path); - recursive_mkdir(path); - free(path); + if (!fb.capacity) + fb.capacity = 100; + if (!fb.contents) { + fb.contents = xmalloc(fb.capacity); + memset(fb.contents, 0, fb.capacity); + } + fb.ub = xmalloc(sizeof(struct undo_buffer) * UNDO_BUFFERS_COUNT); + fb.search_term = xmalloc(SEARCH_TERM_MAX_LEN); + fb.non_blocking_search_term = xmalloc(SEARCH_TERM_MAX_LEN); + memset(fb.ub, 0, sizeof(struct undo_buffer) * UNDO_BUFFERS_COUNT); + memset(fb.search_term, 0, SEARCH_TERM_MAX_LEN); + memset(fb.non_blocking_search_term, 0, SEARCH_TERM_MAX_LEN); + fb.indent_len = default_indent_len; + + // change line endings + int offset = 0; + while((offset = fb_seek_string(&fb, offset, "\r\n")) >= 0) + fb_remove(&fb, offset, 1, 1, 1); + offset = 0; + while((offset = fb_seek_char(&fb, offset, '\r')) >= 0) + fb_change(&fb, "\n", 1, offset, 1); - FILE *new_file = fopen(file_path, "wb"); - fclose(new_file); - realpath(file_path, fb.file_path); - remove(file_path); - - writef_to_status_bar("opened new file %s", fb.file_path); - } else if (path_is_folder(fb.file_path)) { - int len = strlen(fb.file_path); - if (fb.file_path[len-1] != '/' && len < PATH_MAX-1) { - fb.file_path[len] = '/'; - fb.file_path[len+1] = '\0'; - } - } else { - FILE *file = fopen(fb.file_path, "rb"); - if (file) { - fseek(file, 0L, SEEK_END); - long readsize = ftell(file); - rewind(file); - - if (readsize > (long)1.048576e+7) { - fclose(file); - die("you are opening a huge file(>10MiB), not allowed"); - return fb; - // TODO: don't crash - } - - fb.len = readsize; - fb.capacity = readsize + 100; - - fb.contents = xmalloc(fb.capacity); - fb.contents[0] = 0; - - char bom[4] = {0}; - fread(bom, 1, 3, file); - if (strcmp(bom, "\xEF\xBB\xBF")) - rewind(file); - else - fb.mode |= FB_UTF8_SIGNED; - fread(fb.contents, 1, readsize, file); - fclose(file); - - fb.syntax_index = -1; - } - } - - if (!fb.capacity) - fb.capacity = 100; - if (!fb.contents) { - fb.contents = xmalloc(fb.capacity); - memset(fb.contents, 0, fb.capacity); - } - fb.ub = xmalloc(sizeof(struct undo_buffer) * UNDO_BUFFERS_COUNT); - fb.search_term = xmalloc(SEARCH_TERM_MAX_LEN); - fb.non_blocking_search_term = xmalloc(SEARCH_TERM_MAX_LEN); - memset(fb.ub, 0, sizeof(struct undo_buffer) * UNDO_BUFFERS_COUNT); - memset(fb.search_term, 0, SEARCH_TERM_MAX_LEN); - memset(fb.non_blocking_search_term, 0, SEARCH_TERM_MAX_LEN); - fb.indent_len = default_indent_len; - - // change line endings - int offset = 0; - while((offset = fb_seek_string(&fb, offset, "\r\n")) >= 0) - fb_remove(&fb, offset, 1, 1, 1); - offset = 0; - while((offset = fb_seek_char(&fb, offset, '\r')) >= 0) - fb_change(&fb, "\n", 1, offset, 1); - - call_extension(fb_new_file_opened, &fb); - - call_extension(fb_contents_updated, &fb, 0, FB_CONTENT_INIT); - - if (res) - writef_to_status_bar("new fb %s", fb.file_path); - return fb; + call_extension(fb_new_file_opened, &fb); + + call_extension(fb_contents_updated, &fb, 0, FB_CONTENT_INIT); + + if (res) + writef_to_status_bar("new fb %s", fb.file_path); + return fb; } int fb_new_entry(const char* file_path) { - static char full_path[PATH_MAX]; - if (!file_path) - file_path = "./"; - soft_assert(strlen(file_path) < PATH_MAX, file_path = "./";); - - char* res = realpath(file_path, full_path); - - if (available_buffer_slots) { - if (res) { - for(int n = 0; n < available_buffer_slots; n++) { - if (file_buffers[n].contents) { - if (strcmp(file_buffers[n].file_path, full_path) == 0) { - writef_to_status_bar("buffer exits"); - return n; - } + static char full_path[PATH_MAX]; + if (!file_path) + file_path = "./"; + soft_assert(strlen(file_path) < PATH_MAX, file_path = "./";); + + char* res = realpath(file_path, full_path); + + if (available_buffer_slots) { + if (res) { + for(int n = 0; n < available_buffer_slots; n++) { + if (file_buffers[n].contents) { + if (strcmp(file_buffers[n].file_path, full_path) == 0) { + writef_to_status_bar("buffer exits"); + return n; + } + } + } + } else { + strcpy(full_path, file_path); } - } - } else { - strcpy(full_path, file_path); - } - for(int n = 0; n < available_buffer_slots; n++) { - if (!file_buffers[n].contents) { - if (is_file_type(full_path, ".seproj")) - return open_seproj(fb_new(full_path)); - file_buffers[n] = fb_new(full_path); - return n; - } + for(int n = 0; n < available_buffer_slots; n++) { + if (!file_buffers[n].contents) { + if (is_file_type(full_path, ".seproj")) + return open_seproj(fb_new(full_path)); + file_buffers[n] = fb_new(full_path); + return n; + } + } } - } - if (is_file_type(full_path, ".seproj")) - return open_seproj(fb_new(full_path)); + if (is_file_type(full_path, ".seproj")) + return open_seproj(fb_new(full_path)); - available_buffer_slots++; - file_buffers = xrealloc(file_buffers, sizeof(struct file_buffer) * available_buffer_slots); - file_buffers[available_buffer_slots-1] = fb_new(full_path); + available_buffer_slots++; + file_buffers = xrealloc(file_buffers, sizeof(struct file_buffer) * available_buffer_slots); + file_buffers[available_buffer_slots-1] = fb_new(full_path); - return available_buffer_slots-1; + return available_buffer_slots-1; } void fb_destroy(struct file_buffer* fb) { - free(fb->ub); - free(fb->contents); - free(fb->file_path); - free(fb->search_term); - free(fb->non_blocking_search_term); - *fb = (struct file_buffer){0}; + free(fb->ub); + free(fb->contents); + free(fb->file_path); + free(fb->search_term); + free(fb->non_blocking_search_term); + *fb = (struct file_buffer){0}; } void fb_insert(struct file_buffer* fb, const char* new_content, const int len, const int offset, int do_not_callback) { - soft_assert(fb, return;); - soft_assert(fb->contents, fb->capacity = 0;); - soft_assert(offset <= fb->len && offset >= 0, - fprintf(stderr, "writing past fb%s\n", fb->file_path); - return; - ); + soft_assert(fb, return;); + soft_assert(fb->contents, fb->capacity = 0;); + soft_assert(offset <= fb->len && offset >= 0, + fprintf(stderr, "writing past fb '%s'\n", fb->file_path); + return; + ); - if (fb->len + len >= fb->capacity) { - fb->capacity = fb->len + len + 256; - fb->contents = xrealloc(fb->contents, fb->capacity); - } - if (offset < fb->len) - memmove(fb->contents+offset+len, fb->contents+offset, fb->len-offset); - fb->len += len; + if (fb->len + len >= fb->capacity) { + fb->capacity = fb->len + len + 256; + fb->contents = xrealloc(fb->contents, fb->capacity); + } + if (offset < fb->len) + memmove(fb->contents+offset+len, fb->contents+offset, fb->len-offset); + fb->len += len; - memcpy(fb->contents+offset, new_content, len); - if (!do_not_callback) - call_extension(fb_contents_updated, fb, offset, FB_CONTENT_NORMAL_EDIT); + memcpy(fb->contents+offset, new_content, len); + if (!do_not_callback) + call_extension(fb_contents_updated, fb, offset, FB_CONTENT_NORMAL_EDIT); } void fb_change(struct file_buffer* fb, const char* new_content, const int len, const int offset, int do_not_callback) { - soft_assert(offset <= fb->len && offset >= 0, return;); + soft_assert(offset <= fb->len && offset >= 0, return;); - if (offset + len > fb->len) { - fb->len = offset + len; - if (fb->len >= fb->capacity) { - fb->capacity = fb->len + len + 256; - fb->contents = xrealloc(fb->contents, fb->capacity); + if (offset + len > fb->len) { + fb->len = offset + len; + if (fb->len >= fb->capacity) { + fb->capacity = fb->len + len + 256; + fb->contents = xrealloc(fb->contents, fb->capacity); + } } - } - memcpy(fb->contents+offset, new_content, len); - if (!do_not_callback) - call_extension(fb_contents_updated, fb, offset, FB_CONTENT_NORMAL_EDIT); + memcpy(fb->contents+offset, new_content, len); + if (!do_not_callback) + call_extension(fb_contents_updated, fb, offset, FB_CONTENT_NORMAL_EDIT); } int fb_remove(struct file_buffer* fb, int offset, int len, int do_not_calculate_charsize, int do_not_callback) { - LIMIT(offset, 0, fb->len-1); - if (len == 0) return 0; - soft_assert(fb->contents, return 0;); - soft_assert(offset + len <= fb->len, return 0;); - - int removed_len = 0; - if (do_not_calculate_charsize) { - removed_len = len; - } else { - while (len--) { - int charsize = utf8_decode_buffer(fb->contents + offset, fb->len - offset, NULL); - if (fb->len - charsize < 0) - return 0; - removed_len += charsize; + LIMIT(offset, 0, fb->len-1); + if (len == 0) return 0; + soft_assert(fb->contents, return 0;); + soft_assert(offset + len <= fb->len, return 0;); + + int removed_len = 0; + if (do_not_calculate_charsize) { + removed_len = len; + } else { + while (len--) { + int charsize = utf8_decode_buffer(fb->contents + offset, fb->len - offset, NULL); + if (fb->len - charsize < 0) + return 0; + removed_len += charsize; + } } - } - fb->len -= removed_len; - memmove(fb->contents+offset, fb->contents+offset+removed_len, fb->len-offset); - if (!do_not_callback) - call_extension(fb_contents_updated, fb, offset, FB_CONTENT_NORMAL_EDIT); - return removed_len; + fb->len -= removed_len; + memmove(fb->contents+offset, fb->contents+offset+removed_len, fb->len-offset); + if (!do_not_callback) + call_extension(fb_contents_updated, fb, offset, FB_CONTENT_NORMAL_EDIT); + return removed_len; } void wb_copy_ub_to_current(struct window_buffer* wb) { - struct file_buffer* fb = get_fb(wb); - struct undo_buffer* cub = &fb->ub[fb->current_undo_buffer]; + struct file_buffer* fb = get_fb(wb); + struct undo_buffer* cub = &fb->ub[fb->current_undo_buffer]; - fb->contents = xrealloc(fb->contents, cub->capacity); - memcpy(fb->contents, cub->contents, cub->capacity); - fb->len = cub->len; - fb->capacity = cub->capacity; + fb->contents = xrealloc(fb->contents, cub->capacity); + memcpy(fb->contents, cub->contents, cub->capacity); + fb->len = cub->len; + fb->capacity = cub->capacity; - wb_move_to_offset(wb, cub->cursor_offset, CURSOR_SNAPPED); - //TODO: remove y_scroll from undo buffer - wb->y_scroll = cub->y_scroll; + wb_move_to_offset(wb, cub->cursor_offset, CURSOR_SNAPPED); + //TODO: remove y_scroll from undo buffer + wb->y_scroll = cub->y_scroll; } void fb_undo(struct file_buffer* fb) { - if (fb->current_undo_buffer == 0) { - writef_to_status_bar("end of undo buffer"); - return; - } - fb->current_undo_buffer--; - fb->available_redo_buffers++; + if (fb->current_undo_buffer == 0) { + writef_to_status_bar("end of undo buffer"); + return; + } + fb->current_undo_buffer--; + fb->available_redo_buffers++; - wb_copy_ub_to_current(focused_window); - writef_to_status_bar("undo"); + wb_copy_ub_to_current(focused_window); + writef_to_status_bar("undo"); } void fb_redo(struct file_buffer* fb) { - if (fb->available_redo_buffers == 0) { - writef_to_status_bar("end of redo buffer"); - return; - } - fb->available_redo_buffers--; - fb->current_undo_buffer++; + if (fb->available_redo_buffers == 0) { + writef_to_status_bar("end of redo buffer"); + return; + } + fb->available_redo_buffers--; + fb->current_undo_buffer++; - wb_copy_ub_to_current(focused_window); - writef_to_status_bar("redo"); + wb_copy_ub_to_current(focused_window); + writef_to_status_bar("redo"); } void fb_add_to_undo(struct file_buffer* fb, int offset, enum buffer_content_reason reason) { - static time_t last_normal_edit; - static int edits; + static time_t last_normal_edit; + static int edits; - if (reason == FB_CONTENT_CURSOR_MOVE) { - struct undo_buffer* cub = &fb->ub[fb->current_undo_buffer]; - cub->cursor_offset = offset; - if (focused_window) - cub->y_scroll = focused_window->y_scroll; - else - cub->y_scroll = 0; - return; - } + if (reason == FB_CONTENT_CURSOR_MOVE) { + struct undo_buffer* cub = &fb->ub[fb->current_undo_buffer]; + cub->cursor_offset = offset; + if (focused_window) + cub->y_scroll = focused_window->y_scroll; + else + cub->y_scroll = 0; + return; + } - if (reason == FB_CONTENT_NORMAL_EDIT) { - time_t previous_time = last_normal_edit; - last_normal_edit = time(NULL); + if (reason == FB_CONTENT_NORMAL_EDIT) { + time_t previous_time = last_normal_edit; + last_normal_edit = time(NULL); - if (last_normal_edit - previous_time < 2 && edits < 30) { - edits++; - goto copy_undo_buffer; + if (last_normal_edit - previous_time < 2 && edits < 30) { + edits++; + goto copy_undo_buffer; + } else { + edits = 0; + } + } else if (reason == FB_CONTENT_INIT) { + goto copy_undo_buffer; + } + + fb->available_redo_buffers = 0; + if (fb->current_undo_buffer == UNDO_BUFFERS_COUNT-1) { + char* begin_buffer = fb->ub[0].contents; + memmove(fb->ub, &(fb->ub[1]), (UNDO_BUFFERS_COUNT-1) * sizeof(struct undo_buffer)); + fb->ub[fb->current_undo_buffer].contents = begin_buffer; } else { - edits = 0; - } - } else if (reason == FB_CONTENT_INIT) { - goto copy_undo_buffer; - } - - fb->available_redo_buffers = 0; - if (fb->current_undo_buffer == UNDO_BUFFERS_COUNT-1) { - char* begin_buffer = fb->ub[0].contents; - memmove(fb->ub, &(fb->ub[1]), (UNDO_BUFFERS_COUNT-1) * sizeof(struct undo_buffer)); - fb->ub[fb->current_undo_buffer].contents = begin_buffer; - } else { - fb->current_undo_buffer++; - } + fb->current_undo_buffer++; + } copy_undo_buffer: ; - struct undo_buffer* cub = fb->ub + fb->current_undo_buffer; + struct undo_buffer* cub = fb->ub + fb->current_undo_buffer; - cub->contents = xrealloc(cub->contents, fb->capacity); - memcpy(cub->contents, fb->contents, fb->capacity); - cub->len = fb->len; - cub->capacity = fb->capacity; - cub->cursor_offset = offset; - if (focused_window) - cub->y_scroll = focused_window->y_scroll; - else - cub->y_scroll = 0; + cub->contents = xrealloc(cub->contents, fb->capacity); + memcpy(cub->contents, fb->contents, fb->capacity); + cub->len = fb->len; + cub->capacity = fb->capacity; + cub->cursor_offset = offset; + if (focused_window) + cub->y_scroll = focused_window->y_scroll; + else + cub->y_scroll = 0; } char* fb_get_string_between_offsets(struct file_buffer* fb, int start, int end) { - int len = end - start; + int len = end - start; - char* string = xmalloc(len + 1); - memcpy(string, fb->contents+start, len); - string[len] = 0; - return string; + char* string = xmalloc(len + 1); + memcpy(string, fb->contents+start, len); + string[len] = 0; + return string; } char* fb_get_selection(struct file_buffer* fb, int* selection_len) { - if (!(fb->mode & FB_SELECTION_ON)) - return NULL; + if (!(fb->mode & FB_SELECTION_ON)) + return NULL; - int start, end; - if (fb_is_selection_start_top_left(fb)) { - start = fb->s1o; - end = fb->s2o+1; - } else { - start = fb->s2o; - end = fb->s1o+1; - } - if (selection_len) - *selection_len = end - start; - return fb_get_string_between_offsets(fb, start, end); + int start, end; + if (fb_is_selection_start_top_left(fb)) { + start = fb->s1o; + end = fb->s2o+1; + } else { + start = fb->s2o; + end = fb->s1o+1; + } + if (selection_len) + *selection_len = end - start; + return fb_get_string_between_offsets(fb, start, end); } int fb_is_selection_start_top_left(const struct file_buffer* fb) { - return (fb->s1o <= fb->s2o) ? 1 : 0; + return (fb->s1o <= fb->s2o) ? 1 : 0; } void fb_remove_selection(struct file_buffer* buffer) { - if (!(buffer->mode & FB_SELECTION_ON)) - return; + if (!(buffer->mode & FB_SELECTION_ON)) + return; - int start, end, len; - if (fb_is_selection_start_top_left(buffer)) { - start = buffer->s1o; - end = buffer->s2o+1; - } else { - start = buffer->s2o; - end = buffer->s1o+1; - } - len = end - start; - fb_remove(buffer, start, len, 1, 1); - call_extension(fb_contents_updated, buffer, start, FB_CONTENT_BIG_CHANGE); + int start, end, len; + if (fb_is_selection_start_top_left(buffer)) { + start = buffer->s1o; + end = buffer->s2o+1; + } else { + start = buffer->s2o; + end = buffer->s1o+1; + } + len = end - start; + fb_remove(buffer, start, len, 1, 1); + call_extension(fb_contents_updated, buffer, start, FB_CONTENT_BIG_CHANGE); } char* fb_get_line_at_offset(const struct file_buffer* fb, int offset) { - int start = fb_seek_char_backwards(fb, offset, '\n'); - if (start < 0) start = 0; - int end = fb_seek_char(fb, offset, '\n'); - if (end < 0) end = fb->len-1; + int start = fb_seek_char_backwards(fb, offset, '\n'); + if (start < 0) start = 0; + int end = fb_seek_char(fb, offset, '\n'); + if (end < 0) end = fb->len-1; - int len = end - start; + int len = end - start; - char* res = xmalloc(len + 1); - if (len > 0) - memcpy(res, fb->contents+start, len); - res[len] = 0; - return res; + char* res = xmalloc(len + 1); + if (len > 0) + memcpy(res, fb->contents+start, len); + res[len] = 0; + return res; } void fb_offset_to_xy(struct file_buffer* fb, int offset, int maxx, int y_scroll, int* cx, int* cy, int* xscroll) { - *cx = *cy = *xscroll = 0; - soft_assert(fb, return;); + *cx = *cy = *xscroll = 0; + soft_assert(fb, return;); - if (fb->len <= 0) - return; - LIMIT(offset, 0, fb->len); - - char* repl = fb->contents; - char* last = repl + offset; - - char* new_repl; - if (wrap_buffer && maxx > 0) { - int yscroll = 0; - while ((new_repl = memchr(repl, '\n', last - repl))) { - if (++yscroll >= y_scroll) - break; - repl = new_repl+1; - } - *cy = yscroll - y_scroll; - } else { - while ((new_repl = memchr(repl, '\n', last - repl))) { - repl = new_repl+1; - *cy += 1; + if (fb->len <= 0) + return; + LIMIT(offset, 0, fb->len); + + char* repl = fb->contents; + char* last = repl + offset; + + char* new_repl; + if (wrap_buffer && maxx > 0) { + int yscroll = 0; + while ((new_repl = memchr(repl, '\n', last - repl))) { + if (++yscroll >= y_scroll) + break; + repl = new_repl+1; + } + *cy = yscroll - y_scroll; + } else { + while ((new_repl = memchr(repl, '\n', last - repl))) { + repl = new_repl+1; + *cy += 1; + } + *cy -= y_scroll; } - *cy -= y_scroll; - } - while (repl < last) { - if (wrap_buffer && maxx > 0 && (*repl == '\n' || *cx >= maxx)) { - *cy += 1; - *cx = 0; - repl++; - continue; - } - if (*repl == '\t') { - repl++; - if (*cx <= 0) *cx += 1; - while (*cx % tabspaces != 0) *cx += 1; - *cx += 1; - continue; + while (repl < last) { + if (wrap_buffer && maxx > 0 && (*repl == '\n' || *cx >= maxx)) { + *cy += 1; + *cx = 0; + repl++; + continue; + } + if (*repl == '\t') { + repl++; + if (*cx <= 0) *cx += 1; + while (*cx % tabspaces != 0) *cx += 1; + *cx += 1; + continue; + } + rune_t u; + repl += utf8_decode_buffer(repl, last - repl, &u); + *cx += wcwidth(u); } - rune_t u; - repl += utf8_decode_buffer(repl, last - repl, &u); - *cx += wcwidth(u); - } - // TODO: make customizable - // -1 = wrap, >= 0 is padding or something like that - const int padding = 3; + // TODO: make customizable + // -1 = wrap, >= 0 is padding or something like that + const int padding = 3; - if ((*cx - maxx) + padding > 0) - *xscroll = (*cx - maxx) + padding; + if ((*cx - maxx) + padding > 0) + *xscroll = (*cx - maxx) + padding; } //////////////////////////////////////////////// @@ -621,135 +621,135 @@ fb_offset_to_xy(struct file_buffer* fb, int offset, int maxx, int y_scroll, int* struct window_buffer wb_new(int fb_index) { - struct window_buffer wb = {0}; - wb.fb_index = fb_index; - if (path_is_folder(get_fb(&wb)->file_path)) { - wb.mode = WB_FILE_BROWSER; - writef_to_status_bar("opened file browser %s", get_fb(&wb)->file_path); - } + struct window_buffer wb = {0}; + wb.fb_index = fb_index; + if (path_is_folder(get_fb(&wb)->file_path)) { + wb.mode = WB_FILE_BROWSER; + writef_to_status_bar("opened file browser %s", get_fb(&wb)->file_path); + } - return wb; + return wb; } void wb_move_on_line(struct window_buffer* wb, int amount, enum cursor_reason callback_reason) { - const struct file_buffer* fb = get_fb(wb); - if (fb->len <= 0) - return; + const struct file_buffer* fb = get_fb(wb); + if (fb->len <= 0) + return; - if (amount < 0) { - while (wb->cursor_offset > 0 && fb->contents[wb->cursor_offset - 1] != '\n' && amount < 0) { - wb->cursor_offset--; - if ((fb->contents[wb->cursor_offset] & 0xC0) == 0x80) // if byte starts with 0b10 - continue; // byte is UTF-8 extender - amount++; - } - LIMIT(wb->cursor_offset, 0, fb->len); - } else if (amount > 0) { - for (int charsize = 0; - wb->cursor_offset < fb->len && amount > 0 && fb->contents[wb->cursor_offset + charsize] != '\n'; - wb->cursor_offset += charsize, amount--) { - rune_t u; - charsize = utf8_decode_buffer(fb->contents + wb->cursor_offset, fb->len - wb->cursor_offset, &u); - if (u != '\n' && u != '\t') - if (wcwidth(u) <= 0) - amount++; - if (wb->cursor_offset + charsize > fb->len) - break; + if (amount < 0) { + while (wb->cursor_offset > 0 && fb->contents[wb->cursor_offset - 1] != '\n' && amount < 0) { + wb->cursor_offset--; + if ((fb->contents[wb->cursor_offset] & 0xC0) == 0x80) // if byte starts with 0b10 + continue; // byte is UTF-8 extender + amount++; + } + LIMIT(wb->cursor_offset, 0, fb->len); + } else if (amount > 0) { + for (int charsize = 0; + wb->cursor_offset < fb->len && amount > 0 && fb->contents[wb->cursor_offset + charsize] != '\n'; + wb->cursor_offset += charsize, amount--) { + rune_t u; + charsize = utf8_decode_buffer(fb->contents + wb->cursor_offset, fb->len - wb->cursor_offset, &u); + if (u != '\n' && u != '\t') + if (wcwidth(u) <= 0) + amount++; + if (wb->cursor_offset + charsize > fb->len) + break; + } } - } - if (callback_reason) - call_extension(wb_cursor_movement, wb, callback_reason); + if (callback_reason) + call_extension(wb_cursor_movement, wb, callback_reason); } void wb_move_offset_relative(struct window_buffer* wb, int amount, enum cursor_reason callback_reason) { - //NOTE: this does not check if the character on this offset is the start of a valid utf8 char - const struct file_buffer* fb = get_fb((wb)); - if (fb->len <= 0) - return; - wb->cursor_offset += amount; - LIMIT(wb->cursor_offset, 0, fb->len); + //NOTE: this does not check if the character on this offset is the start of a valid utf8 char + const struct file_buffer* fb = get_fb((wb)); + if (fb->len <= 0) + return; + wb->cursor_offset += amount; + LIMIT(wb->cursor_offset, 0, fb->len); - if (callback_reason) - call_extension(wb_cursor_movement, wb, callback_reason); + if (callback_reason) + call_extension(wb_cursor_movement, wb, callback_reason); } void wb_move_lines(struct window_buffer* wb, int amount, enum cursor_reason callback_reason) { - const struct file_buffer* fb = get_fb((wb)); - if (fb->len <= 0) - return; - int offset = wb->cursor_offset; - if (amount > 0) { - while (amount-- && offset >= 0) { - int new_offset = fb_seek_char(fb, offset, '\n'); - if (new_offset < 0) { - offset = fb->len; - break; - } - offset = new_offset+1; - } - } else if (amount < 0) { - while (amount++ && offset >= 0) - offset = fb_seek_char_backwards(fb, offset, '\n')-1; - } - wb_move_to_offset(wb, offset, callback_reason); + const struct file_buffer* fb = get_fb((wb)); + if (fb->len <= 0) + return; + int offset = wb->cursor_offset; + if (amount > 0) { + while (amount-- && offset >= 0) { + int new_offset = fb_seek_char(fb, offset, '\n'); + if (new_offset < 0) { + offset = fb->len; + break; + } + offset = new_offset+1; + } + } else if (amount < 0) { + while (amount++ && offset >= 0) + offset = fb_seek_char_backwards(fb, offset, '\n')-1; + } + wb_move_to_offset(wb, offset, callback_reason); } void wb_move_to_offset(struct window_buffer* wb, int offset, enum cursor_reason callback_reason) { - //NOTE: this does not check if the character on this offset is the start of a valid utf8 char - const struct file_buffer* fb = get_fb((wb)); - if (fb->len <= 0) - return; - LIMIT(offset, 0, fb->len); - wb->cursor_offset = offset; + //NOTE: this does not check if the character on this offset is the start of a valid utf8 char + const struct file_buffer* fb = get_fb((wb)); + if (fb->len <= 0) + return; + LIMIT(offset, 0, fb->len); + wb->cursor_offset = offset; - if (callback_reason) - call_extension(wb_cursor_movement, wb, callback_reason); + if (callback_reason) + call_extension(wb_cursor_movement, wb, callback_reason); } void wb_move_to_x(struct window_buffer* wb, int x, enum cursor_reason callback_reason) { - soft_assert(wb, return;); - struct file_buffer* fb = get_fb(wb); - - int offset = fb_seek_char_backwards(fb, wb->cursor_offset, '\n'); - if (offset < 0) - offset = 0; - wb_move_to_offset(wb, offset, 0); - - int x_counter = 0; - - while (offset < fb->len) { - if (fb->contents[offset] == '\t') { - offset++; - if (x_counter <= 0) x_counter += 1; - while (x_counter % tabspaces != 0) x_counter += 1; - x_counter += 1; - continue; - } else if (fb->contents[offset] == '\n') { - break; - } - rune_t u = 0; - int charsize = utf8_decode_buffer(fb->contents + offset, fb->len - offset, &u); - x_counter += wcwidth(u); - if (x_counter <= x) { - offset += charsize; - if (x_counter == x) - break; - } else { - break; + soft_assert(wb, return;); + struct file_buffer* fb = get_fb(wb); + + int offset = fb_seek_char_backwards(fb, wb->cursor_offset, '\n'); + if (offset < 0) + offset = 0; + wb_move_to_offset(wb, offset, 0); + + int x_counter = 0; + + while (offset < fb->len) { + if (fb->contents[offset] == '\t') { + offset++; + if (x_counter <= 0) x_counter += 1; + while (x_counter % tabspaces != 0) x_counter += 1; + x_counter += 1; + continue; + } else if (fb->contents[offset] == '\n') { + break; + } + rune_t u = 0; + int charsize = utf8_decode_buffer(fb->contents + offset, fb->len - offset, &u); + x_counter += wcwidth(u); + if (x_counter <= x) { + offset += charsize; + if (x_counter == x) + break; + } else { + break; + } } - } - wb_move_to_offset(wb, offset, callback_reason); + wb_move_to_offset(wb, offset, callback_reason); } //////////////////////////////////////////////// @@ -759,173 +759,173 @@ wb_move_to_x(struct window_buffer* wb, int x, enum cursor_reason callback_reason static int is_correct_mode(enum window_split_mode mode, enum move_directons move) { - if (move == MOVE_RIGHT || move == MOVE_LEFT) - return (mode == WINDOW_HORISONTAL); - if (move == MOVE_UP || move == MOVE_DOWN) - return (mode == WINDOW_VERTICAL); - return 0; + if (move == MOVE_RIGHT || move == MOVE_LEFT) + return (mode == WINDOW_HORISONTAL); + if (move == MOVE_UP || move == MOVE_DOWN) + return (mode == WINDOW_VERTICAL); + return 0; } void window_node_split(struct window_split_node* parent, float ratio, enum window_split_mode mode) { - soft_assert(parent, return;); - soft_assert(parent->mode == WINDOW_SINGULAR, return;); - soft_assert(mode != WINDOW_SINGULAR, return;); - - if ((parent->maxx - parent->minx < MIN_WINDOW_SPLIT_SIZE_HORISONTAL && mode == WINDOW_HORISONTAL) - || (parent->maxy - parent->miny < MIN_WINDOW_SPLIT_SIZE_VERTICAL && mode == WINDOW_VERTICAL)) - return; - - parent->node1 = xmalloc(sizeof(struct window_split_node)); - *parent->node1 = *parent; - parent->node1->search = xmalloc(SEARCH_TERM_MAX_LEN); - parent->node1->parent = parent; - parent->node1->node1 = NULL; - parent->node1->node2 = NULL; - - - parent->node2 = xmalloc(sizeof(struct window_split_node)); - *parent->node2 = *parent; - parent->node2->search = xmalloc(SEARCH_TERM_MAX_LEN); - parent->node2->parent = parent; - parent->node2->node1 = NULL; - parent->node2->node2 = NULL; - - if (parent->mode == WINDOW_HORISONTAL) { - // NOTE: if the window resizing is changed, change in draw tree function as well - int middlex = ((float)(parent->maxx - parent->minx) * parent->ratio) + parent->minx; - parent->node1->minx = parent->minx; - parent->node1->miny = parent->miny; - parent->node1->maxx = middlex; - parent->node1->maxy = parent->maxy; - parent->node2->minx = middlex+2; - parent->node2->miny = parent->miny; - parent->node2->maxx = parent->maxx; - parent->node2->maxy = parent->maxy; - } else if (parent->mode == WINDOW_VERTICAL) { - // NOTE: if the window resizing is changed, change in draw tree function as well - int middley = ((float)(parent->maxy - parent->miny) * parent->ratio) + parent->miny; - parent->node1->minx = parent->minx; - parent->node1->miny = parent->miny; - parent->node1->maxx = parent->maxx; - parent->node1->maxy = middley; - parent->node2->minx = parent->miny; - parent->node2->miny = middley; - parent->node2->maxx = parent->maxx; - parent->node2->maxy = parent->maxy; - } - - parent->mode = mode; - parent->ratio = ratio; - parent->wb = (struct window_buffer){0}; + soft_assert(parent, return;); + soft_assert(parent->mode == WINDOW_SINGULAR, return;); + soft_assert(mode != WINDOW_SINGULAR, return;); + + if ((parent->maxx - parent->minx < MIN_WINDOW_SPLIT_SIZE_HORISONTAL && mode == WINDOW_HORISONTAL) + || (parent->maxy - parent->miny < MIN_WINDOW_SPLIT_SIZE_VERTICAL && mode == WINDOW_VERTICAL)) + return; + + parent->node1 = xmalloc(sizeof(struct window_split_node)); + *parent->node1 = *parent; + parent->node1->search = xmalloc(SEARCH_TERM_MAX_LEN); + parent->node1->parent = parent; + parent->node1->node1 = NULL; + parent->node1->node2 = NULL; + + + parent->node2 = xmalloc(sizeof(struct window_split_node)); + *parent->node2 = *parent; + parent->node2->search = xmalloc(SEARCH_TERM_MAX_LEN); + parent->node2->parent = parent; + parent->node2->node1 = NULL; + parent->node2->node2 = NULL; + + if (parent->mode == WINDOW_HORISONTAL) { + // NOTE: if the window resizing is changed, change in draw tree function as well + int middlex = ((float)(parent->maxx - parent->minx) * parent->ratio) + parent->minx; + parent->node1->minx = parent->minx; + parent->node1->miny = parent->miny; + parent->node1->maxx = middlex; + parent->node1->maxy = parent->maxy; + parent->node2->minx = middlex+2; + parent->node2->miny = parent->miny; + parent->node2->maxx = parent->maxx; + parent->node2->maxy = parent->maxy; + } else if (parent->mode == WINDOW_VERTICAL) { + // NOTE: if the window resizing is changed, change in draw tree function as well + int middley = ((float)(parent->maxy - parent->miny) * parent->ratio) + parent->miny; + parent->node1->minx = parent->minx; + parent->node1->miny = parent->miny; + parent->node1->maxx = parent->maxx; + parent->node1->maxy = middley; + parent->node2->minx = parent->miny; + parent->node2->miny = middley; + parent->node2->maxx = parent->maxx; + parent->node2->maxy = parent->maxy; + } + + parent->mode = mode; + parent->ratio = ratio; + parent->wb = (struct window_buffer){0}; } struct window_split_node* window_node_delete(struct window_split_node* node) { - if (!node->parent) { - writef_to_status_bar("can't close root winodw"); - return node; - } - struct window_split_node* old = node; - node = node->parent; - struct window_split_node* other = (node->node1 == old) ? node->node2 : node->node1; - free(old->search); - free(old); - - struct window_split_node* parent = node->parent; - *node = *other; - if (other->mode != WINDOW_SINGULAR) { - other->node1->parent = node; - other->node2->parent = node; - } - free(other); - node->parent = parent; + if (!node->parent) { + writef_to_status_bar("can't close root winodw"); + return node; + } + struct window_split_node* old = node; + node = node->parent; + struct window_split_node* other = (node->node1 == old) ? node->node2 : node->node1; + free(old->search); + free(old); + + struct window_split_node* parent = node->parent; + *node = *other; + if (other->mode != WINDOW_SINGULAR) { + other->node1->parent = node; + other->node2->parent = node; + } + free(other); + node->parent = parent; - return node; + return node; } void window_node_draw_tree_to_screen(struct window_split_node* root, int minx, int miny, int maxx, int maxy) { - soft_assert(root, return;); - - if (root->mode == WINDOW_SINGULAR) { - LIMIT(maxx, 0, screen.col-1); - LIMIT(maxy, 0, screen.row-1); - LIMIT(minx, 0, maxx); - LIMIT(miny, 0, maxy); - root->minx = minx; - root->miny = miny; - root->maxx = maxx; - root->maxy = maxy; - if (root->wb.mode != 0) { - int wn_custom_window_draw_callback_exists = 0; - extension_callback_exists(wn_custom_window_draw, wn_custom_window_draw_callback_exists = 1;); - soft_assert(wn_custom_window_draw_callback_exists, return;); - - call_extension(wn_custom_window_draw, root); - - return; - } else { - window_node_draw_to_screen(root); - } - } else if (root->mode == WINDOW_HORISONTAL) { - // NOTE: if the window resizing is changed, change in split function as well - int middlex = ((float)(maxx - minx) * root->ratio) + minx; + soft_assert(root, return;); + + if (root->mode == WINDOW_SINGULAR) { + LIMIT(maxx, 0, screen.col-1); + LIMIT(maxy, 0, screen.row-1); + LIMIT(minx, 0, maxx); + LIMIT(miny, 0, maxy); + root->minx = minx; + root->miny = miny; + root->maxx = maxx; + root->maxy = maxy; + if (root->wb.mode != 0) { + int wn_custom_window_draw_callback_exists = 0; + extension_callback_exists(wn_custom_window_draw, wn_custom_window_draw_callback_exists = 1;); + soft_assert(wn_custom_window_draw_callback_exists, return;); + + call_extension(wn_custom_window_draw, root); + + return; + } else { + window_node_draw_to_screen(root); + } + } else if (root->mode == WINDOW_HORISONTAL) { + // NOTE: if the window resizing is changed, change in split function as well + int middlex = ((float)(maxx - minx) * root->ratio) + minx; - // print seperator - screen_set_region(middlex+1, miny, middlex+1, maxy, L'│'); + // print seperator + screen_set_region(middlex+1, miny, middlex+1, maxy, L'│'); - window_node_draw_tree_to_screen(root->node1, minx, miny, middlex, maxy); - window_node_draw_tree_to_screen(root->node2, middlex+2, miny, maxx, maxy); + window_node_draw_tree_to_screen(root->node1, minx, miny, middlex, maxy); + window_node_draw_tree_to_screen(root->node2, middlex+2, miny, maxx, maxy); - for (int y = miny; y < maxy+1; y++) - xdrawline(middlex+1, y, middlex+2); - } else if (root->mode == WINDOW_VERTICAL) { - // NOTE: if the window resizing is changed, change in split function as well - int middley = ((float)(maxy - miny) * root->ratio) + miny; + for (int y = miny; y < maxy+1; y++) + xdrawline(middlex+1, y, middlex+2); + } else if (root->mode == WINDOW_VERTICAL) { + // NOTE: if the window resizing is changed, change in split function as well + int middley = ((float)(maxy - miny) * root->ratio) + miny; - window_node_draw_tree_to_screen(root->node1, minx, miny, maxx, middley); - window_node_draw_tree_to_screen(root->node2, minx, middley, maxx, maxy); - } + window_node_draw_tree_to_screen(root->node1, minx, miny, maxx, middley); + window_node_draw_tree_to_screen(root->node2, minx, middley, maxx, maxy); + } } void window_node_move_all_cursors_on_same_fb(struct window_split_node* root, struct window_split_node* excluded, int fb_index, int offset, - void(movement)(struct window_buffer*, int, enum cursor_reason), - int move, enum cursor_reason reason) + void(movement)(struct window_buffer*, int, enum cursor_reason), + int move, enum cursor_reason reason) { - if (root->mode == WINDOW_SINGULAR) { - if (root->wb.fb_index == fb_index && root->wb.cursor_offset >= offset && root != excluded) - movement(&root->wb, move, reason); - } else { - window_node_move_all_cursors_on_same_fb(root->node1, excluded, fb_index, offset, movement, move, reason); - window_node_move_all_cursors_on_same_fb(root->node2, excluded, fb_index, offset, movement, move, reason); - } + if (root->mode == WINDOW_SINGULAR) { + if (root->wb.fb_index == fb_index && root->wb.cursor_offset >= offset && root != excluded) + movement(&root->wb, move, reason); + } else { + window_node_move_all_cursors_on_same_fb(root->node1, excluded, fb_index, offset, movement, move, reason); + window_node_move_all_cursors_on_same_fb(root->node2, excluded, fb_index, offset, movement, move, reason); + } } void window_node_move_all_yscrolls(struct window_split_node* root, struct window_split_node* excluded, int fb_index, int offset, int move) { - if (root->mode == WINDOW_SINGULAR) { - if (root->wb.fb_index == fb_index && root->wb.cursor_offset >= offset && root != excluded) - root->wb.y_scroll += move; - } else { - window_node_move_all_yscrolls(root->node1, excluded, fb_index, offset, move); - window_node_move_all_yscrolls(root->node2, excluded, fb_index, offset, move); - } + if (root->mode == WINDOW_SINGULAR) { + if (root->wb.fb_index == fb_index && root->wb.cursor_offset >= offset && root != excluded) + root->wb.y_scroll += move; + } else { + window_node_move_all_yscrolls(root->node1, excluded, fb_index, offset, move); + window_node_move_all_yscrolls(root->node2, excluded, fb_index, offset, move); + } } int window_other_nodes_contain_fb(struct window_split_node* node, struct window_split_node* root) { - if (root->mode == WINDOW_SINGULAR) - return (root->wb.fb_index == node->wb.fb_index && root != node); + if (root->mode == WINDOW_SINGULAR) + return (root->wb.fb_index == node->wb.fb_index && root != node); - return (window_other_nodes_contain_fb(node, root->node1) || - window_other_nodes_contain_fb(node, root->node2)); + return (window_other_nodes_contain_fb(node, root->node1) || + window_other_nodes_contain_fb(node, root->node2)); } // TODO: create a distance type function and use that instead (from the current cursor position)? @@ -933,66 +933,66 @@ window_other_nodes_contain_fb(struct window_split_node* node, struct window_spli struct window_split_node* window_switch_to_window(struct window_split_node* node, enum move_directons move) { - soft_assert(node, return &root_node;); - if (!node->parent) return node; - soft_assert(node->mode == WINDOW_SINGULAR, - while(node->mode != WINDOW_SINGULAR) - node = node->node1; - return node; - ); - struct window_split_node* old_node = node; - - if (move == MOVE_RIGHT || move == MOVE_DOWN) { - // traverse up the tree to the right - for (; node->parent; node = node->parent) { - if (is_correct_mode(node->parent->mode, move) && node->parent->node1 == node) { - // traverse down until a screen is found - node = node->parent->node2; - while(node->mode != WINDOW_SINGULAR) - node = node->node1; - - return node; - } - } - } else if (move == MOVE_LEFT || move == MOVE_UP) { - // traverse up the tree to the left - for (; node->parent; node = node->parent) { - if (is_correct_mode(node->parent->mode, move) && node->parent->node2 == node) { - // traverse down until a screen is found - node = node->parent->node1; - while(node->mode != WINDOW_SINGULAR) - node = node->node2; - - return node; - } + soft_assert(node, return &root_node;); + if (!node->parent) return node; + soft_assert(node->mode == WINDOW_SINGULAR, + while(node->mode != WINDOW_SINGULAR) + node = node->node1; + return node; + ); + struct window_split_node* old_node = node; + + if (move == MOVE_RIGHT || move == MOVE_DOWN) { + // traverse up the tree to the right + for (; node->parent; node = node->parent) { + if (is_correct_mode(node->parent->mode, move) && node->parent->node1 == node) { + // traverse down until a screen is found + node = node->parent->node2; + while(node->mode != WINDOW_SINGULAR) + node = node->node1; + + return node; + } + } + } else if (move == MOVE_LEFT || move == MOVE_UP) { + // traverse up the tree to the left + for (; node->parent; node = node->parent) { + if (is_correct_mode(node->parent->mode, move) && node->parent->node2 == node) { + // traverse down until a screen is found + node = node->parent->node1; + while(node->mode != WINDOW_SINGULAR) + node = node->node2; + + return node; + } + } } - } - return old_node; + return old_node; } void window_node_resize(struct window_split_node* node, enum move_directons move, float amount) { - for (; node; node = node->parent) { - if (is_correct_mode(node->mode, move)) { - float amount = (move == MOVE_RIGHT || move == MOVE_LEFT) ? 0.1f : 0.05f; - if (move == MOVE_RIGHT || move == MOVE_DOWN) amount = -amount; - node->ratio -= amount; - LIMIT(node->ratio, 0.001f, 0.95f); - return; + for (; node; node = node->parent) { + if (is_correct_mode(node->mode, move)) { + float amount = (move == MOVE_RIGHT || move == MOVE_LEFT) ? 0.1f : 0.05f; + if (move == MOVE_RIGHT || move == MOVE_DOWN) amount = -amount; + node->ratio -= amount; + LIMIT(node->ratio, 0.001f, 0.95f); + return; + } } - } } void window_node_resize_absolute(struct window_split_node* node, enum move_directons move, float amount) { - for (; node; node = node->parent) { - if (is_correct_mode(node->mode, move)) { - node->ratio = amount; - LIMIT(node->ratio, 0.001f, 0.95f); - return; + for (; node; node = node->parent) { + if (is_correct_mode(node->mode, move)) { + node->ratio = amount; + LIMIT(node->ratio, 0.001f, 0.95f); + return; + } } - } } diff --git a/buffer.h b/buffer.h @@ -24,52 +24,57 @@ extern struct window_buffer* focused_window; #define UNDO_BUFFERS_COUNT 128 struct undo_buffer { - char* contents; // not null terminated - int len, capacity; - int cursor_offset; - int y_scroll; + char* contents; // not null terminated + int len, capacity; + int cursor_offset; + int y_scroll; }; enum buffer_flags { - FB_SELECTION_ON = 1 << 0, - FB_BLOCK_SELECT = 1 << 1, - FB_LINE_SELECT = 1 << 2, - FB_SELECT_MASK = (FB_SELECTION_ON | FB_BLOCK_SELECT | FB_LINE_SELECT), - FB_SELECT_MODE_MASK = (FB_BLOCK_SELECT | FB_LINE_SELECT), - FB_READ_ONLY = 1 << 3, - FB_UTF8_SIGNED = 1 << 4, - FB_SEARCH_BLOCKING = 1 << 5, - FB_SEARCH_BLOCKING_IDLE = 1 << 6, - FB_SEARCH_BLOCKING_MASK = (FB_SEARCH_BLOCKING | FB_SEARCH_BLOCKING_IDLE), - FB_SEARCH_NON_BLOCKING = 1 << 7, - FB_SEARCH_BLOCKING_BACKWARDS = 1 << 8, - FB_SEARCH_NON_BLOCKING_BACKWARDS = 1 << 9, + FB_SELECTION_ON = 1 << 0, + FB_BLOCK_SELECT = 1 << 1, + FB_LINE_SELECT = 1 << 2, + FB_SELECT_MASK = (FB_SELECTION_ON | FB_BLOCK_SELECT | FB_LINE_SELECT), + FB_SELECT_MODE_MASK = (FB_BLOCK_SELECT | FB_LINE_SELECT), + FB_READ_ONLY = 1 << 3, + FB_UTF8_SIGNED = 1 << 4, + FB_SEARCH_BLOCKING = 1 << 5, + FB_SEARCH_BLOCKING_IDLE = 1 << 6, + FB_SEARCH_BLOCKING_MASK = (FB_SEARCH_BLOCKING | FB_SEARCH_BLOCKING_IDLE), + FB_SEARCH_NON_BLOCKING = 1 << 7, + FB_SEARCH_BLOCKING_BACKWARDS = 1 << 8, + FB_SEARCH_NON_BLOCKING_BACKWARDS = 1 << 9, }; struct file_buffer { - char* file_path; - char* contents; // !! NOT NULL TERMINATED !! - int len; - int capacity; - int mode; // buffer_flags - struct undo_buffer* ub; - // TODO: int file_buffer_len; - int current_undo_buffer; - int available_redo_buffers; - int s1o, s2o; // selection start offset and end offset - char* search_term; - char* non_blocking_search_term; - int syntax_index; - unsigned int indent_len; // amount of spaces, if 0 tab is used + char* file_path; + char* contents; // !! NOT NULL TERMINATED !! + int len; + int capacity; + int mode; // buffer_flags + struct undo_buffer* ub; + int current_undo_buffer; + int available_redo_buffers; + int s1o, s2o; // selection start offset and end offset + + // used for "ctrl+f" searches + char* search_term; + // used for vim-style f searches + char* non_blocking_search_term; + + unsigned int indent_len; // amount of spaces, if 0 tab is used + + // required by syntax.h, not used by anything else + int syntax_index; }; enum buffer_content_reason { - FB_CONTENT_DO_NOT_CALLBACK = 0, - FB_CONTENT_OPERATION_ENDED, - FB_CONTENT_NORMAL_EDIT, - FB_CONTENT_BIG_CHANGE, - FB_CONTENT_INIT, - FB_CONTENT_CURSOR_MOVE, + FB_CONTENT_DO_NOT_CALLBACK = 0, + FB_CONTENT_OPERATION_ENDED, + FB_CONTENT_NORMAL_EDIT, + FB_CONTENT_BIG_CHANGE, + FB_CONTENT_INIT, + FB_CONTENT_CURSOR_MOVE, }; struct file_buffer* get_fb(struct window_buffer* wb); @@ -118,28 +123,28 @@ void fb_offset_to_xy(struct file_buffer* fb, int offset, int maxx, int y_scroll, #define WB_MODES_DEFAULT_END 1 struct window_buffer { - int y_scroll; - int cursor_offset; - int cursor_col; - - int fb_index; // index into an array storing file buffers - - /////////////////////////////////// - // you may implement your own "modes" - // it will run a callback where you can render your window - // a callback allowing you to override the default input callback - // is also provided - // TODO:↑ - // see extensions/window_modes for other modes - unsigned int mode; // WB_NORMAL = 0 + int y_scroll; + int cursor_offset; + int cursor_col; + + int fb_index; // index into an array storing file buffers + + /////////////////////////////////// + // you may implement your own "modes" + // it will run a callback where you can render your window + // a callback allowing you to override the default input callback + // is also provided + // TODO:↑ + // see extensions/window_modes for other modes + unsigned int mode; // WB_NORMAL = 0 }; enum cursor_reason { - CURSOR_DO_NOT_CALLBACK = 0, - CURSOR_COMMAND_MOVEMENT = 1, - CURSOR_UP_DOWN_MOVEMENT, - CURSOR_RIGHT_LEFT_MOVEMENT, - CURSOR_SNAPPED, + CURSOR_DO_NOT_CALLBACK = 0, + CURSOR_COMMAND_MOVEMENT = 1, + CURSOR_UP_DOWN_MOVEMENT, + CURSOR_RIGHT_LEFT_MOVEMENT, + CURSOR_SNAPPED, }; struct window_buffer wb_new(int buffer_index); @@ -149,27 +154,27 @@ struct window_buffer wb_new(int buffer_index); // enum window_split_mode { - WINDOW_SINGULAR, - WINDOW_HORISONTAL, - WINDOW_VERTICAL, - WINDOW_FILE_BROWSER, + WINDOW_SINGULAR, + WINDOW_HORISONTAL, + WINDOW_VERTICAL, + WINDOW_FILE_BROWSER, }; struct window_split_node { - struct window_buffer wb; - enum window_split_mode mode; - float ratio; - struct window_split_node *node1, *node2, *parent; - int minx, miny, maxx, maxy; // position informatin from the last frame - char* search; - int selected; + struct window_buffer wb; + enum window_split_mode mode; + float ratio; + struct window_split_node *node1, *node2, *parent; + int minx, miny, maxx, maxy; // position informatin from the last frame + char* search; + int selected; }; enum move_directons { - MOVE_RIGHT, - MOVE_LEFT, - MOVE_UP, - MOVE_DOWN, + MOVE_RIGHT, + MOVE_LEFT, + MOVE_UP, + MOVE_DOWN, }; //////////////////////////////////////////////// diff --git a/extensions/syntax/gd.h b/extensions/syntax/gd.h @@ -1,99 +1,99 @@ #include "handy_defines.h" const struct syntax_scheme_entry gd_syntax[] = { - // Coloring type arguments Color + // Coloring type arguments Color - // strings + // strings #ifdef string_color - {COLOR_AROUND_TO_LINE, {"\"", "\""}, string_color}, - {COLOR_AROUND, {"\"\"\"", "\"\"\""}, string_color}, - {COLOR_AROUND_TO_LINE, {"'", "'"}, string_color}, - {COLOR_INSIDE_TO_LINE, {"$", "."}, string_color}, - {COLOR_INSIDE_TO_LINE, {"$", " "}, string_color}, - {COLOR_INSIDE_TO_LINE, {"$", "("}, string_color}, - {COLOR_INSIDE_TO_LINE, {"$", "["}, string_color}, - {COLOR_INSIDE_TO_LINE, {"$", "\n"}, string_color}, - {COLOR_STR, {"$"}, string_color}, + {COLOR_AROUND_TO_LINE, {"\"", "\""}, string_color}, + {COLOR_AROUND, {"\"\"\"", "\"\"\""}, string_color}, + {COLOR_AROUND_TO_LINE, {"'", "'"}, string_color}, + {COLOR_INSIDE_TO_LINE, {"$", "."}, string_color}, + {COLOR_INSIDE_TO_LINE, {"$", " "}, string_color}, + {COLOR_INSIDE_TO_LINE, {"$", "("}, string_color}, + {COLOR_INSIDE_TO_LINE, {"$", "["}, string_color}, + {COLOR_INSIDE_TO_LINE, {"$", "\n"}, string_color}, + {COLOR_STR, {"$"}, string_color}, #endif - // comments + // comments #ifdef comment_color - {COLOR_AROUND, {"#", "\n"}, comment_color}, + {COLOR_AROUND, {"#", "\n"}, comment_color}, #endif - // operators + // operators #ifdef operator_color - {COLOR_STR, {"!="}, normal_color}, - {COLOR_STR, {"!"}, operator_color}, + {COLOR_STR, {"!="}, normal_color}, + {COLOR_STR, {"!"}, operator_color}, #endif - // constants + // constants #ifdef constants_color - {COLOR_UPPER_CASE_WORD, {0}, constants_color}, - {COLOR_WORD, {"PI"}, constants_color}, - {COLOR_WORD, {"TAU"}, constants_color}, - {COLOR_WORD, {"INF"}, constants_color}, - {COLOR_WORD, {"NAN"}, constants_color}, - {COLOR_WORD, {"null"}, constants_color}, - {COLOR_WORD, {"true"}, constants_color}, - {COLOR_WORD, {"false"}, constants_color}, - {COLOR_STR_AFTER_WORD, {"const"}, constants_color}, + {COLOR_UPPER_CASE_WORD, {0}, constants_color}, + {COLOR_WORD, {"PI"}, constants_color}, + {COLOR_WORD, {"TAU"}, constants_color}, + {COLOR_WORD, {"INF"}, constants_color}, + {COLOR_WORD, {"NAN"}, constants_color}, + {COLOR_WORD, {"null"}, constants_color}, + {COLOR_WORD, {"true"}, constants_color}, + {COLOR_WORD, {"false"}, constants_color}, + {COLOR_STR_AFTER_WORD, {"const"}, constants_color}, #endif - // keywords + // keywords #ifdef keyword_color - color_keyword("extends"), color_keyword("class_name"), - color_keyword("var"), color_keyword("const"), - color_keyword("enum"), color_keyword("func"), - color_keyword("if"), color_keyword("else"), - color_keyword("elif"), color_keyword("for"), - color_keyword("while"), color_keyword("in"), - color_keyword("return"), color_keyword("class"), - color_keyword("pass"), color_keyword("continue"), - color_keyword("break"), color_keyword("is"), - color_keyword("as"), color_keyword("self"), - color_keyword("tool"), color_keyword("signal"), - color_keyword("static"), color_keyword("onready"), - color_keyword("export"), color_keyword("setget"), - color_keyword("breakpoint"), color_keyword("yield"), - color_keyword("assert"), color_keyword("preload"), - color_keyword("remote"), color_keyword("master"), - color_keyword("puppet"), color_keyword("remotesync"), - color_keyword("mastersync"), color_keyword("puppetsync"), - color_keyword("and"), color_keyword("or"), + color_keyword("extends"), color_keyword("class_name"), + color_keyword("var"), color_keyword("const"), + color_keyword("enum"), color_keyword("func"), + color_keyword("if"), color_keyword("else"), + color_keyword("elif"), color_keyword("for"), + color_keyword("while"), color_keyword("in"), + color_keyword("return"), color_keyword("class"), + color_keyword("pass"), color_keyword("continue"), + color_keyword("break"), color_keyword("is"), + color_keyword("as"), color_keyword("self"), + color_keyword("tool"), color_keyword("signal"), + color_keyword("static"), color_keyword("onready"), + color_keyword("export"), color_keyword("setget"), + color_keyword("breakpoint"), color_keyword("yield"), + color_keyword("assert"), color_keyword("preload"), + color_keyword("remote"), color_keyword("master"), + color_keyword("puppet"), color_keyword("remotesync"), + color_keyword("mastersync"), color_keyword("puppetsync"), + color_keyword("and"), color_keyword("or"), #endif - // functions + // functions #ifdef function_color - {COLOR_WORD_INSIDE, {"func ", "("}, macro_color}, - {COLOR_WORD_INSIDE, {"class ", ":"}, macro_color}, - {COLOR_WORD_BEFORE_STR, {"("}, function_color}, + {COLOR_WORD_INSIDE, {"func ", "("}, macro_color}, + {COLOR_WORD_INSIDE, {"class ", ":"}, macro_color}, + {COLOR_WORD_BEFORE_STR, {"("}, function_color}, #endif - // types + // types #ifdef type_color - color_type("bool"), color_type("int"), - color_type("float"), color_type("String"), - color_type("Vector2"), color_type("Rect2"), - color_type("Vector3"), color_type("Transform2D"), - color_type("Plane"), color_type("Quat"), - color_type("AABB"), color_type("Basis"), - color_type("Transform"), color_type("Color"), - color_type("NodePath"), color_type("RID"), - color_type("Object"), color_type("Array"), - color_type("PoolByteArray"), color_type("PoolIntArray"), - color_type("PoolRealArray"), color_type("PoolStringArray"), - color_type("PoolVector2Array"), color_type("PoolVector3Array"), - color_type("PoolColorArray"), color_type("Dictionary"), - color_type("Dictionary"), color_type("Node"), - color_type("void"), + color_type("bool"), color_type("int"), + color_type("float"), color_type("String"), + color_type("Vector2"), color_type("Rect2"), + color_type("Vector3"), color_type("Transform2D"), + color_type("Plane"), color_type("Quat"), + color_type("AABB"), color_type("Basis"), + color_type("Transform"), color_type("Color"), + color_type("NodePath"), color_type("RID"), + color_type("Object"), color_type("Array"), + color_type("PoolByteArray"), color_type("PoolIntArray"), + color_type("PoolRealArray"), color_type("PoolStringArray"), + color_type("PoolVector2Array"), color_type("PoolVector3Array"), + color_type("PoolColorArray"), color_type("Dictionary"), + color_type("Dictionary"), color_type("Node"), + color_type("void"), #endif - // numbers + // numbers #ifdef number_color - color_numbers(), + color_numbers(), #endif }; #define gd_word_seperators default_word_seperators const struct indent_scheme_entry gd_indent[] = { - {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"return"}}, - {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"break"}}, - {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"continue"}}, - {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"pass"}}, - {INDENT_NEW, INDENT_LINE_ENDS_WITH_STR, -1, {":"}}, + {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"return"}}, + {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"break"}}, + {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"continue"}}, + {INDENT_REMOVE, INDENT_LINE_CONTAINS_WORD, -1, {"pass"}}, + {INDENT_NEW, INDENT_LINE_ENDS_WITH_STR, -1, {":"}}, }; diff --git a/extensions/syntax/handy_defines.h b/extensions/syntax/handy_defines.h @@ -8,25 +8,25 @@ #endif #ifdef type_color -#define color_type(_str) {COLOR_WORD,{_str}, type_color} +#define color_type(_str) {COLOR_WORD,{_str}, type_color} #endif #ifdef number_color -#define color_number(_num) \ - {COLOR_WORD_STARTING_WITH_STR, {_num}, number_color}, \ - {COLOR_WORD_ENDING_WITH_STR, {_num".f"},number_color} +#define color_number(_num) \ + {COLOR_WORD_STARTING_WITH_STR, {_num}, number_color}, \ + {COLOR_WORD_ENDING_WITH_STR, {_num".f"},number_color} #endif -#define color_numbers() \ - color_number("0"), \ - color_number("1"), \ - color_number("2"), \ - color_number("3"), \ - color_number("4"), \ - color_number("5"), \ - color_number("6"), \ - color_number("7"), \ - color_number("8"), \ - color_number("9") +#define color_numbers() \ + color_number("0"), \ + color_number("1"), \ + color_number("2"), \ + color_number("3"), \ + color_number("4"), \ + color_number("5"), \ + color_number("6"), \ + color_number("7"), \ + color_number("8"), \ + color_number("9") #endif // HANDY_DEFINES_H_ diff --git a/extensions/syntax/syntax.h b/extensions/syntax/syntax.h @@ -16,92 +16,92 @@ static int fb_set_syntax_scheme(struct file_buffer* fb); static int apply_syntax(struct window_split_node* wn, const int offset_start, const int offset_end, uint8_t* move_buffer, const int move_buffer_len); static const struct extension syntax_e = { - .fb_new_file_opened = fb_set_syntax_scheme, - .window_written_to_screen = apply_syntax + .fb_new_file_opened = fb_set_syntax_scheme, + .window_written_to_screen = apply_syntax }; #define UPPER_CASE_WORD_MIN_LEN 3 enum syntax_scheme_mode { - // needs two strings - COLOR_AROUND, - // needs two strings - COLOR_AROUND_TO_LINE, - // needs two strings - COLOR_INSIDE, - // needs two strings - COLOR_INSIDE_TO_LINE, - // needs two strings - COLOR_WORD_INSIDE, - // needs one string - COLOR_WORD, - // needs one string - COLOR_WORD_ENDING_WITH_STR, - // needs one string - COLOR_WORD_STARTING_WITH_STR, - // needs one string - COLOR_STR, - // needs two strings - // colors word if string is found after it - COLOR_WORD_STR, - // needs one string - // can be combined with others if this is first - COLOR_STR_AFTER_WORD, - // needs one string - // "(" would color like this "not_colored colored(" - // "[" would color like this "not_colored colored [" - COLOR_WORD_BEFORE_STR, - // needs one string - // "(" would color like this "colored not_colored(" - // "=" would color like this "colored not_colored =" - COLOR_WORD_BEFORE_STR_STR, - // no arguments needed - COLOR_UPPER_CASE_WORD, + // needs two strings + COLOR_AROUND, + // needs two strings + COLOR_AROUND_TO_LINE, + // needs two strings + COLOR_INSIDE, + // needs two strings + COLOR_INSIDE_TO_LINE, + // needs two strings + COLOR_WORD_INSIDE, + // needs one string + COLOR_WORD, + // needs one string + COLOR_WORD_ENDING_WITH_STR, + // needs one string + COLOR_WORD_STARTING_WITH_STR, + // needs one string + COLOR_STR, + // needs two strings + // colors word if string is found after it + COLOR_WORD_STR, + // needs one string + // can be combined with others if this is first + COLOR_STR_AFTER_WORD, + // needs one string + // "(" would color like this "not_colored colored(" + // "[" would color like this "not_colored colored [" + COLOR_WORD_BEFORE_STR, + // needs one string + // "(" would color like this "colored not_colored(" + // "=" would color like this "colored not_colored =" + COLOR_WORD_BEFORE_STR_STR, + // no arguments needed + COLOR_UPPER_CASE_WORD, }; struct syntax_scheme_entry { - const enum syntax_scheme_mode mode; - const struct delimiter arg; - const struct glyph attr; + const enum syntax_scheme_mode mode; + const struct delimiter arg; + const struct glyph attr; }; // TODO: INDENT_LINE_CONTAINS_STR_AND_STR enum indent_scheme_mode { - INDENT_LINE_ENDS_WITH_STR, - INDENT_LINE_DOES_NOT_END_WITH_STR, + INDENT_LINE_ENDS_WITH_STR, + INDENT_LINE_DOES_NOT_END_WITH_STR, - INDENT_LINE_CONTAINS_WORD, - INDENT_LINE_ONLY_CONTAINS_STR, - // neds two strings - INDENT_LINE_CONTAINS_STR_MORE_THAN_STR, + INDENT_LINE_CONTAINS_WORD, + INDENT_LINE_ONLY_CONTAINS_STR, + // neds two strings + INDENT_LINE_CONTAINS_STR_MORE_THAN_STR, }; enum indent_scheme_type { - INDENT_REMOVE = -1, - INDENT_KEEP_OPENER = 0, - INDENT_NEW = 1, + INDENT_REMOVE = -1, + INDENT_KEEP_OPENER = 0, + INDENT_NEW = 1, - INDENT_KEEP, - // needs two strings, requires closer to be string 1 and opener to be string two - INDENT_RETURN_TO_OPENER_BASE_INDENT, + INDENT_KEEP, + // needs two strings, requires closer to be string 1 and opener to be string two + INDENT_RETURN_TO_OPENER_BASE_INDENT, }; struct indent_scheme_entry { - const enum indent_scheme_type type; - const enum indent_scheme_mode mode; - const unsigned int line_offset; - const struct delimiter arg; + const enum indent_scheme_type type; + const enum indent_scheme_mode mode; + const unsigned int line_offset; + const struct delimiter arg; }; struct syntax_scheme { - const char* file_ending; - const char* word_seperators; + const char* file_ending; + const char* word_seperators; - const struct syntax_scheme_entry* entries; - const int entry_count; + const struct syntax_scheme_entry* entries; + const int entry_count; - const struct indent_scheme_entry* indents; - const int indent_count; + const struct indent_scheme_entry* indents; + const int indent_count; }; @@ -116,530 +116,533 @@ static int get_line_relative_offset(struct file_buffer* fb, int offset, int cou static const struct syntax_scheme* fb_get_syntax_scheme(struct file_buffer* fb) { - return fb->syntax_index < 0 ? NULL : &syntax_schemes[fb->syntax_index]; + return fb->syntax_index < 0 ? NULL : &syntax_schemes[fb->syntax_index]; } static int fb_set_syntax_scheme(struct file_buffer* fb) { - for (int i = 0; syntax_schemes[i].file_ending; i++) - if (is_file_type(fb->file_path, syntax_schemes[i].file_ending)) - fb->syntax_index = i; - return 0; + for (int i = 0; syntax_schemes[i].file_ending; i++) + if (is_file_type(fb->file_path, syntax_schemes[i].file_ending)) + fb->syntax_index = i; + return 0; } static int apply_syntax(struct window_split_node* wn, const int offset_start, const int offset_end, uint8_t* move_buffer, const int move_buffer_len) { - global_attr = default_attributes; - struct window_buffer* wb = &wn->wb; - struct file_buffer* fb = get_fb(wb); - const struct syntax_scheme* cs = fb_get_syntax_scheme(fb); - if (!cs) - return 0; - - // clear state - do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); - - // search backwards to find multi-line syntax highlighting - for (int i = 0; i < cs->entry_count; i++) { - const struct syntax_scheme_entry cse = cs->entries[i]; - if (cse.mode == COLOR_AROUND || cse.mode == COLOR_INSIDE) { - int offset = 0; - int count = 0; - int start_len = strlen(cse.arg.start); - while((offset = fb_seek_string(fb, offset, cse.arg.start)) >= 0) { - offset += start_len; - if (offset >= offset_start) - break; - count++; - } - - if (strcmp(cse.arg.start, cse.arg.end) != 0) { - int end_len = strlen(cse.arg.end); - offset = 0; - while((offset = fb_seek_string(fb, offset, cse.arg.end)) >= 0) { - offset += end_len; - if (offset >= offset_start) - break; - count--; + global_attr = default_attributes; + struct window_buffer* wb = &wn->wb; + struct file_buffer* fb = get_fb(wb); + const struct syntax_scheme* cs = fb_get_syntax_scheme(fb); + if (!cs) + return 0; + + // clear state + do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); + + // search backwards to find multi-line syntax highlighting + for (int i = 0; i < cs->entry_count; i++) { + const struct syntax_scheme_entry cse = cs->entries[i]; + if (cse.mode == COLOR_AROUND || cse.mode == COLOR_INSIDE) { + int offset = 0; + int count = 0; + int start_len = strlen(cse.arg.start); + while((offset = fb_seek_string(fb, offset, cse.arg.start)) >= 0) { + offset += start_len; + if (offset >= offset_start) + break; + count++; + } + + if (strcmp(cse.arg.start, cse.arg.end) != 0) { + int end_len = strlen(cse.arg.end); + offset = 0; + while((offset = fb_seek_string(fb, offset, cse.arg.end)) >= 0) { + offset += end_len; + if (offset >= offset_start) + break; + count--; + } + } + if (count > 0) { + offset = fb_seek_string_backwards(fb, offset_start, cse.arg.start); + do_syntax_scheme(fb, cs, offset); + break; + } } - } - if (count > 0) { - offset = fb_seek_string_backwards(fb, offset_start, cse.arg.start); - do_syntax_scheme(fb, cs, offset); - break; - } } - } - - int x = wn->minx + move_buffer[0], y = wn->miny; - int move_buffer_index = 0; - int charsize = 1; - for(int i = offset_start; i < offset_end && y < wn->maxy - && move_buffer_index < move_buffer_len; i += charsize) { - do_syntax_scheme(fb, cs, i); - screen_set_attr(x, y)->fg = global_attr.fg; - screen_set_attr(x, y)->bg = global_attr.bg; - - uint8_t amount = move_buffer[move_buffer_index]; - if (amount & (1<<7)) { - x = wn->minx; - y++; - amount &= ~(1<<7); + + int x = wn->minx + move_buffer[0], y = wn->miny; + int move_buffer_index = 0; + int charsize = 1; + for(int i = offset_start; i < offset_end && y < wn->maxy + && move_buffer_index < move_buffer_len; i += charsize) { + do_syntax_scheme(fb, cs, i); + screen_set_attr(x, y)->fg = global_attr.fg; + screen_set_attr(x, y)->bg = global_attr.bg; + + uint8_t amount = move_buffer[move_buffer_index]; + if (amount & (1<<7)) { + x = wn->minx; + y++; + amount &= ~(1<<7); + } + x += amount; + + rune_t u; + charsize = utf8_decode_buffer(fb->contents + i, i - offset_start, &u); + if (charsize == 0) + charsize = 1; + move_buffer_index++; } - x += amount; - - rune_t u; - charsize = utf8_decode_buffer(fb->contents + i, i - offset_start, &u); - if (charsize == 0) - charsize = 1; - move_buffer_index++; - } - - do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); - global_attr = default_attributes; - return 0; + + do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); + global_attr = default_attributes; + return 0; } void do_syntax_scheme(struct file_buffer* fb, const struct syntax_scheme* cs, int offset) { - static int end_at_whitespace = 0; - static const char* end_condition; - static int end_condition_len; - static struct glyph next_word_attr; - static int color_next_word = 0; - static int around = 0; - - if (!fb || !cs) { - // reset - end_at_whitespace = 0; - end_condition_len = 0; - around = 0; - color_next_word = 0; - end_condition = NULL; - global_attr = default_attributes; - return; - } - - char* buf = fb->contents; - int buflen = fb->len; - - if (end_condition && !color_next_word) { - if (buflen - offset <= end_condition_len) - return; - if (end_at_whitespace && buf[offset] == '\n') { - // *_TO_LINE reached end of line - end_condition_len = 0; - end_condition = NULL; - end_at_whitespace = 0; - global_attr = default_attributes; - } else if (fb_offset_starts_with(fb, offset, end_condition)) { - if (isspace(end_condition[end_condition_len-1])) { - end_condition_len--; - if (end_condition_len <= 0) - global_attr = default_attributes; - } - // if it's around not inside, don't reset color until later - if (around) + static int end_at_whitespace = 0; + static const char* end_condition; + static int end_condition_len; + static struct glyph next_word_attr; + static int color_next_word = 0; + static int around = 0; + + if (!fb || !cs) { + // reset + end_at_whitespace = 0; + end_condition_len = 0; around = 0; - else + color_next_word = 0; + end_condition = NULL; global_attr = default_attributes; - - end_condition = NULL; - end_at_whitespace = 0; - } - return; - } else if (end_at_whitespace) { - if (!fb_is_on_a_word(fb, offset, cs->word_seperators)) { - end_at_whitespace = 0; - global_attr = default_attributes; - } else { - return; - } - } else if (color_next_word) { - // check if new word encountered - if (!fb_is_on_a_word(fb, offset, cs->word_seperators)) - return; - global_attr = next_word_attr; - color_next_word = 0; - end_at_whitespace = 1; - return; - } else if (end_condition_len > 0) { - // wait for the word/sequence to finish - // NOTE: does not work with utf8 chars - // TODO: ??? - if (--end_condition_len <= 0) - global_attr = default_attributes; - else - return; - } - - for (int i = 0; i < cs->entry_count; i++) { - struct syntax_scheme_entry entry = cs->entries[i]; - enum syntax_scheme_mode mode = entry.mode; - - if (mode == COLOR_UPPER_CASE_WORD) { - if (!fb_is_start_of_a_word(fb, offset, cs->word_seperators)) - continue; - - int end_len = 0; - while (offset + end_len < fb->len && !str_contains_char(cs->word_seperators, buf[offset + end_len])) { - if (!isupper(buf[offset + end_len]) && buf[offset + end_len] != '_' - && (!end_len || (buf[offset + end_len] < '0' || buf[offset + end_len] > '9'))) - goto not_upper_case; - end_len++; - } - // upper case words must be longer than UPPER_CASE_WORD_MIN_LEN chars - if (end_len < UPPER_CASE_WORD_MIN_LEN) - continue; - - global_attr = entry.attr; - end_condition_len = end_len; - return; - - not_upper_case: - continue; + return; } - int len = strlen(entry.arg.start); - - if (mode == COLOR_WORD_BEFORE_STR || mode == COLOR_WORD_BEFORE_STR_STR || mode == COLOR_WORD_ENDING_WITH_STR) { - // check if this is a new word - if (str_contains_char(cs->word_seperators, buf[offset])) continue; - - int offset_tmp = offset; - // find new word twice if it's BEFORE_STR_STR - int times = mode == COLOR_WORD_BEFORE_STR_STR ? 2 : 1; - int first_word_len = 0; - int first_time = 1; - while (times--) { - // seek end of word - offset_tmp = fb_seek_word_end(fb, offset_tmp, cs->word_seperators); - if (offset_tmp == offset && mode == COLOR_WORD_BEFORE_STR_STR) - goto exit_word_before_str_str; - if (first_time) - first_word_len = offset_tmp - offset; - - if (mode != COLOR_WORD_ENDING_WITH_STR) - offset_tmp = fb_seek_not_whitespace(fb, offset_tmp); - - first_time = 0; - } - - if (mode == COLOR_WORD_ENDING_WITH_STR) { - offset_tmp -= len; - if (offset_tmp < 0) - continue; - } - if (fb_offset_starts_with(fb, offset_tmp, entry.arg.start)) { - global_attr = entry.attr; - end_condition_len = first_word_len; + char* buf = fb->contents; + int buflen = fb->len; + + if (end_condition && !color_next_word) { + if (buflen - offset <= end_condition_len) + return; + if (end_at_whitespace && buf[offset] == '\n') { + // *_TO_LINE reached end of line + end_condition_len = 0; + end_condition = NULL; + end_at_whitespace = 0; + global_attr = default_attributes; + } else if (fb_offset_starts_with(fb, offset, end_condition)) { + if (isspace(end_condition[end_condition_len-1])) { + end_condition_len--; + if (end_condition_len <= 0) + global_attr = default_attributes; + } + // if it's around not inside, don't reset color until later + if (around) + around = 0; + else + global_attr = default_attributes; + + end_condition = NULL; + end_at_whitespace = 0; + } return; - } - exit_word_before_str_str: - continue; + } else if (end_at_whitespace) { + if (!fb_is_on_a_word(fb, offset, cs->word_seperators)) { + end_at_whitespace = 0; + global_attr = default_attributes; + } else { + return; + } + } else if (color_next_word) { + // check if new word encountered + if (!fb_is_on_a_word(fb, offset, cs->word_seperators)) + return; + global_attr = next_word_attr; + color_next_word = 0; + end_at_whitespace = 1; + return; + } else if (end_condition_len > 0) { + // wait for the word/sequence to finish + // NOTE: does not work with utf8 chars + // TODO: ??? + if (--end_condition_len <= 0) + global_attr = default_attributes; + else + return; } - if (mode == COLOR_INSIDE || mode == COLOR_INSIDE_TO_LINE || mode == COLOR_WORD_INSIDE) { - if (offset - len < 0) - continue; - // check the if what's behind the cursor is the first string - if (fb_offset_starts_with(fb, offset - len, entry.arg.start)) { - if (offset < fb->len && fb_offset_starts_with(fb, offset, entry.arg.end)) - continue; - - if (mode == COLOR_WORD_INSIDE) { - // verify that only one word exists inside - int offset_tmp = offset; - offset_tmp = fb_seek_not_whitespace(fb, offset_tmp); - offset_tmp = fb_seek_whitespace(fb, offset_tmp); - int offset_tmp1 = offset_tmp - strlen(entry.arg.end); - offset_tmp = fb_seek_not_whitespace(fb, offset_tmp); - - if ((!fb_offset_starts_with(fb, offset_tmp, entry.arg.end) - && !fb_offset_starts_with(fb, offset_tmp1, entry.arg.end)) - || offset_tmp1 - offset <= 1 || offset_tmp - offset <= 1) - continue; - } else if (mode == COLOR_INSIDE_TO_LINE) { - if (fb_seek_char(fb, offset, '\n') < fb_seek_string(fb, offset, entry.arg.end)) + for (int i = 0; i < cs->entry_count; i++) { + struct syntax_scheme_entry entry = cs->entries[i]; + enum syntax_scheme_mode mode = entry.mode; + + if (mode == COLOR_UPPER_CASE_WORD) { + if (!fb_is_start_of_a_word(fb, offset, cs->word_seperators)) + continue; + + int end_len = 0; + while (offset + end_len < fb->len && !str_contains_char(cs->word_seperators, buf[offset + end_len])) { + if (!isupper(buf[offset + end_len]) && buf[offset + end_len] != '_' + && (!end_len || (buf[offset + end_len] < '0' || buf[offset + end_len] > '9'))) + goto not_upper_case; + end_len++; + } + // upper case words must be longer than UPPER_CASE_WORD_MIN_LEN chars + if (end_len < UPPER_CASE_WORD_MIN_LEN) + continue; + + global_attr = entry.attr; + end_condition_len = end_len; + return; + + not_upper_case: continue; } + int len = strlen(entry.arg.start); + + if (mode == COLOR_WORD_BEFORE_STR || mode == COLOR_WORD_BEFORE_STR_STR || mode == COLOR_WORD_ENDING_WITH_STR) { + // check if this is a new word + if (str_contains_char(cs->word_seperators, buf[offset])) continue; + + int offset_tmp = offset; + // find new word twice if it's BEFORE_STR_STR + int times = mode == COLOR_WORD_BEFORE_STR_STR ? 2 : 1; + int first_word_len = 0; + int first_time = 1; + while (times--) { + // seek end of word + offset_tmp = fb_seek_word_end(fb, offset_tmp, cs->word_seperators); + if (offset_tmp == offset && mode == COLOR_WORD_BEFORE_STR_STR) + goto exit_word_before_str_str; + if (first_time) + first_word_len = offset_tmp - offset; + + if (mode != COLOR_WORD_ENDING_WITH_STR) + offset_tmp = fb_seek_not_whitespace(fb, offset_tmp); + + first_time = 0; + } + + if (mode == COLOR_WORD_ENDING_WITH_STR) { + offset_tmp -= len; + if (offset_tmp < 0) + continue; + } + if (fb_offset_starts_with(fb, offset_tmp, entry.arg.start)) { + global_attr = entry.attr; + end_condition_len = first_word_len; + return; + } + exit_word_before_str_str: + continue; + } - end_condition = entry.arg.end; - end_condition_len = strlen(entry.arg.end); - global_attr = entry.attr; - around = 0; - return; - } - continue; - } + if (mode == COLOR_INSIDE || mode == COLOR_INSIDE_TO_LINE || mode == COLOR_WORD_INSIDE) { + if (offset - len < 0) + continue; + // check the if what's behind the cursor is the first string + if (fb_offset_starts_with(fb, offset - len, entry.arg.start)) { + if (offset < fb->len && fb_offset_starts_with(fb, offset, entry.arg.end)) + continue; + + if (mode == COLOR_WORD_INSIDE) { + // verify that only one word exists inside + int offset_tmp = offset; + offset_tmp = fb_seek_not_whitespace(fb, offset_tmp); + offset_tmp = fb_seek_whitespace(fb, offset_tmp); + int offset_tmp1 = offset_tmp - strlen(entry.arg.end); + offset_tmp = fb_seek_not_whitespace(fb, offset_tmp); + + if ((!fb_offset_starts_with(fb, offset_tmp, entry.arg.end) + && !fb_offset_starts_with(fb, offset_tmp1, entry.arg.end)) + || offset_tmp1 - offset <= 1 || offset_tmp - offset <= 1) + continue; + } else if (mode == COLOR_INSIDE_TO_LINE) { + if (fb_seek_char(fb, offset, '\n') < fb_seek_string(fb, offset, entry.arg.end)) + continue; + } + + + end_condition = entry.arg.end; + end_condition_len = strlen(entry.arg.end); + global_attr = entry.attr; + around = 0; + return; + } + continue; + } - if ((mode == COLOR_AROUND || mode == COLOR_AROUND_TO_LINE) && - fb_offset_starts_with(fb, offset, entry.arg.start)) { - end_condition = entry.arg.end; - end_condition_len = strlen(entry.arg.end); - around = 1; - if (entry.mode == COLOR_AROUND_TO_LINE) - end_at_whitespace = 1; - global_attr = entry.attr; - return; + if ((mode == COLOR_AROUND || mode == COLOR_AROUND_TO_LINE) && + fb_offset_starts_with(fb, offset, entry.arg.start)) { + end_condition = entry.arg.end; + end_condition_len = strlen(entry.arg.end); + around = 1; + if (entry.mode == COLOR_AROUND_TO_LINE) + end_at_whitespace = 1; + global_attr = entry.attr; + return; + } + if (mode == COLOR_WORD || mode == COLOR_STR_AFTER_WORD || + mode == COLOR_WORD_STR || mode == COLOR_WORD_STARTING_WITH_STR) { + + // check if this is the start of a new word that matches word exactly(except for WORD_STARTING_WITH_STR) + if(!fb_offset_starts_with(fb, offset, entry.arg.start) || + !fb_is_start_of_a_word(fb, offset, cs->word_seperators) || + (fb_is_on_a_word(fb, offset + len, cs->word_seperators) && mode != COLOR_WORD_STARTING_WITH_STR)) + continue; + + if (mode == COLOR_WORD_STR) { + int offset_str = fb_seek_not_whitespace(fb, offset + len); + + if (!fb_offset_starts_with(fb, offset_str, entry.arg.end)) + continue; + end_condition_len = strlen(entry.arg.start); + } else { + end_at_whitespace = 1; + } + if (mode == COLOR_STR_AFTER_WORD) { + next_word_attr = entry.attr; + color_next_word = 1; + continue; + } + global_attr = entry.attr; + return; + } + if (mode == COLOR_STR) { + if (!fb_offset_starts_with(fb, offset, entry.arg.start)) + continue; + end_condition_len = len; + global_attr = entry.attr; + return; + } } - if (mode == COLOR_WORD || mode == COLOR_STR_AFTER_WORD || - mode == COLOR_WORD_STR || mode == COLOR_WORD_STARTING_WITH_STR) { - - // check if this is the start of a new word that matches word exactly(except for WORD_STARTING_WITH_STR) - if(!fb_offset_starts_with(fb, offset, entry.arg.start) || - !fb_is_start_of_a_word(fb, offset, cs->word_seperators) || - (fb_is_on_a_word(fb, offset + len, cs->word_seperators) && mode != COLOR_WORD_STARTING_WITH_STR)) - continue; +} - if (mode == COLOR_WORD_STR) { - int offset_str = fb_seek_not_whitespace(fb, offset + len); - if (!fb_offset_starts_with(fb, offset_str, entry.arg.end)) - continue; - end_condition_len = strlen(entry.arg.start); - } else { - end_at_whitespace = 1; - } - if (mode == COLOR_STR_AFTER_WORD) { - next_word_attr = entry.attr; - color_next_word = 1; - continue; - } - global_attr = entry.attr; - return; - } - if (mode == COLOR_STR) { - if (!fb_offset_starts_with(fb, offset, entry.arg.start)) - continue; - end_condition_len = len; - global_attr = entry.attr; - return; - } - } -} +//////////////////////// +// Auto indent +// +// -// TODO: make seperate plugin -// also make the "syntax" member of file buffer not a thing -// needs to be more dynamic int fb_auto_indent(struct file_buffer* fb, int offset) { - const struct syntax_scheme* cs = fb_get_syntax_scheme(fb); - LIMIT(offset, 0, fb->len-1); + const struct syntax_scheme* cs = fb_get_syntax_scheme(fb); + LIMIT(offset, 0, fb->len-1); + + int indent_diff = 0; + int indent_keep_x = -1; + int keep_pos = 0; + + int get_line_offset; + char* get_line = NULL; + + for (int i = 0; i < cs->indent_count; i++) { + const struct indent_scheme_entry indent = cs->indents[i]; + + get_line_offset = get_line_relative_offset(fb, offset, indent.line_offset); + if (get_line) + free(get_line); + get_line = fb_get_line_at_offset(fb, get_line_offset); + + switch(indent.mode) { + int temp_offset, len; + char* res; + case INDENT_LINE_CONTAINS_WORD: + case INDENT_LINE_ONLY_CONTAINS_STR: + case INDENT_LINE_CONTAINS_STR_MORE_THAN_STR: + res = strstr(get_line, indent.arg.start); + if (!res) + continue; + if (INDENT_LINE_CONTAINS_WORD) { + if (res > get_line && !str_contains_char(cs->word_seperators, *(res-1))) + continue; + res += strlen(indent.arg.start); + if (*res && !str_contains_char(cs->word_seperators, *res)) + continue; + } else if (INDENT_LINE_CONTAINS_STR_MORE_THAN_STR == indent.mode) { + char* start_last = get_line; + char* end_last = get_line; + for (int count = 0; count >= 0; ) { + if (start_last && (start_last = strstr(start_last, indent.arg.start))) { + start_last++; + count--; + } else { + goto indent_for_loop_continue; + } + if (end_last && (end_last = strstr(end_last, indent.arg.end))) { + end_last++; + count++; + } + } + } else if (indent.mode == INDENT_LINE_ONLY_CONTAINS_STR) { + int str_start = fb_seek_string_backwards(fb, get_line_offset, indent.arg.start); + int str_end = str_start + strlen(indent.arg.start); + int line_end = MIN(get_line_offset + 1, fb->len); + int line_start = MAX(fb_seek_char_backwards(fb, get_line_offset, '\n'), 0); + if (fb_seek_not_whitespace_backwards(fb, str_start-1) >= line_start || + fb_seek_not_whitespace(fb, str_end+1) <= line_end) + continue; + } + if (indent.type == INDENT_KEEP_OPENER || indent.type == INDENT_RETURN_TO_OPENER_BASE_INDENT) + keep_pos = fb_seek_string_backwards(fb, get_line_offset, indent.arg.start); + goto set_indent_type; + + case INDENT_LINE_ENDS_WITH_STR: + case INDENT_LINE_DOES_NOT_END_WITH_STR: + len = strlen(indent.arg.start); + temp_offset = fb_seek_not_whitespace_backwards(fb, get_line_offset) - len; + if (temp_offset < 0 || + temp_offset < fb_seek_char_backwards(fb, get_line_offset, '\n')) + continue; + if (memcmp(fb->contents + get_line_offset, indent.arg.start, strlen(indent.arg.start)) == 0) { + if (indent.mode == INDENT_LINE_DOES_NOT_END_WITH_STR) + continue; + } else { + if (indent.mode == INDENT_LINE_ENDS_WITH_STR) + continue; + } + keep_pos = temp_offset; + goto set_indent_type; + + set_indent_type: + if (indent.type == INDENT_KEEP_OPENER) { + if (indent_keep_x >= 0) + continue; + int tmp; + fb_offset_to_xy(fb, keep_pos, 0, 0, &indent_keep_x, &tmp, &tmp); + } else if (indent.type == INDENT_RETURN_TO_OPENER_BASE_INDENT) { + if (indent_keep_x >= 0) + continue; + int opener, closer; + if (!fb_get_delimiter(fb, keep_pos, indent.arg, NULL, &opener, &closer)) { + indent_keep_x = -1; + goto indent_for_loop_continue; + } + keep_pos = fb_seek_not_whitespace(fb, fb_seek_char_backwards(fb, opener, '\n')); + int tmp; + fb_offset_to_xy(fb, keep_pos, 0, 0, &indent_keep_x, &tmp, &tmp); + //TODO: why does this miss by one? + if (indent_keep_x > 0) + indent_keep_x--; + } else { + if (indent_diff) + continue; + indent_diff += indent.type; + } + } + indent_for_loop_continue: + continue; + } - int indent_diff = 0; - int indent_keep_x = -1; - int keep_pos = 0; + if (get_line) + free(get_line); - int get_line_offset; - char* get_line = NULL; + int indents = 0, extra_spaces = 0; - for (int i = 0; i < cs->indent_count; i++) { - const struct indent_scheme_entry indent = cs->indents[i]; + int prev_line_offset = fb_seek_char_backwards(fb, offset, '\n') - 1; + if (prev_line_offset < 0) + return 0; + char* prev_line = fb_get_line_at_offset(fb, prev_line_offset); - get_line_offset = get_line_relative_offset(fb, offset, indent.line_offset); - if (get_line) - free(get_line); - get_line = fb_get_line_at_offset(fb, get_line_offset); - - switch(indent.mode) { - int temp_offset, len; - char* res; - case INDENT_LINE_CONTAINS_WORD: - case INDENT_LINE_ONLY_CONTAINS_STR: - case INDENT_LINE_CONTAINS_STR_MORE_THAN_STR: - res = strstr(get_line, indent.arg.start); - if (!res) - continue; - if (INDENT_LINE_CONTAINS_WORD) { - if (res > get_line && !str_contains_char(cs->word_seperators, *(res-1))) - continue; - res += strlen(indent.arg.start); - if (*res && !str_contains_char(cs->word_seperators, *res)) - continue; - } else if (INDENT_LINE_CONTAINS_STR_MORE_THAN_STR == indent.mode) { - char* start_last = get_line; - char* end_last = get_line; - for (int count = 0; count >= 0; ) { - if (start_last && (start_last = strstr(start_last, indent.arg.start))) { - start_last++; - count--; - } else { - goto indent_for_loop_continue; - } - if (end_last && (end_last = strstr(end_last, indent.arg.end))) { - end_last++; - count++; - } - } - } else if (indent.mode == INDENT_LINE_ONLY_CONTAINS_STR) { - int str_start = fb_seek_string_backwards(fb, get_line_offset, indent.arg.start); - int str_end = str_start + strlen(indent.arg.start); - int line_end = MIN(get_line_offset + 1, fb->len); - int line_start = MAX(fb_seek_char_backwards(fb, get_line_offset, '\n'), 0); - if (fb_seek_not_whitespace_backwards(fb, str_start-1) >= line_start || - fb_seek_not_whitespace(fb, str_end+1) <= line_end) - continue; - } - if (indent.type == INDENT_KEEP_OPENER || indent.type == INDENT_RETURN_TO_OPENER_BASE_INDENT) - keep_pos = fb_seek_string_backwards(fb, get_line_offset, indent.arg.start); - goto set_indent_type; - - case INDENT_LINE_ENDS_WITH_STR: - case INDENT_LINE_DOES_NOT_END_WITH_STR: - len = strlen(indent.arg.start); - temp_offset = fb_seek_not_whitespace_backwards(fb, get_line_offset) - len; - if (temp_offset < 0 || - temp_offset < fb_seek_char_backwards(fb, get_line_offset, '\n')) - continue; - if (memcmp(fb->contents + get_line_offset, indent.arg.start, strlen(indent.arg.start)) == 0) { - if (indent.mode == INDENT_LINE_DOES_NOT_END_WITH_STR) - continue; - } else { - if (indent.mode == INDENT_LINE_ENDS_WITH_STR) - continue; - } - keep_pos = temp_offset; - goto set_indent_type; - - set_indent_type: - if (indent.type == INDENT_KEEP_OPENER) { - if (indent_keep_x >= 0) - continue; - int tmp; - fb_offset_to_xy(fb, keep_pos, 0, 0, &indent_keep_x, &tmp, &tmp); - } else if (indent.type == INDENT_RETURN_TO_OPENER_BASE_INDENT) { - if (indent_keep_x >= 0) - continue; - int opener, closer; - if (!fb_get_delimiter(fb, keep_pos, indent.arg, NULL, &opener, &closer)) { - indent_keep_x = -1; - goto indent_for_loop_continue; - } - keep_pos = fb_seek_not_whitespace(fb, fb_seek_char_backwards(fb, opener, '\n')); - int tmp; - fb_offset_to_xy(fb, keep_pos, 0, 0, &indent_keep_x, &tmp, &tmp); - //TODO: why does this miss by one? - if (indent_keep_x > 0) - indent_keep_x--; - } else { - if (indent_diff) - continue; - indent_diff += indent.type; - } + if (indent_keep_x >= 0) { + whitespace_count_to_indent_amount(fb->indent_len, indent_keep_x, &indents, &extra_spaces); + } else { + whitespace_count_to_indent_amount(fb->indent_len, get_line_leading_whitespace_count(prev_line), &indents, &extra_spaces); + } + if (indent_diff != INDENT_KEEP) { + indents += indent_diff; + indents = MAX(indents, 0); + } + + // remove the lines existing indent + int removed = 0; + int line_code_start = MIN(fb_seek_not_whitespace(fb, prev_line_offset + 1), fb_seek_char(fb, prev_line_offset + 1, '\n')); + if (line_code_start - (prev_line_offset) >= 1) { + removed = line_code_start - (prev_line_offset+1); + fb_remove(fb, prev_line_offset + 1, removed, 1, 1); } - indent_for_loop_continue: - continue; - } - if (get_line) - free(get_line); + if (indents + extra_spaces <= 0) { + free(prev_line); + return -removed; + } - int indents = 0, extra_spaces = 0; + unsigned int indent_str_len = 0; + while(indents--) + indent_str_len += fb->indent_len ? fb->indent_len : 1; + char indent_str[indent_str_len + extra_spaces]; + + char space_tab = fb->indent_len > 0 ? ' ' : '\t'; + int i = 0; + if (!fb->indent_len) + for (/* i = 0 */; i < indent_str_len; i++) + indent_str[i] = space_tab; + for (/* i = 0 or indent_str_len */ ; i < indent_str_len + extra_spaces; i++) + indent_str[i] = ' '; + + fb_insert(fb, indent_str, indent_str_len + extra_spaces, prev_line_offset + 1, 0); - int prev_line_offset = fb_seek_char_backwards(fb, offset, '\n') - 1; - if (prev_line_offset < 0) - return 0; - char* prev_line = fb_get_line_at_offset(fb, prev_line_offset); - - if (indent_keep_x >= 0) { - whitespace_count_to_indent_amount(fb->indent_len, indent_keep_x, &indents, &extra_spaces); - } else { - whitespace_count_to_indent_amount(fb->indent_len, get_line_leading_whitespace_count(prev_line), &indents, &extra_spaces); - } - if (indent_diff != INDENT_KEEP) { - indents += indent_diff; - indents = MAX(indents, 0); - } - - // remove the lines existing indent - int removed = 0; - int line_code_start = MIN(fb_seek_not_whitespace(fb, prev_line_offset + 1), fb_seek_char(fb, prev_line_offset + 1, '\n')); - if (line_code_start - (prev_line_offset) >= 1) { - removed = line_code_start - (prev_line_offset+1); - fb_remove(fb, prev_line_offset + 1, removed, 1, 1); - } - - if (indents + extra_spaces <= 0) { free(prev_line); - return -removed; - } - - unsigned int indent_str_len = 0; - while(indents--) - indent_str_len += fb->indent_len ? fb->indent_len : 1; - char indent_str[indent_str_len + extra_spaces]; - - char space_tab = fb->indent_len > 0 ? ' ' : '\t'; - int i = 0; - if (!fb->indent_len) - for (/* i = 0 */; i < indent_str_len; i++) - indent_str[i] = space_tab; - for (/* i = 0 or indent_str_len */ ; i < indent_str_len + extra_spaces; i++) - indent_str[i] = ' '; - - fb_insert(fb, indent_str, indent_str_len + extra_spaces, prev_line_offset + 1, 0); - - free(prev_line); - return indent_str_len + extra_spaces - removed; + return indent_str_len + extra_spaces - removed; } int get_line_leading_whitespace_count(const char* line) { - int count = 0; - while(*line) { - if (*line == ' ') - count++; - else if (*line == '\t') - count += tabspaces - (count % tabspaces); - else - break; - line++; - } - return count; + int count = 0; + while(*line) { + if (*line == ' ') + count++; + else if (*line == '\t') + count += tabspaces - (count % tabspaces); + else + break; + line++; + } + return count; } void whitespace_count_to_indent_amount(int indent_len, int count, int* indent_count, int* extra_spaces) { - *indent_count = 0, *extra_spaces = 0; - int space_count = indent_len > 0 ? indent_len : tabspaces; - while(count >= space_count) { - *indent_count += 1; - count -= space_count; - } - *extra_spaces = count; + *indent_count = 0, *extra_spaces = 0; + int space_count = indent_len > 0 ? indent_len : tabspaces; + while(count >= space_count) { + *indent_count += 1; + count -= space_count; + } + *extra_spaces = count; } int get_line_relative_offset(struct file_buffer* fb, int offset, int count) { - offset = fb_seek_char(fb, offset, '\n'); - if (offset < 0) - offset = fb->len; - if (count > 0) { - while(count-- && offset >= 0) - offset = fb_seek_char(fb, offset+1, '\n'); + offset = fb_seek_char(fb, offset, '\n'); if (offset < 0) - offset = fb->len; - } else if (count < 0) { - offset = fb_seek_char_backwards(fb, offset, '\n'); - while(count++ && offset >= 0) - offset = fb_seek_char_backwards(fb, offset-1, '\n'); + offset = fb->len; + if (count > 0) { + while(count-- && offset >= 0) + offset = fb_seek_char(fb, offset+1, '\n'); + if (offset < 0) + offset = fb->len; + } else if (count < 0) { + offset = fb_seek_char_backwards(fb, offset, '\n'); + while(count++ && offset >= 0) + offset = fb_seek_char_backwards(fb, offset-1, '\n'); + if (offset < 0) + offset = 0; + } + offset = fb_seek_char(fb, offset, '\n'); + if (offset > 0 && fb->contents[offset-1] != '\n') + offset--; if (offset < 0) - offset = 0; - } - offset = fb_seek_char(fb, offset, '\n'); - if (offset > 0 && fb->contents[offset-1] != '\n') - offset--; - if (offset < 0) - offset = fb->len; - return offset; + offset = fb->len; + return offset; } diff --git a/se.c b/se.c @@ -18,8 +18,6 @@ #include "config.h" #include "extension.h" -// se.c globals - ///////////////////////////////////////////// // Internal functions // @@ -34,14 +32,14 @@ static void color_selection(struct glyph* letter); int writef_string(int y, int x1, int x2, const char* fmt, ...) { - char string[STATUS_BAR_MAX_LEN]; + char string[STATUS_BAR_MAX_LEN]; - va_list args; - va_start(args, fmt); - vsnprintf(string, STATUS_BAR_MAX_LEN, fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + vsnprintf(string, STATUS_BAR_MAX_LEN, fmt, args); + va_end(args); - return write_string(string, y, x1, x2); + return write_string(string, y, x1, x2); } char status_bar_contents[STATUS_BAR_MAX_LEN] = {0}; @@ -50,327 +48,327 @@ uint32_t status_bar_bg; void writef_to_status_bar(const char* fmt, ...) { - if (fmt) { - if (status_bar_bg == error_color || - status_bar_bg == warning_color || - status_bar_bg == ok_color) - return; - - va_list args; - va_start(args, fmt); - vsnprintf(status_bar_contents, STATUS_BAR_MAX_LEN, fmt, args); - va_end(args); - - status_bar_bg = alternate_bg_dark; - return; - } + if (fmt) { + if (status_bar_bg == error_color || + status_bar_bg == warning_color || + status_bar_bg == ok_color) + return; + + va_list args; + va_start(args, fmt); + vsnprintf(status_bar_contents, STATUS_BAR_MAX_LEN, fmt, args); + va_end(args); + + status_bar_bg = alternate_bg_dark; + return; + } - global_attr = default_attributes; - global_attr.bg = status_bar_bg; + global_attr = default_attributes; + global_attr.bg = status_bar_bg; - status_bar_end = write_string(status_bar_contents, screen.row-1, 0, screen.col); - screen_set_region(status_bar_end, screen.row-1, screen.col-1, screen.row-1, ' '); + status_bar_end = write_string(status_bar_contents, screen.row-1, 0, screen.col); + screen_set_region(status_bar_end, screen.row-1, screen.col-1, screen.row-1, ' '); - global_attr = default_attributes; + global_attr = default_attributes; } void draw_status_bar() { - writef_to_status_bar(NULL); - xdrawline(0, screen.row-1, screen.col); - draw_horisontal_line(screen.row-2, 0, screen.col-1); - if (get_fb(focused_window)->mode & FB_SEARCH_BLOCKING) - xdrawcursor(status_bar_end, screen.row-1, 1); - status_bar_bg = alternate_bg_dark; + writef_to_status_bar(NULL); + xdrawline(0, screen.row-1, screen.col); + draw_horisontal_line(screen.row-2, 0, screen.col-1); + if (get_fb(focused_window)->mode & FB_SEARCH_BLOCKING) + xdrawcursor(status_bar_end, screen.row-1, 1); + status_bar_bg = alternate_bg_dark; } void window_node_draw_to_screen(struct window_split_node* wn) { - struct window_buffer* wb = &wn->wb; - struct file_buffer* fb = get_fb(wb); - int minx = wn->minx, miny = wn->miny, - maxx = wn->maxx, maxy = wn->maxy; - - LIMIT(wb->cursor_offset, 0, fb->len); - screen_set_region(minx, miny, maxx, maxy, ' '); - int focused = wb == focused_window && !(fb->mode & FB_SEARCH_BLOCKING); - - int x = minx, y = miny; - global_attr = default_attributes; - - // force the screen in a place where the cursor is visable - int ox, oy, xscroll; - fb_offset_to_xy(fb, wb->cursor_offset, maxx - minx, wb->y_scroll, &ox, &oy, &xscroll); - if (oy < 0) { - wb->y_scroll += oy; - } else { - oy += miny - maxy+2; - if (oy > 0) - wb->y_scroll += oy; - } - if (wb->y_scroll < 0) - wb->y_scroll = 0; - - if (wrap_buffer) - xscroll = 0; - - // move to y_scroll - char* repl = fb->contents; - char* last = repl + fb->len; - char* new_repl; - int line = wb->y_scroll; - while ((new_repl = memchr(repl, '\n', last - repl))) { - if (--line < 0) - break; - else if (new_repl+1 < last) - repl = new_repl+1; - else - return; - } - int offset_start = repl - fb->contents - 1; - int cursor_x = 0, cursor_y = 0; - - // actually write to the screen - int once = 0; - int search_found = 0; - int non_blocking_search_found = 0; - - // TODO: verify that last - repl is the same as offset_last - offset_start - int move_buffer_len = last - repl + 2; - uint8_t* move_buffer = xmalloc(move_buffer_len); - memset(move_buffer, 0, move_buffer_len); - move_buffer[0] = 0; - int lastx = x, lasty = y; - int move_buffer_index = 0; - - // TODO: write max string len of 127 - // TODO: make the write thing similar to syntax? - char* new_line_start = NULL; - call_extension(wb_new_line_draw, &new_line_start, wb, y - miny, maxy - y, minx, maxx, &global_attr); - if (new_line_start) { - struct glyph old_attr = global_attr; - global_attr = default_attributes; - x = write_string(new_line_start, y, minx, maxx+1); - global_attr = old_attr; - } + struct window_buffer* wb = &wn->wb; + struct file_buffer* fb = get_fb(wb); + int minx = wn->minx, miny = wn->miny, + maxx = wn->maxx, maxy = wn->maxy; + + LIMIT(wb->cursor_offset, 0, fb->len); + screen_set_region(minx, miny, maxx, maxy, ' '); + int focused = wb == focused_window && !(fb->mode & FB_SEARCH_BLOCKING); - int tmp = 0; - call_extension(wb_write_status_bar, &tmp, NULL, 0, 0, 0, 0, NULL, NULL); + int x = minx, y = miny; + global_attr = default_attributes; - for (int charsize = 1; repl < last && charsize; repl += charsize) { - if (y > lasty) { - move_buffer[move_buffer_index] = x - minx; - move_buffer[move_buffer_index] |= 1<<7; + // force the screen in a place where the cursor is visable + int ox, oy, xscroll; + fb_offset_to_xy(fb, wb->cursor_offset, maxx - minx, wb->y_scroll, &ox, &oy, &xscroll); + if (oy < 0) { + wb->y_scroll += oy; } else { - move_buffer[move_buffer_index] = x - lastx; + oy += miny - maxy+2; + if (oy > 0) + wb->y_scroll += oy; } - move_buffer_index++; - lastx = x, lasty = y; - - if (!once && repl - fb->contents >= wb->cursor_offset) { - // if the buffer being drawn is focused, set the cursor position global - once = 1; - cursor_x = x - xscroll; - cursor_y = y; - LIMIT(cursor_x, minx, maxx); - LIMIT(cursor_y, miny, maxy); - } - - if (!wrap_buffer && x - xscroll > maxx && *repl != '\n') { - charsize = 1; - x++; - continue; + if (wb->y_scroll < 0) + wb->y_scroll = 0; + + if (wrap_buffer) + xscroll = 0; + + // move to y_scroll + char* repl = fb->contents; + char* last = repl + fb->len; + char* new_repl; + int line = wb->y_scroll; + while ((new_repl = memchr(repl, '\n', last - repl))) { + if (--line < 0) + break; + else if (new_repl+1 < last) + repl = new_repl+1; + else + return; } - - if (*repl == '\n' || (wrap_buffer && x >= maxx)) { - x = minx; - if (++y >= maxy-1) - break; - if (wrap_buffer && *repl != '\n') - continue; - charsize = 1; - char* new_line_start = NULL; - call_extension(wb_new_line_draw, &new_line_start, wb, y - miny, maxy - y, minx, maxx, &global_attr); - if (new_line_start) { + int offset_start = repl - fb->contents - 1; + int cursor_x = 0, cursor_y = 0; + + // actually write to the screen + int once = 0; + int search_found = 0; + int non_blocking_search_found = 0; + + // TODO: verify that last - repl is the same as offset_last - offset_start + int move_buffer_len = last - repl + 2; + uint8_t* move_buffer = xmalloc(move_buffer_len); + memset(move_buffer, 0, move_buffer_len); + move_buffer[0] = 0; + int lastx = x, lasty = y; + int move_buffer_index = 0; + + // TODO: write max string len of 127 + // TODO: make the write thing similar to syntax? + char* new_line_start = NULL; + call_extension(wb_new_line_draw, &new_line_start, wb, y - miny, maxy - y, minx, maxx, &global_attr); + if (new_line_start) { struct glyph old_attr = global_attr; global_attr = default_attributes; x = write_string(new_line_start, y, minx, maxx+1); global_attr = old_attr; - } - continue; - } else if (*repl == '\t') { - charsize = 1; - if ((x - minx) <= 0) { - x += screen_set_char(' ', x - xscroll, y); - if (x >= maxx) - continue; - } - while ((x - minx) % tabspaces != 0 && x - xscroll <= maxx) - x += screen_set_char(' ', x - xscroll, y); - - if (x - xscroll <= maxx) - x += screen_set_char(' ', x, y); - continue; } - rune_t u; - charsize = utf8_decode_buffer(repl, last - repl, &u); - - int width; - if (x - xscroll >= minx) - width = screen_set_char(u, x - xscroll, y); - else - width = wcwidth(u); - - // drawing search highlight - if (fb->mode & FB_SEARCH_BLOCKING_MASK) { - if (!search_found && fb_offset_starts_with(fb, repl - fb->contents, fb->search_term)) - search_found = strlen(fb->search_term); - if (search_found) { - screen_set_attr(x - xscroll, y)->bg = highlight_color; - screen_set_attr(x - xscroll, y)->fg = default_attributes.bg; - search_found--; - } + int tmp = 0; + call_extension(wb_write_status_bar, &tmp, NULL, 0, 0, 0, 0, NULL, NULL); + + for (int charsize = 1; repl < last && charsize; repl += charsize) { + if (y > lasty) { + move_buffer[move_buffer_index] = x - minx; + move_buffer[move_buffer_index] |= 1<<7; + } else { + move_buffer[move_buffer_index] = x - lastx; + } + move_buffer_index++; + lastx = x, lasty = y; + + if (!once && repl - fb->contents >= wb->cursor_offset) { + // if the buffer being drawn is focused, set the cursor position global + once = 1; + cursor_x = x - xscroll; + cursor_y = y; + LIMIT(cursor_x, minx, maxx); + LIMIT(cursor_y, miny, maxy); + } + + if (!wrap_buffer && x - xscroll > maxx && *repl != '\n') { + charsize = 1; + x++; + continue; + } + + if (*repl == '\n' || (wrap_buffer && x >= maxx)) { + x = minx; + if (++y >= maxy-1) + break; + if (wrap_buffer && *repl != '\n') + continue; + charsize = 1; + char* new_line_start = NULL; + call_extension(wb_new_line_draw, &new_line_start, wb, y - miny, maxy - y, minx, maxx, &global_attr); + if (new_line_start) { + struct glyph old_attr = global_attr; + global_attr = default_attributes; + x = write_string(new_line_start, y, minx, maxx+1); + global_attr = old_attr; + } + continue; + } else if (*repl == '\t') { + charsize = 1; + if ((x - minx) <= 0) { + x += screen_set_char(' ', x - xscroll, y); + if (x >= maxx) + continue; + } + while ((x - minx) % tabspaces != 0 && x - xscroll <= maxx) + x += screen_set_char(' ', x - xscroll, y); + + if (x - xscroll <= maxx) + x += screen_set_char(' ', x, y); + continue; + } + + rune_t u; + charsize = utf8_decode_buffer(repl, last - repl, &u); + + int width; + if (x - xscroll >= minx) + width = screen_set_char(u, x - xscroll, y); + else + width = wcwidth(u); + + // drawing search highlight + if (fb->mode & FB_SEARCH_BLOCKING_MASK) { + if (!search_found && fb_offset_starts_with(fb, repl - fb->contents, fb->search_term)) + search_found = strlen(fb->search_term); + if (search_found) { + screen_set_attr(x - xscroll, y)->bg = highlight_color; + screen_set_attr(x - xscroll, y)->fg = default_attributes.bg; + search_found--; + } + } + if (fb->mode & FB_SEARCH_NON_BLOCKING) { + if (!non_blocking_search_found && fb_offset_starts_with(fb, repl - fb->contents, fb->non_blocking_search_term)) + non_blocking_search_found = strlen(fb->search_term); + if (non_blocking_search_found) { + screen_set_attr(x - xscroll, y)->fg = highlight_color; + screen_set_attr(x - xscroll, y)->mode |= ATTR_UNDERLINE; + non_blocking_search_found--; + } + } + + x += width; } - if (fb->mode & FB_SEARCH_NON_BLOCKING) { - if (!non_blocking_search_found && fb_offset_starts_with(fb, repl - fb->contents, fb->non_blocking_search_term)) - non_blocking_search_found = strlen(fb->search_term); - if (non_blocking_search_found) { - screen_set_attr(x - xscroll, y)->fg = highlight_color; - screen_set_attr(x - xscroll, y)->mode |= ATTR_UNDERLINE; - non_blocking_search_found--; - } + int offset_end = repl - fb->contents; + global_attr = default_attributes; + + if (wb->cursor_offset >= fb->len) { + cursor_x = x - xscroll; + cursor_y = MIN(y, maxy); } - x += width; - } - int offset_end = repl - fb->contents; - global_attr = default_attributes; + call_extension(window_written_to_screen, wn, offset_start, offset_end, move_buffer, move_buffer_len); - if (wb->cursor_offset >= fb->len) { - cursor_x = x - xscroll; - cursor_y = MIN(y, maxy); - } + int status_end = minx; + int write_again; + do { + write_again = 0; + char bar[LINE_MAX_LEN]; + *bar = 0; - call_extension(window_written_to_screen, wn, offset_start, offset_end, move_buffer, move_buffer_len); + call_extension(wb_write_status_bar, &write_again, wb, status_end, maxx+1, cursor_x - minx + xscroll, cursor_y - miny + wb->y_scroll, bar, &global_attr); + status_end = write_string(bar, maxy-1, status_end, maxx+1); - int status_end = minx; - int write_again; - do { - write_again = 0; - char bar[LINE_MAX_LEN]; - *bar = 0; + global_attr = default_attributes; + } while (write_again); - call_extension(wb_write_status_bar, &write_again, wb, status_end, maxx+1, cursor_x - minx + xscroll, cursor_y - miny + wb->y_scroll, bar, &global_attr); - status_end = write_string(bar, maxy-1, status_end, maxx+1); + if (fb->mode & FB_SELECTION_ON) { + int y1, y2, tmp; + fb_offset_to_xy(fb, fb->s1o, 0, wb->y_scroll, &tmp, &y1, &tmp); + fb_offset_to_xy(fb, fb->s2o, 0, wb->y_scroll, &tmp, &y2, &tmp); + writef_string(maxy-1, status_end, maxx, " %dL", abs(y1-y2)); + } - global_attr = default_attributes; - } while (write_again); - - if (fb->mode & FB_SELECTION_ON) { - int y1, y2, tmp; - fb_offset_to_xy(fb, fb->s1o, 0, wb->y_scroll, &tmp, &y1, &tmp); - fb_offset_to_xy(fb, fb->s2o, 0, wb->y_scroll, &tmp, &y2, &tmp); - writef_string(maxy-1, status_end, maxx, " %dL", abs(y1-y2)); - } - - if (focused) { - for (int i = minx; i < maxx+1; i++) { - if (!(fb->mode & FB_SELECTION_ON)) { - if (screen_set_attr(i, cursor_y)->bg == default_attributes.bg) - screen_set_attr(i, cursor_y)->bg = mouse_line_bg; - } - screen_set_attr(i, maxy-1)->bg = alternate_bg_bright; + if (focused) { + for (int i = minx; i < maxx+1; i++) { + if (!(fb->mode & FB_SELECTION_ON)) { + if (screen_set_attr(i, cursor_y)->bg == default_attributes.bg) + screen_set_attr(i, cursor_y)->bg = mouse_line_bg; + } + screen_set_attr(i, maxy-1)->bg = alternate_bg_bright; + } } - } - wb_write_selection(wb, minx, miny, maxx, maxy); - //do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); + wb_write_selection(wb, minx, miny, maxx, maxy); + //do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); - for (int i = miny; i < maxy; i++) - xdrawline(minx, i, maxx+1); + for (int i = miny; i < maxy; i++) + xdrawline(minx, i, maxx+1); - draw_horisontal_line(maxy-1, minx, maxx); + draw_horisontal_line(maxy-1, minx, maxx); - xdrawcursor(cursor_x, cursor_y, focused); - free(move_buffer); + xdrawcursor(cursor_x, cursor_y, focused); + free(move_buffer); } int write_string(const char* string, int y, int minx, int maxx) { - if (!string) - return 0; - LIMIT(maxx, 0, screen.col); - LIMIT(minx, 0, maxx); - - int offset = 0; - int len = strlen(string); - while(minx < maxx && offset < len) { - rune_t u; - int charsize = utf8_decode_buffer(string + offset, len - offset, &u); - offset += charsize; - if (charsize == 1 && u <= 32) - u = ' '; - minx += screen_set_char(u, minx, y); - } - return minx; + if (!string) + return 0; + LIMIT(maxx, 0, screen.col); + LIMIT(minx, 0, maxx); + + int offset = 0; + int len = strlen(string); + while(minx < maxx && offset < len) { + rune_t u; + int charsize = utf8_decode_buffer(string + offset, len - offset, &u); + offset += charsize; + if (charsize == 1 && u <= 32) + u = ' '; + minx += screen_set_char(u, minx, y); + } + return minx; } void color_selection(struct glyph* letter) { - if (letter->bg == default_attributes.bg) - letter->bg = selection_bg; + if (letter->bg == default_attributes.bg) + letter->bg = selection_bg; } void wb_move_cursor_to_selection_start(struct window_buffer* wb) { - const struct file_buffer* fb = get_fb(wb); - if (fb_is_selection_start_top_left(fb)) - wb_move_to_offset(wb, fb->s1o, CURSOR_SNAPPED); - else - wb_move_to_offset(wb, fb->s2o, CURSOR_SNAPPED); + const struct file_buffer* fb = get_fb(wb); + if (fb_is_selection_start_top_left(fb)) + wb_move_to_offset(wb, fb->s1o, CURSOR_SNAPPED); + else + wb_move_to_offset(wb, fb->s2o, CURSOR_SNAPPED); } void wb_write_selection(struct window_buffer* wb, int minx, int miny, int maxx, int maxy) { - soft_assert(wb, return;); - struct file_buffer* fb = get_fb(wb); - - LIMIT(maxx, 0, screen.col-1); - LIMIT(maxy, 0, screen.row-1); - LIMIT(minx, 0, maxx); - LIMIT(miny, 0, maxy); - - if (!(fb->mode & FB_SELECTION_ON)) - return; - - int x, y, x2, y2, tmp, xscroll; - if (fb_is_selection_start_top_left(fb)) { - fb_offset_to_xy(fb, fb->s1o, maxx - minx, wb->y_scroll, &x, &y, &tmp); - fb_offset_to_xy(fb, fb->s2o, maxx - minx, wb->y_scroll, &x2, &y2, &xscroll); - } else { - fb_offset_to_xy(fb, fb->s2o, maxx - minx, wb->y_scroll, &x, &y, &xscroll); - fb_offset_to_xy(fb, fb->s1o, maxx - minx, wb->y_scroll, &x2, &y2, &tmp); - } - x += minx, x2 += minx + 1; - y += miny, y2 += miny; - if (!wrap_buffer) { - x -= xscroll; - x2 -= xscroll; - } - - - for(; y < y2; y++) { - for(; x <= maxx; x++) - color_selection(screen_set_attr(x, y)); - x = 0; - } - for(; x < x2; x++) - color_selection(screen_set_attr(x, y)); + soft_assert(wb, return;); + struct file_buffer* fb = get_fb(wb); + + LIMIT(maxx, 0, screen.col-1); + LIMIT(maxy, 0, screen.row-1); + LIMIT(minx, 0, maxx); + LIMIT(miny, 0, maxy); + + if (!(fb->mode & FB_SELECTION_ON)) + return; + + int x, y, x2, y2, tmp, xscroll; + if (fb_is_selection_start_top_left(fb)) { + fb_offset_to_xy(fb, fb->s1o, maxx - minx, wb->y_scroll, &x, &y, &tmp); + fb_offset_to_xy(fb, fb->s2o, maxx - minx, wb->y_scroll, &x2, &y2, &xscroll); + } else { + fb_offset_to_xy(fb, fb->s2o, maxx - minx, wb->y_scroll, &x, &y, &xscroll); + fb_offset_to_xy(fb, fb->s1o, maxx - minx, wb->y_scroll, &x2, &y2, &tmp); + } + x += minx, x2 += minx + 1; + y += miny, y2 += miny; + if (!wrap_buffer) { + x -= xscroll; + x2 -= xscroll; + } + + + for(; y < y2; y++) { + for(; x <= maxx; x++) + color_selection(screen_set_attr(x, y)); + x = 0; + } + for(; x < x2; x++) + color_selection(screen_set_attr(x, y)); } diff --git a/seek.c b/seek.c @@ -21,266 +21,266 @@ int str_contains_char(const char* string, char check) { - return strchr(string, check) != NULL; + return strchr(string, check) != NULL; } inline int is_file_type(const char* file_path, const char* file_type) { - int ftlen = strlen(file_type); - int offset = strlen(file_path) - ftlen; - if(offset >= 0 && memcmp(file_path + offset, file_type, ftlen) == 0) - return 1; - return 0; + int ftlen = strlen(file_type); + int offset = strlen(file_path) - ftlen; + if(offset >= 0 && memcmp(file_path + offset, file_type, ftlen) == 0) + return 1; + return 0; } char* file_path_get_path(const char* path) { - soft_assert(path, path = "/";); + soft_assert(path, path = "/";); - const char* folder_start = strrchr(path, '/'); - if (!folder_start) - folder_start = path; - else - folder_start++; - int folder_len = folder_start - path; - char* folder = xmalloc(folder_len + 1); + const char* folder_start = strrchr(path, '/'); + if (!folder_start) + folder_start = path; + else + folder_start++; + int folder_len = folder_start - path; + char* folder = xmalloc(folder_len + 1); - memcpy(folder, path, folder_len); - folder[folder_len] = '\0'; + memcpy(folder, path, folder_len); + folder[folder_len] = '\0'; - return folder; + return folder; } inline int path_is_folder(const char* path) { - struct stat statbuf; - if (stat(path, &statbuf) != 0) - return 0; - return S_ISDIR(statbuf.st_mode); + struct stat statbuf; + if (stat(path, &statbuf) != 0) + return 0; + return S_ISDIR(statbuf.st_mode); } inline int fb_seek_char(const struct file_buffer* fb, int offset, char byte) { - if (offset > fb->len) return -1; - char* new_buf = memchr(fb->contents + offset, byte, fb->len - offset); - if (!new_buf) return -1; - return new_buf - fb->contents; + if (offset > fb->len) return -1; + char* new_buf = memchr(fb->contents + offset, byte, fb->len - offset); + if (!new_buf) return -1; + return new_buf - fb->contents; } inline int fb_seek_char_backwards(const struct file_buffer* fb, int offset, char byte) { - BOUNDS_CHECK(offset, 0, fb->len-1); - for (int n = offset-1; n >= 0; n--) { - if (fb->contents[n] == byte) { - return n+1; + BOUNDS_CHECK(offset, 0, fb->len-1); + for (int n = offset-1; n >= 0; n--) { + if (fb->contents[n] == byte) { + return n+1; + } } - } - return -1; + return -1; } inline int fb_seek_string(const struct file_buffer* fb, int offset, const char* string) { - BOUNDS_CHECK(offset, 0, fb->len-1); - int str_len = strlen(string); + BOUNDS_CHECK(offset, 0, fb->len-1); + int str_len = strlen(string); #if 0 - for (int n = offset; n < fb->len - str_len; n++) - if (!memcmp(fb->contents + n, string, str_len)) - return n; + for (int n = offset; n < fb->len - str_len; n++) + if (!memcmp(fb->contents + n, string, str_len)) + return n; #else - char* res = memmem(fb->contents + offset, fb->len - offset, - string, str_len); - if (res) - return res - fb->contents; + char* res = memmem(fb->contents + offset, fb->len - offset, + string, str_len); + if (res) + return res - fb->contents; #endif - return -1; + return -1; } inline int fb_seek_string_backwards(const struct file_buffer* fb, int offset, const char* string) { - int str_len = strlen(string); - offset += str_len; - BOUNDS_CHECK(offset, 0, fb->len-1); - - for (int n = offset - str_len; n >= 0; n--) - if (!memcmp(fb->contents + n, string, str_len)) - return n; - return -1; + int str_len = strlen(string); + offset += str_len; + BOUNDS_CHECK(offset, 0, fb->len-1); + + for (int n = offset - str_len; n >= 0; n--) + if (!memcmp(fb->contents + n, string, str_len)) + return n; + return -1; } inline int wb_seek_string_wrap(const struct window_buffer* wb, int offset, const char* search) { - struct file_buffer* fb = get_fb(focused_window); - if (*search == 0 || !fb_count_string_instances(fb, search, 0, NULL)) - return -1; + struct file_buffer* fb = get_fb(focused_window); + if (*search == 0 || !fb_count_string_instances(fb, search, 0, NULL)) + return -1; - int new_offset = fb_seek_string(fb, offset, search); - if (new_offset < 0) - new_offset = fb_seek_string(fb, 0, search); + int new_offset = fb_seek_string(fb, offset, search); + if (new_offset < 0) + new_offset = fb_seek_string(fb, 0, search); - if (!(fb->mode & FB_SEARCH_BLOCKING)) - fb->mode |= FB_SEARCH_BLOCKING_IDLE; - return new_offset; + if (!(fb->mode & FB_SEARCH_BLOCKING)) + fb->mode |= FB_SEARCH_BLOCKING_IDLE; + return new_offset; } inline int wb_seek_string_wrap_backwards(const struct window_buffer* wb, int offset, const char* search) { - struct file_buffer* fb = get_fb(focused_window); - if (*search == 0 || !fb_count_string_instances(fb, search, 0, NULL)) - return -1; + struct file_buffer* fb = get_fb(focused_window); + if (*search == 0 || !fb_count_string_instances(fb, search, 0, NULL)) + return -1; - int new_offset = fb_seek_string_backwards(fb, offset, search); - if (new_offset < 0) - new_offset = fb_seek_string_backwards(fb, fb->len, search); + int new_offset = fb_seek_string_backwards(fb, offset, search); + if (new_offset < 0) + new_offset = fb_seek_string_backwards(fb, fb->len, search); - if (!(fb->mode & FB_SEARCH_BLOCKING)) - fb->mode |= FB_SEARCH_BLOCKING_IDLE; - return new_offset; + if (!(fb->mode & FB_SEARCH_BLOCKING)) + fb->mode |= FB_SEARCH_BLOCKING_IDLE; + return new_offset; } int fb_is_on_a_word(const struct file_buffer* fb, int offset, const char* word_seperators) { - BOUNDS_CHECK(offset, 0, fb->len); - return !str_contains_char(word_seperators, fb->contents[offset]); + BOUNDS_CHECK(offset, 0, fb->len); + return !str_contains_char(word_seperators, fb->contents[offset]); } inline int fb_is_start_of_a_word(const struct file_buffer* fb, int offset, const char* word_seperators) { - BOUNDS_CHECK(offset, 0, fb->len); - return fb_is_on_a_word(fb, offset, word_seperators) && - (offset-1 <= 0 || str_contains_char(word_seperators, fb->contents[offset-1])); + BOUNDS_CHECK(offset, 0, fb->len); + return fb_is_on_a_word(fb, offset, word_seperators) && + (offset-1 <= 0 || str_contains_char(word_seperators, fb->contents[offset-1])); } inline int fb_is_on_word(const struct file_buffer* fb, int offset, const char* word_seperators, const char* word) { - BOUNDS_CHECK(offset, 0, fb->len); - int word_start = fb_seek_start_of_word_backwards(fb, offset, word_seperators); - int word_len = strlen(word); - if (word_start < offset - (word_len-1)) - return 0; - return fb_offset_starts_with(fb, word_start, word) && - !fb_is_on_a_word(fb, word_start + word_len, word_seperators); + BOUNDS_CHECK(offset, 0, fb->len); + int word_start = fb_seek_start_of_word_backwards(fb, offset, word_seperators); + int word_len = strlen(word); + if (word_start < offset - (word_len-1)) + return 0; + return fb_offset_starts_with(fb, word_start, word) && + !fb_is_on_a_word(fb, word_start + word_len, word_seperators); } inline int fb_offset_starts_with(const struct file_buffer* fb, int offset, const char* start) { - BOUNDS_CHECK(offset, 0, fb->len); - if (offset > 0 && fb->contents[offset-1] == '\\') return 0; + BOUNDS_CHECK(offset, 0, fb->len); + if (offset > 0 && fb->contents[offset-1] == '\\') return 0; - int len = strlen(start); - int mlen = MIN(len, fb->len - offset); - return memcmp(fb->contents + offset, start, mlen) == 0; + int len = strlen(start); + int mlen = MIN(len, fb->len - offset); + return memcmp(fb->contents + offset, start, mlen) == 0; } inline int fb_seek_word(const struct file_buffer* fb, int offset, const char* word_seperators) { - if (fb_is_on_a_word(fb, offset, word_seperators)) - offset = fb_seek_word_end(fb, offset, word_seperators); - while (offset < fb->len && str_contains_char(word_seperators, fb->contents[offset])) offset++; - return offset; + if (fb_is_on_a_word(fb, offset, word_seperators)) + offset = fb_seek_word_end(fb, offset, word_seperators); + while (offset < fb->len && str_contains_char(word_seperators, fb->contents[offset])) offset++; + return offset; } inline int fb_seek_word_end(const struct file_buffer* fb, int offset, const char* word_seperators) { - BOUNDS_CHECK(offset, 0, fb->len); - if (!fb_is_on_a_word(fb, offset, word_seperators)) - offset = fb_seek_word(fb, offset, word_seperators); - while (offset < fb->len && !str_contains_char(word_seperators, fb->contents[offset])) offset++; - return offset; + BOUNDS_CHECK(offset, 0, fb->len); + if (!fb_is_on_a_word(fb, offset, word_seperators)) + offset = fb_seek_word(fb, offset, word_seperators); + while (offset < fb->len && !str_contains_char(word_seperators, fb->contents[offset])) offset++; + return offset; } inline int fb_seek_word_backwards(const struct file_buffer* fb, int offset, const char* word_seperators) { - BOUNDS_CHECK(offset, 0, fb->len); - if (!fb_is_on_a_word(fb, offset, word_seperators)) - while (offset > 0 && str_contains_char(word_seperators, fb->contents[offset])) offset--; - return offset; + BOUNDS_CHECK(offset, 0, fb->len); + if (!fb_is_on_a_word(fb, offset, word_seperators)) + while (offset > 0 && str_contains_char(word_seperators, fb->contents[offset])) offset--; + return offset; } inline int fb_seek_start_of_word_backwards(const struct file_buffer* fb, int offset, const char* word_seperators) { - BOUNDS_CHECK(offset, 0, fb->len); - if (!fb_is_on_a_word(fb, offset, word_seperators)) - while (offset > 0 && str_contains_char(word_seperators, fb->contents[offset])) offset--; - while (offset > 0 && !str_contains_char(word_seperators, fb->contents[offset])) offset--; - return offset+1; + BOUNDS_CHECK(offset, 0, fb->len); + if (!fb_is_on_a_word(fb, offset, word_seperators)) + while (offset > 0 && str_contains_char(word_seperators, fb->contents[offset])) offset--; + while (offset > 0 && !str_contains_char(word_seperators, fb->contents[offset])) offset--; + return offset+1; } inline int fb_seek_whitespace(const struct file_buffer* fb, int offset) { - BOUNDS_CHECK(offset, 0, fb->len); - while (offset < fb->len && !isspace(fb->contents[offset])) offset++; - return offset; + BOUNDS_CHECK(offset, 0, fb->len); + while (offset < fb->len && !isspace(fb->contents[offset])) offset++; + return offset; } inline int fb_seek_whitespace_backwards(const struct file_buffer* fb, int offset) { - BOUNDS_CHECK(offset, 0, fb->len); - while (offset > 0 && !isspace(fb->contents[offset])) offset--; - return offset; + BOUNDS_CHECK(offset, 0, fb->len); + while (offset > 0 && !isspace(fb->contents[offset])) offset--; + return offset; } inline int fb_seek_not_whitespace(const struct file_buffer* fb, int offset) { - BOUNDS_CHECK(offset, 0, fb->len); - while (offset < fb->len && isspace(fb->contents[offset])) offset++; - return offset; + BOUNDS_CHECK(offset, 0, fb->len); + while (offset < fb->len && isspace(fb->contents[offset])) offset++; + return offset; } inline int fb_seek_not_whitespace_backwards(const struct file_buffer* fb, int offset) { - BOUNDS_CHECK(offset, 0, fb->len); - while (offset > 0 && isspace(fb->contents[offset])) offset--; - return offset; + BOUNDS_CHECK(offset, 0, fb->len); + while (offset > 0 && isspace(fb->contents[offset])) offset--; + return offset; } inline int fb_count_string_instances(const struct file_buffer* fb, const char* string, int offset, int* before_offset) { - int tmp; - if (!before_offset) - before_offset = &tmp; - if (!string || *string == 0) { - *before_offset = 0; - return 0; - } - - int pos = -1; - int count = 0; - int once = 1; - while((pos = fb_seek_string(fb, pos+1, string)) >= 0) { - if (pos > 0 && fb->contents[pos-2] == '\\') - continue; - if (once && pos > offset) { - *before_offset = count; - once = 0; + int tmp; + if (!before_offset) + before_offset = &tmp; + if (!string || *string == 0) { + *before_offset = 0; + return 0; } - count++; - } - if (once) - *before_offset = count; - return count; + + int pos = -1; + int count = 0; + int once = 1; + while((pos = fb_seek_string(fb, pos+1, string)) >= 0) { + if (pos > 0 && fb->contents[pos-2] == '\\') + continue; + if (once && pos > offset) { + *before_offset = count; + once = 0; + } + count++; + } + if (once) + *before_offset = count; + return count; } /* @@ -296,189 +296,189 @@ fb_count_string_instances(const struct file_buffer* fb, const char* string, int int fb_seek_string_not_escaped(const struct file_buffer* fb, int offset, const char* string) { - for (;;) { - offset = fb_seek_string(fb, offset, string); - if (offset >= 0 && fb->contents[offset-1] == '\\') - offset++; - else - break; - } - return offset; + for (;;) { + offset = fb_seek_string(fb, offset, string); + if (offset >= 0 && fb->contents[offset-1] == '\\') + offset++; + else + break; + } + return offset; } inline int fb_seek_string_backwards_not_escaped(const struct file_buffer* fb, int offset, const char* string) { - for (;;) { - offset = fb_seek_string_backwards(fb, offset, string); - if (offset >= 0 && fb->contents[offset-1] == '\\') - offset--; - else - break; - } - return offset; + for (;;) { + offset = fb_seek_string_backwards(fb, offset, string); + if (offset >= 0 && fb->contents[offset-1] == '\\') + offset--; + else + break; + } + return offset; } inline static int fb_get_delimiter_equal_start_end(const struct file_buffer* fb, int offset, const char* string, struct delimiter* ignore, int* start, int* end) { - int ignore_index = 0; - int last_distance = 0; - - while (last_distance >= 0) { - int d_res = INT32_MAX; - int i = 0; - if (ignore) { - for (struct delimiter* ign = ignore; ign->start; ign++) { - int d = fb_seek_string_not_escaped(fb, last_distance, ign->start); - if (d < 0 || d > offset) { - i++; - continue; + int ignore_index = 0; + int last_distance = 0; + + while (last_distance >= 0) { + int d_res = INT32_MAX; + int i = 0; + if (ignore) { + for (struct delimiter* ign = ignore; ign->start; ign++) { + int d = fb_seek_string_not_escaped(fb, last_distance, ign->start); + if (d < 0 || d > offset) { + i++; + continue; + } + + if (d < d_res) { + d_res = d; + ignore_index = i; + } + i++; + } } - - if (d < d_res) { - d_res = d; - ignore_index = i; + int str_d = fb_seek_string_not_escaped(fb, last_distance, string); + + if ((str_d <= 0 || str_d > offset) && d_res == INT32_MAX) + return 0; + + const char* end_str; + if (str_d >= 0 && str_d <= d_res) { + last_distance = str_d; + end_str = string; + *start = last_distance; + } else { + last_distance = d_res; + end_str = ignore[ignore_index].end; } - i++; - } - } - int str_d = fb_seek_string_not_escaped(fb, last_distance, string); - - if ((str_d <= 0 || str_d > offset) && d_res == INT32_MAX) - return 0; - - const char* end_str; - if (str_d >= 0 && str_d <= d_res) { - last_distance = str_d; - end_str = string; - *start = last_distance; - } else { - last_distance = d_res; - end_str = ignore[ignore_index].end; - } - last_distance = fb_seek_string_not_escaped(fb, last_distance+1, end_str); + last_distance = fb_seek_string_not_escaped(fb, last_distance+1, end_str); - if (end_str == string && last_distance > offset) { - *end = last_distance; - return 1; + if (end_str == string && last_distance > offset) { + *end = last_distance; + return 1; + } + if (last_distance >= 0) + last_distance++; } - if (last_distance >= 0) - last_distance++; - } - return 0; + return 0; } inline static int fb_get_matched_delimiter_end(const struct file_buffer* fb, int offset, struct delimiter d) { - int closers_left = 1; - while (closers_left) { - int next_open = fb_seek_string_not_escaped(fb, offset, d.start); - int next_close = fb_seek_string_not_escaped(fb, offset, d.end); - - if (next_close < 0 || next_open < 0) - return next_close; - - if (next_open < next_close) { - closers_left++; - offset = next_open+1; - } else { - closers_left--; - offset = next_close; - if (closers_left) - offset++; + int closers_left = 1; + while (closers_left) { + int next_open = fb_seek_string_not_escaped(fb, offset, d.start); + int next_close = fb_seek_string_not_escaped(fb, offset, d.end); + + if (next_close < 0 || next_open < 0) + return next_close; + + if (next_open < next_close) { + closers_left++; + offset = next_open+1; + } else { + closers_left--; + offset = next_close; + if (closers_left) + offset++; + } } - } - return offset; + return offset; } inline static int fb_get_matched_delimiter_start(const struct file_buffer* fb, int offset, struct delimiter d) { - int openers_left = 1; - while (openers_left) { - int next_open = fb_seek_string_backwards_not_escaped(fb, offset, d.start); - int next_close = fb_seek_string_backwards_not_escaped(fb, offset, d.end); - - if (next_close < 0 || next_open < 0) - return next_open; - - if (next_open < next_close) { - openers_left++; - offset = next_open-1; - } else { - openers_left--; - offset = next_open; - if (openers_left) - offset--; + int openers_left = 1; + while (openers_left) { + int next_open = fb_seek_string_backwards_not_escaped(fb, offset, d.start); + int next_close = fb_seek_string_backwards_not_escaped(fb, offset, d.end); + + if (next_close < 0 || next_open < 0) + return next_open; + + if (next_open < next_close) { + openers_left++; + offset = next_open-1; + } else { + openers_left--; + offset = next_open; + if (openers_left) + offset--; + } } - } - return offset; + return offset; } inline int fb_get_delimiter(const struct file_buffer* fb, int offset, struct delimiter d, struct delimiter* ignore, int* start, int* end) { - const char* start_word = d.start; - const char* end_word = d.end; - - soft_assert(start, return 0;); - soft_assert(end, return 0;); - soft_assert(start_word, return 0;); - soft_assert(end_word, return 0;); - - if (strcmp(start_word, end_word) == 0) - return fb_get_delimiter_equal_start_end(fb, offset, start_word, ignore, start, end); - int wanted_opener = fb_get_matched_delimiter_start(fb, offset, d); - - int ignore_index = 0; - int last_distance = 0; - - while (last_distance >= 0) { - int d_res = INT32_MAX; - int i = 0; - if (ignore) { - for (struct delimiter* ign = ignore; ign->start; ign++) { - int d = fb_seek_string_not_escaped(fb, last_distance, ign->start); - if (d < 0 || d > offset) { - i++; - continue; + const char* start_word = d.start; + const char* end_word = d.end; + + soft_assert(start, return 0;); + soft_assert(end, return 0;); + soft_assert(start_word, return 0;); + soft_assert(end_word, return 0;); + + if (strcmp(start_word, end_word) == 0) + return fb_get_delimiter_equal_start_end(fb, offset, start_word, ignore, start, end); + int wanted_opener = fb_get_matched_delimiter_start(fb, offset, d); + + int ignore_index = 0; + int last_distance = 0; + + while (last_distance >= 0) { + int d_res = INT32_MAX; + int i = 0; + if (ignore) { + for (struct delimiter* ign = ignore; ign->start; ign++) { + int d = fb_seek_string_not_escaped(fb, last_distance, ign->start); + if (d < 0 || d > offset) { + i++; + continue; + } + + if (d < d_res) { + d_res = d; + ignore_index = i; + } + i++; + } } + int str_d = fb_seek_string_not_escaped(fb, last_distance, start_word); - if (d < d_res) { - d_res = d; - ignore_index = i; - } - i++; - } - } - int str_d = fb_seek_string_not_escaped(fb, last_distance, start_word); + if ((str_d <= 0 || str_d > offset) && d_res == INT32_MAX) + return 0; - if ((str_d <= 0 || str_d > offset) && d_res == INT32_MAX) - return 0; + if (str_d >= 0 && str_d <= d_res) { + if (str_d == wanted_opener) { + last_distance = str_d; + *start = last_distance; - if (str_d >= 0 && str_d <= d_res) { - if (str_d == wanted_opener) { - last_distance = str_d; - *start = last_distance; + last_distance = fb_get_matched_delimiter_end(fb, last_distance+1, d); - last_distance = fb_get_matched_delimiter_end(fb, last_distance+1, d); + if (last_distance > offset) { + *end = last_distance; + return 1; + } + } + } else { + last_distance = d_res; - if (last_distance > offset) { - *end = last_distance; - return 1; + last_distance = fb_seek_string_not_escaped(fb, last_distance+1, ignore[ignore_index].end); } - } - } else { - last_distance = d_res; - last_distance = fb_seek_string_not_escaped(fb, last_distance+1, ignore[ignore_index].end); + if (last_distance >= 0) + last_distance++; } - - if (last_distance >= 0) - last_distance++; - } - return 0; + return 0; } diff --git a/seek.h b/seek.h @@ -8,8 +8,8 @@ #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) struct delimiter { - char* start; - char* end; + char* start; + char* end; }; int str_contains_char(const char* string, char check); diff --git a/utf8.c b/utf8.c @@ -17,101 +17,101 @@ static size_t utf8_validate(rune_t *, size_t); rune_t utf8_decodebyte(char c, size_t *i) { - for (*i = 0; *i < LEN(utfmask); ++(*i)) - if (((uint8_t)c & utfmask[*i]) == utfbyte[*i]) - return (uint8_t)c & ~utfmask[*i]; - return 0; + for (*i = 0; *i < LEN(utfmask); ++(*i)) + if (((uint8_t)c & utfmask[*i]) == utfbyte[*i]) + return (uint8_t)c & ~utfmask[*i]; + return 0; } size_t utf8_encode(rune_t u, char *c) { - size_t len, i; + size_t len, i; - len = utf8_validate(&u, 0); - if (len > UTF_SIZ) - return 0; + len = utf8_validate(&u, 0); + if (len > UTF_SIZ) + return 0; - for (i = len - 1; i != 0; --i) { - c[i] = utf8_encodebyte(u, 0); - u >>= 6; - } - c[0] = utf8_encodebyte(u, len); + for (i = len - 1; i != 0; --i) { + c[i] = utf8_encodebyte(u, 0); + u >>= 6; + } + c[0] = utf8_encodebyte(u, len); - return len; + return len; } char utf8_encodebyte(rune_t u, size_t i) { - return utfbyte[i] | (u & ~utfmask[i]); + return utfbyte[i] | (u & ~utfmask[i]); } size_t utf8_validate(rune_t *u, size_t i) { - const rune_t utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; - const rune_t utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + const rune_t utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; + const rune_t utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; - if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) - *u = UTF_INVALID; - for (i = 1; *u > utfmax[i]; ++i) - ; + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; - return i; + return i; } size_t utf8_decode(const char *c, rune_t *u, size_t clen) { - size_t i, j, len, type; - rune_t udecoded; + size_t i, j, len, type; + rune_t udecoded; - *u = UTF_INVALID; - if (!clen) - return 0; - udecoded = utf8_decodebyte(c[0], &len); - if (!BETWEEN(len, 1, UTF_SIZ)) - return 1; - for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { - udecoded = (udecoded << 6) | utf8_decodebyte(c[i], &type); - if (type != 0) - return j; - } - if (j < len) - return 0; - *u = udecoded; - utf8_validate(u, len); - - return len; + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8_decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8_decodebyte(c[i], &type); + if (type != 0) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8_validate(u, len); + + return len; } int utf8_decode_buffer(const char* buffer, const int buflen, rune_t* u) { - if (!buflen) return 0; + if (!buflen) return 0; - rune_t u_tmp; - int charsize; - if (!u) - u = &u_tmp; + rune_t u_tmp; + int charsize; + if (!u) + u = &u_tmp; - // process a complete utf8 char - charsize = utf8_decode(buffer, u, buflen); + // process a complete utf8 char + charsize = utf8_decode(buffer, u, buflen); - return charsize; + return charsize; } void utf8_remove_string_end(char* string) { - char* end = string + strlen(string); - if (end == string) - return; - - do { - end--; - // if byte starts with 0b10, byte is an UTF-8 extender - } while (end > string && (*end & 0xC0) == 0x80); - *end = 0; + char* end = string + strlen(string); + if (end == string) + return; + + do { + end--; + // if byte starts with 0b10, byte is an UTF-8 extender + } while (end > string && (*end & 0xC0) == 0x80); + *end = 0; } diff --git a/x.c b/x.c @@ -31,15 +31,15 @@ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 -#define IS_SET(flag) ((win.mode & (flag)) != 0) -#define TRUERED(x) (((x) & 0xff0000) >> 8) -#define TRUEGREEN(x) (((x) & 0xff00)) -#define TRUEBLUE(x) (((x) & 0xff) << 8) -#define DEFAULT(a, b) (a) = (a) ? (a) : (b) -#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) -#define IS_TRUECOL(x) (1 << 24 & (x)) -#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) -#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) +#define IS_SET(flag) ((win.mode & (flag)) != 0) +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) +#define DEFAULT(a, b) (a) = (a) ? (a) : (b) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) +#define IS_TRUECOL(x) (1 << 24 & (x)) +#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #include <X11/Xatom.h> #include <X11/cursorfont.h> @@ -48,11 +48,11 @@ // Purely graphic info typedef struct { - int tw, th; // tty width and height - int w, h; // window width and height - int ch; // char height - int cw; // char width - int mode; // window state/mode flags + int tw, th; // tty width and height + int w, h; // window width and height + int ch; // char height + int cw; // char width + int mode; // window state/mode flags } TermWindow; extern TermWindow win; @@ -61,56 +61,56 @@ typedef XftColor Color; typedef XftGlyphFontSpec GlyphFontSpec; typedef struct { - Display *dpy; - Colormap cmap; - Window win; - Drawable buf; - GlyphFontSpec *specbuf; // font spec buffer used for rendering - Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; - struct { - XIM xim; - XIC xic; - XPoint spot; - XVaNestedList spotlist; - } ime; - Draw draw; - Visual *vis; - XSetWindowAttributes attrs; - int scr; - int isfixed; // is fixed geometry? - int l, t; // left and top offset - int gm; // geometry mask + Display *dpy; + Colormap cmap; + Window win; + Drawable buf; + GlyphFontSpec *specbuf; // font spec buffer used for rendering + Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; + struct { + XIM xim; + XIC xic; + XPoint spot; + XVaNestedList spotlist; + } ime; + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; + int scr; + int isfixed; // is fixed geometry? + int l, t; // left and top offset + int gm; // geometry mask } XWindow; extern XWindow xw; // Font structure #define Font Font_ typedef struct { - int height; - int width; - int ascent; - int descent; - int badslant; - int badweight; - short lbearing; - short rbearing; - XftFont *match; - FcFontSet *set; - FcPattern *pattern; + int height; + int width; + int ascent; + int descent; + int badslant; + int badweight; + short lbearing; + short rbearing; + XftFont *match; + FcFontSet *set; + FcPattern *pattern; } Font; // Font Ring Cache enum { - FRC_NORMAL, - FRC_ITALIC, - FRC_BOLD, - FRC_ITALICBOLD + FRC_NORMAL, + FRC_ITALIC, + FRC_BOLD, + FRC_ITALICBOLD }; typedef struct { - XftFont *font; - int flags; - rune_t unicodep; + XftFont *font; + int flags; + rune_t unicodep; } Fontcache; extern Fontcache *frc; @@ -118,10 +118,10 @@ extern int frclen; // Drawing Context typedef struct { - Color *col; - size_t collen; - Font font, bfont, ifont, ibfont; - GC gc; + Color *col; + size_t collen; + Font font, bfont, ifont, ibfont; + GC gc; } DC; extern DC dc; @@ -164,17 +164,17 @@ static void resize(XEvent *); static void focus(XEvent *); static void (*handler[LASTEvent])(XEvent *) = { - [KeyPress] = kpress, - [ClientMessage] = cmessage, - [ConfigureNotify] = resize, - [VisibilityNotify] = visibility, - [UnmapNotify] = unmap, - [Expose] = expose, - [FocusIn] = focus, - [FocusOut] = focus, - [PropertyNotify] = propnotify, - [SelectionNotify] = selnotify, - [SelectionRequest] = selrequest, + [KeyPress] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, + [UnmapNotify] = unmap, + [Expose] = expose, + [FocusIn] = focus, + [FocusOut] = focus, + [PropertyNotify] = propnotify, + [SelectionNotify] = selnotify, + [SelectionRequest] = selrequest, }; //////////////////////////////////////////////// @@ -206,111 +206,111 @@ double usedfontsize = 0; void screen_init(int col, int row) { - global_attr = default_attributes; + global_attr = default_attributes; - screen.col = 0; - screen.row = 0; - screen.lines = NULL; - screen_resize(col, row); + screen.col = 0; + screen.row = 0; + screen.lines = NULL; + screen_resize(col, row); } void draw_horisontal_line(int y, int x1, int x2) { - if (y < 0 || y > screen.row || - x2 < x1 || x2 > screen.col || - x1 < 0 || x1 > x2-1) - return; - - Color drawcol = dc.col[default_attributes.fg]; - XftDrawRect(xw.draw, &drawcol, - border_px + x1 * win.cw, border_px + (y + 1) * win.ch - cursor_thickness, - win.cw * (x2-x1+1), 1); + if (y < 0 || y > screen.row || + x2 < x1 || x2 > screen.col || + x1 < 0 || x1 > x2-1) + return; + + Color drawcol = dc.col[default_attributes.fg]; + XftDrawRect(xw.draw, &drawcol, + border_px + x1 * win.cw, border_px + (y + 1) * win.ch - cursor_thickness, + win.cw * (x2-x1+1), 1); } void set_clipboard_copy(char* buffer, int len) { - if (!buffer) - return; - if (copy_buffer) - free(copy_buffer); - copy_buffer = buffer; - copy_len = len; - - Atom clipboard; - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + if (!buffer) + return; + if (copy_buffer) + free(copy_buffer); + copy_buffer = buffer; + copy_len = len; + + Atom clipboard; + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); } void execute_clipbaord_event() { - Atom clipboard; + Atom clipboard; - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XConvertSelection(xw.dpy, clipboard, xtarget, clipboard, - xw.win, CurrentTime); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xtarget, clipboard, + xw.win, CurrentTime); } int screen_set_char(rune_t u, int x, int y) { - struct glyph attr = global_attr; - if (y >= screen.row || x >= screen.col || - y < 0 || x < 0) - return 1; - - if (u == 0) - u = screen.lines[y][x].u; - int width = wcwidth(u); - if (width == -1) - width = 1; - else if (width > 1) - attr.mode |= ATTR_WIDE; - - if (screen.lines[y][x].mode & ATTR_WIDE || attr.mode & ATTR_WIDE) { - if (x+1 < screen.col) { - screen.lines[y][x+1].u = ' '; - screen.lines[y][x+1].mode |= ATTR_WDUMMY; - } - } else if (screen.lines[y][x].mode & ATTR_WDUMMY && x-1 >= 0) { - screen.lines[y][x-1].u = ' '; - screen.lines[y][x-1].mode &= ~ATTR_WIDE; - } - - screen.lines[y][x] = attr; - screen.lines[y][x].u = u; - - return width; + struct glyph attr = global_attr; + if (y >= screen.row || x >= screen.col || + y < 0 || x < 0) + return 1; + + if (u == 0) + u = screen.lines[y][x].u; + int width = wcwidth(u); + if (width == -1) + width = 1; + else if (width > 1) + attr.mode |= ATTR_WIDE; + + if (screen.lines[y][x].mode & ATTR_WIDE || attr.mode & ATTR_WIDE) { + if (x+1 < screen.col) { + screen.lines[y][x+1].u = ' '; + screen.lines[y][x+1].mode |= ATTR_WDUMMY; + } + } else if (screen.lines[y][x].mode & ATTR_WDUMMY && x-1 >= 0) { + screen.lines[y][x-1].u = ' '; + screen.lines[y][x-1].mode &= ~ATTR_WIDE; + } + + screen.lines[y][x] = attr; + screen.lines[y][x].u = u; + + return width; } void* xmalloc(size_t len) { - void *p; - if (!(p = malloc(len))) - die("malloc: error, reutrned NULL | errno: %s\n", strerror(errno)); - return p; + void *p; + if (!(p = malloc(len))) + die("malloc: error, reutrned NULL | errno: %s\n", strerror(errno)); + return p; } void* xrealloc(void *p, size_t len) { - if ((p = realloc(p, len)) == NULL) - die("realloc: error, returned NULL | errno: %s\n", strerror(errno)); - return p; + if ((p = realloc(p, len)) == NULL) + die("realloc: error, returned NULL | errno: %s\n", strerror(errno)); + return p; } void die(const char *errstr, ...) { - va_list ap; + va_list ap; - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - assert(0); + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + assert(0); } //////////////////////////////////////////////// @@ -320,49 +320,49 @@ die(const char *errstr, ...) struct glyph* screen_set_attr(int x, int y) { - static struct glyph dummy; - if (y >= screen.row || x >= screen.col || - y < 0 || x < 0) - return &dummy; + static struct glyph dummy; + if (y >= screen.row || x >= screen.col || + y < 0 || x < 0) + return &dummy; - return &screen.lines[y][x]; + return &screen.lines[y][x]; } void screen_set_region(int x1, int y1, int x2, int y2, rune_t u) { - for (int y = y1; y <= y2; y++) - for (int x = x1; x <= x2; x++) - screen_set_char(u, x, y); + for (int y = y1; y <= y2; y++) + for (int x = x1; x <= x2; x++) + screen_set_char(u, x, y); } void screen_resize(int col, int row) { - if (col < 1 || row < 1) { - fprintf(stderr, - "tresize: error resizing to %dx%d\n", col, row); - return; - } - - // resize to new height - for (int i = row; i < screen.row; i++) - free(screen.lines[i]); - - screen.lines = xrealloc(screen.lines, row * sizeof(*screen.lines)); - - for (int i = screen.row; i < row; i++) - screen.lines[i] = NULL; - - // resize each row to new width, zero-pad if needed - for (int i = 0; i < row; i++) { - screen.lines[i] = xrealloc(screen.lines[i], col * sizeof(struct glyph)); - memset(screen.lines[i], 0, col * sizeof(struct glyph)); - } - - // update terminal size - screen.col = col; - screen.row = row; + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); + return; + } + + // resize to new height + for (int i = row; i < screen.row; i++) + free(screen.lines[i]); + + screen.lines = xrealloc(screen.lines, row * sizeof(*screen.lines)); + + for (int i = screen.row; i < row; i++) + screen.lines[i] = NULL; + + // resize each row to new width, zero-pad if needed + for (int i = 0; i < row; i++) { + screen.lines[i] = xrealloc(screen.lines[i], col * sizeof(struct glyph)); + memset(screen.lines[i], 0, col * sizeof(struct glyph)); + } + + // update terminal size + screen.col = col; + screen.row = row; } @@ -371,250 +371,250 @@ screen_resize(int col, int row) void propnotify(XEvent *e) { - XPropertyEvent *xpev; - Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - - xpev = &e->xproperty; - if (xpev->state == PropertyNewValue && - (xpev->atom == XA_PRIMARY || - xpev->atom == clipboard)) { - selnotify(e); - } + XPropertyEvent *xpev; + Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + + xpev = &e->xproperty; + if (xpev->state == PropertyNewValue && + (xpev->atom == XA_PRIMARY || + xpev->atom == clipboard)) { + selnotify(e); + } } void selnotify(XEvent *e) { - unsigned long nitems, ofs, rem; - int format; - uint8_t *data, *last, *repl; - Atom type, incratom, property = None; - - incratom = XInternAtom(xw.dpy, "INCR", 0); - - ofs = 0; - if (e->type == SelectionNotify) - property = e->xselection.property; - else if (e->type == PropertyNotify) - property = e->xproperty.atom; - - if (property == None) - return; - - do { - if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, - BUFSIZ/4, False, AnyPropertyType, - &type, &format, &nitems, &rem, - &data)) { - fprintf(stderr, "Clipboard allocation failed\n"); - return; - } - - if (e->type == PropertyNotify && nitems == 0 && rem == 0) { - /* - * If there is some PropertyNotify with no data, then - * this is the signal of the selection owner that all - * data has been transferred. We won't need to receive - * PropertyNotify events anymore. - */ - MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, - &xw.attrs); - } - - if (type == incratom) { - /* - * Activate the PropertyNotify events so we receive - * when the selection owner does send us the next - * chunk of data. - */ - MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, - &xw.attrs); - - // Deleting the property is the transfer start signal. - XDeleteProperty(xw.dpy, xw.win, (int)property); - continue; - } - - // replace all '\r' with '\n'. - repl = data; - last = data + nitems * format / 8; - while ((repl = memchr(repl, '\r', last - repl))) { - *repl++ = '\n'; - } - - struct file_buffer* fb = get_fb(focused_window); - if (fb->contents) { - if (fb->mode & FB_SELECTION_ON) { - fb_remove_selection(fb); - wb_move_cursor_to_selection_start(focused_window); - fb->mode &= ~(FB_SELECTION_ON); - } - call_extension(fb_paste, fb, (char*)data, nitems * format / 8); - call_extension(fb_contents_updated, fb, focused_window->cursor_offset, FB_CONTENT_BIG_CHANGE); - } - XFree(data); - /* number of 32-bit chunks returned */ - ofs += nitems * format / 32; - } while (rem > 0); - - /* - * Deleting the property again tells the selection owner to send the - * next data chunk in the property. - */ - XDeleteProperty(xw.dpy, xw.win, (int)property); + unsigned long nitems, ofs, rem; + int format; + uint8_t *data, *last, *repl; + Atom type, incratom, property = None; + + incratom = XInternAtom(xw.dpy, "INCR", 0); + + ofs = 0; + if (e->type == SelectionNotify) + property = e->xselection.property; + else if (e->type == PropertyNotify) + property = e->xproperty.atom; + + if (property == None) + return; + + do { + if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, + BUFSIZ/4, False, AnyPropertyType, + &type, &format, &nitems, &rem, + &data)) { + fprintf(stderr, "Clipboard allocation failed\n"); + return; + } + + if (e->type == PropertyNotify && nitems == 0 && rem == 0) { + /* + * If there is some PropertyNotify with no data, then + * this is the signal of the selection owner that all + * data has been transferred. We won't need to receive + * PropertyNotify events anymore. + */ + MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + } + + if (type == incratom) { + /* + * Activate the PropertyNotify events so we receive + * when the selection owner does send us the next + * chunk of data. + */ + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + + // Deleting the property is the transfer start signal. + XDeleteProperty(xw.dpy, xw.win, (int)property); + continue; + } + + // replace all '\r' with '\n'. + repl = data; + last = data + nitems * format / 8; + while ((repl = memchr(repl, '\r', last - repl))) { + *repl++ = '\n'; + } + + struct file_buffer* fb = get_fb(focused_window); + if (fb->contents) { + if (fb->mode & FB_SELECTION_ON) { + fb_remove_selection(fb); + wb_move_cursor_to_selection_start(focused_window); + fb->mode &= ~(FB_SELECTION_ON); + } + call_extension(fb_paste, fb, (char*)data, nitems * format / 8); + call_extension(fb_contents_updated, fb, focused_window->cursor_offset, FB_CONTENT_BIG_CHANGE); + } + XFree(data); + /* number of 32-bit chunks returned */ + ofs += nitems * format / 32; + } while (rem > 0); + + /* + * Deleting the property again tells the selection owner to send the + * next data chunk in the property. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); } void selrequest(XEvent *e) { - XSelectionRequestEvent *xsre = (XSelectionRequestEvent *) e; - XSelectionEvent xev = {0}; - Atom xa_targets, string, clipboard; - char *seltext = NULL; - - xev.type = SelectionNotify; - xev.requestor = xsre->requestor; - xev.selection = xsre->selection; - xev.target = xsre->target; - xev.time = xsre->time; - if (xsre->property == None) - xsre->property = xsre->target; - - // reject - xev.property = None; - - xa_targets = XInternAtom(xw.dpy, "TARGETS", 0); - if (xsre->target == xa_targets) { - // respond with the supported type - string = xtarget; - XChangeProperty(xsre->display, xsre->requestor, xsre->property, - XA_ATOM, 32, PropModeReplace, - (uint8_t *) &string, 1); - xev.property = xsre->property; - } else if (xsre->target == xtarget || xsre->target == XA_STRING) { - /* - * xith XA_STRING non ascii characters may be incorrect in the - * requestor. It is not our problem, use utf8. - */ - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - int sel_len; - if (xsre->selection == XA_PRIMARY) { - seltext = fb_get_selection(get_fb(focused_window), &sel_len); - } else if (xsre->selection == clipboard) { - seltext = copy_buffer; - sel_len = copy_len; - } else { - fprintf(stderr, - "Unhandled clipboard selection 0x%lx\n", - xsre->selection); - return; - } - if (seltext) { - XChangeProperty(xsre->display, xsre->requestor, - xsre->property, xsre->target, - 8, PropModeReplace, - (uint8_t *)seltext, sel_len); - xev.property = xsre->property; - if (seltext != copy_buffer) - free(seltext); - } - } - - // all done, send a notification to the listener - if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev)) - fprintf(stderr, "Error sending SelectionNotify event\n"); + XSelectionRequestEvent *xsre = (XSelectionRequestEvent *) e; + XSelectionEvent xev = {0}; + Atom xa_targets, string, clipboard; + char *seltext = NULL; + + xev.type = SelectionNotify; + xev.requestor = xsre->requestor; + xev.selection = xsre->selection; + xev.target = xsre->target; + xev.time = xsre->time; + if (xsre->property == None) + xsre->property = xsre->target; + + // reject + xev.property = None; + + xa_targets = XInternAtom(xw.dpy, "TARGETS", 0); + if (xsre->target == xa_targets) { + // respond with the supported type + string = xtarget; + XChangeProperty(xsre->display, xsre->requestor, xsre->property, + XA_ATOM, 32, PropModeReplace, + (uint8_t *) &string, 1); + xev.property = xsre->property; + } else if (xsre->target == xtarget || xsre->target == XA_STRING) { + /* + * xith XA_STRING non ascii characters may be incorrect in the + * requestor. It is not our problem, use utf8. + */ + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + int sel_len; + if (xsre->selection == XA_PRIMARY) { + seltext = fb_get_selection(get_fb(focused_window), &sel_len); + } else if (xsre->selection == clipboard) { + seltext = copy_buffer; + sel_len = copy_len; + } else { + fprintf(stderr, + "Unhandled clipboard selection 0x%lx\n", + xsre->selection); + return; + } + if (seltext) { + XChangeProperty(xsre->display, xsre->requestor, + xsre->property, xsre->target, + 8, PropModeReplace, + (uint8_t *)seltext, sel_len); + xev.property = xsre->property; + if (seltext != copy_buffer) + free(seltext); + } + } + + // all done, send a notification to the listener + if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev)) + fprintf(stderr, "Error sending SelectionNotify event\n"); } void cresize(int width, int height) { - int col, row; + int col, row; - if (width > 0) - win.w = width; - if (height > 0) - win.h = height; + if (width > 0) + win.w = width; + if (height > 0) + win.h = height; - col = (win.w - 2 * border_px) / win.cw; - row = (win.h - 2 * border_px) / win.ch; - col = MAX(1, col); - row = MAX(1, row); + col = (win.w - 2 * border_px) / win.cw; + row = (win.h - 2 * border_px) / win.ch; + col = MAX(1, col); + row = MAX(1, row); - screen_resize(col, row); - xresize(col, row); + screen_resize(col, row); + xresize(col, row); } void xresize(int col, int row) { - win.tw = col * win.cw; - win.th = row * win.ch; + win.tw = col * win.cw; + win.th = row * win.ch; - XFreePixmap(xw.dpy, xw.buf); - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, - DefaultDepth(xw.dpy, xw.scr)); - XftDrawChange(xw.draw, xw.buf); - xclear(0, 0, win.w, win.h); + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + DefaultDepth(xw.dpy, xw.scr)); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); - // resize to new width - xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); + // resize to new width + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); } int xloadcolor(int i, const char *name, Color *ncolor) { - if (!name) { - if (!(name = colors[i])) - return 0; - } + if (!name) { + if (!(name = colors[i])) + return 0; + } - return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); } void xloadcols(void) { - int i; - static int loaded; - - if (loaded) { - Color *cp; - for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) - XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); - } else { - i = 0; - while (colors[i++]) - ; - dc.collen = i; - dc.col = xmalloc(dc.collen * sizeof(Color)); - loaded = 1; - } - - for (i = 0; i < dc.collen; i++) { - if (!xloadcolor(i, NULL, &dc.col[i])) { - if (colors[i]) - die("could not allocate color '%s'\n", colors[i]); - } - } + int i; + static int loaded; + + if (loaded) { + Color *cp; + for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) + XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + } else { + i = 0; + while (colors[i++]) + ; + dc.collen = i; + dc.col = xmalloc(dc.collen * sizeof(Color)); + loaded = 1; + } + + for (i = 0; i < dc.collen; i++) { + if (!xloadcolor(i, NULL, &dc.col[i])) { + if (colors[i]) + die("could not allocate color '%s'\n", colors[i]); + } + } } int xsetcolorname(int x, const char *name) { - Color ncolor; + Color ncolor; - if (!BETWEEN(x, 0, dc.collen)) - return 1; + if (!BETWEEN(x, 0, dc.collen)) + return 1; - if (!xloadcolor(x, name, &ncolor)) - return 1; + if (!xloadcolor(x, name, &ncolor)) + return 1; - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; + XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); + dc.col[x] = ncolor; - return 0; + return 0; } @@ -622,754 +622,754 @@ xsetcolorname(int x, const char *name) void xclear(int x1, int y1, int x2, int y2) { - XftDrawRect(xw.draw, &dc.col[default_attributes.bg], - x1, y1, x2-x1, y2-y1); + XftDrawRect(xw.draw, &dc.col[default_attributes.bg], + x1, y1, x2-x1, y2-y1); } void xhints(void) { - XClassHint class = {"se", "se"}; - XWMHints wm = {.flags = InputHint, .input = 1}; - XSizeHints *sizeh; - - sizeh = XAllocSizeHints(); - - sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; - sizeh->height = win.h; - sizeh->width = win.w; - sizeh->height_inc = win.ch; - sizeh->width_inc = win.cw; - sizeh->base_height = 2 * border_px; - sizeh->base_width = 2 * border_px; - sizeh->min_height = win.ch + 2 * border_px; - sizeh->min_width = win.cw + 2 * border_px; - if (xw.isfixed) { - sizeh->flags |= PMaxSize; - sizeh->min_width = sizeh->max_width = win.w; - sizeh->min_height = sizeh->max_height = win.h; - } - if (xw.gm & (XValue|YValue)) { - sizeh->flags |= USPosition | PWinGravity; - sizeh->x = xw.l; - sizeh->y = xw.t; - sizeh->win_gravity = xgeommasktogravity(xw.gm); - } - - XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, - &class); - XFree(sizeh); + XClassHint class = {"se", "se"}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + + sizeh = XAllocSizeHints(); + + sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; + sizeh->height = win.h; + sizeh->width = win.w; + sizeh->height_inc = win.ch; + sizeh->width_inc = win.cw; + sizeh->base_height = 2 * border_px; + sizeh->base_width = 2 * border_px; + sizeh->min_height = win.ch + 2 * border_px; + sizeh->min_width = win.cw + 2 * border_px; + if (xw.isfixed) { + sizeh->flags |= PMaxSize; + sizeh->min_width = sizeh->max_width = win.w; + sizeh->min_height = sizeh->max_height = win.h; + } + if (xw.gm & (XValue|YValue)) { + sizeh->flags |= USPosition | PWinGravity; + sizeh->x = xw.l; + sizeh->y = xw.t; + sizeh->win_gravity = xgeommasktogravity(xw.gm); + } + + XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, + &class); + XFree(sizeh); } int xgeommasktogravity(int mask) { - switch (mask & (XNegative|YNegative)) { - case 0: - return NorthWestGravity; - case XNegative: - return NorthEastGravity; - case YNegative: - return SouthWestGravity; - } - - return SouthEastGravity; + switch (mask & (XNegative|YNegative)) { + case 0: + return NorthWestGravity; + case XNegative: + return NorthEastGravity; + case YNegative: + return SouthWestGravity; + } + + return SouthEastGravity; } int xloadfont(Font *f, FcPattern *pattern) { - FcPattern *configured; - FcPattern *match; - FcResult result; - XGlyphInfo extents; - int wantattr, haveattr; - - /* - * Manually configure instead of calling XftMatchFont - * so that we can use the configured pattern for - * "missing struct glyph" lookups. - */ - configured = FcPatternDuplicate(pattern); - if (!configured) - return 1; - - FcConfigSubstitute(NULL, configured, FcMatchPattern); - XftDefaultSubstitute(xw.dpy, xw.scr, configured); - - match = FcFontMatch(NULL, configured, &result); - if (!match) { - FcPatternDestroy(configured); - return 1; - } - - if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { - FcPatternDestroy(configured); - FcPatternDestroy(match); - return 1; - } - - if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == - XftResultMatch)) { - /* - * Check if xft was unable to find a font with the appropriate - * slant but gave us one anyway. Try to mitigate. - */ - if ((XftPatternGetInteger(f->match->pattern, "slant", 0, - &haveattr) != XftResultMatch) || haveattr < wantattr) { - f->badslant = 1; - fputs("font slant does not match\n", stderr); - } - } - - if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == - XftResultMatch)) { - if ((XftPatternGetInteger(f->match->pattern, "weight", 0, - &haveattr) != XftResultMatch) || haveattr != wantattr) { - f->badweight = 1; - fputs("font weight does not match\n", stderr); - } - } - - // Printable characters in ASCII, used to estimate the advance width of single wide characters. - const char ascii_printable[] = - " !\"#$%&'()*+,-./0123456789:;<=>?" - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" - "`abcdefghijklmnopqrstuvwxyz{|}~"; - - XftTextExtentsUtf8(xw.dpy, f->match, - (const FcChar8 *) ascii_printable, - strlen(ascii_printable), &extents); - - f->set = NULL; - f->pattern = configured; - - f->ascent = f->match->ascent; - f->descent = f->match->descent; - f->lbearing = 0; - f->rbearing = f->match->max_advance_width; - - f->height = f->ascent + f->descent; - f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); - - return 0; + FcPattern *configured; + FcPattern *match; + FcResult result; + XGlyphInfo extents; + int wantattr, haveattr; + + /* + * Manually configure instead of calling XftMatchFont + * so that we can use the configured pattern for + * "missing struct glyph" lookups. + */ + configured = FcPatternDuplicate(pattern); + if (!configured) + return 1; + + FcConfigSubstitute(NULL, configured, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, configured); + + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } + + if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(configured); + FcPatternDestroy(match); + return 1; + } + + if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == + XftResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((XftPatternGetInteger(f->match->pattern, "slant", 0, + &haveattr) != XftResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("font slant does not match\n", stderr); + } + } + + if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == + XftResultMatch)) { + if ((XftPatternGetInteger(f->match->pattern, "weight", 0, + &haveattr) != XftResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("font weight does not match\n", stderr); + } + } + + // Printable characters in ASCII, used to estimate the advance width of single wide characters. + const char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; + + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) ascii_printable, + strlen(ascii_printable), &extents); + + f->set = NULL; + f->pattern = configured; + + f->ascent = f->match->ascent; + f->descent = f->match->descent; + f->lbearing = 0; + f->rbearing = f->match->max_advance_width; + + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + + return 0; } void xloadfonts(const char *fontstr, double fontsize) { - FcPattern *pattern; - double fontval; - - if (fontstr[0] == '-') - pattern = XftXlfdParse(fontstr, False, False); - else - pattern = FcNameParse((const FcChar8 *)fontstr); - - if (!pattern) - die("can't open font %s\n", fontstr); - - if (fontsize > 1) { - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternDel(pattern, FC_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); - usedfontsize = fontsize; - } else { - if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == - FcResultMatch) { - usedfontsize = fontval; - } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == - FcResultMatch) { - usedfontsize = -1; - } else { - /* - * Default font size is 12, if none given. This is to - * have a known usedfontsize value. - */ - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); - usedfontsize = 12; - } - defaultfontsize = usedfontsize; - } - - if (xloadfont(&dc.font, pattern)) - die("can't open font %s\n", fontstr); - - if (usedfontsize < 0) { - FcPatternGetDouble(dc.font.match->pattern, - FC_PIXEL_SIZE, 0, &fontval); - usedfontsize = fontval; - if (fontsize == 0) - defaultfontsize = fontval; - } - - /* Setting character width and height. */ - win.cw = ceilf(dc.font.width * cw_scale); - win.ch = ceilf(dc.font.height * ch_scale); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (xloadfont(&dc.ifont, pattern)) - die("can't open font %s\n", fontstr); - - FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - if (xloadfont(&dc.ibfont, pattern)) - die("can't open font %s\n", fontstr); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); - if (xloadfont(&dc.bfont, pattern)) - die("can't open font %s\n", fontstr); - - FcPatternDestroy(pattern); + FcPattern *pattern; + double fontval; + + if (fontstr[0] == '-') + pattern = XftXlfdParse(fontstr, False, False); + else + pattern = FcNameParse((const FcChar8 *)fontstr); + + if (!pattern) + die("can't open font %s\n", fontstr); + + if (fontsize > 1) { + FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); + usedfontsize = fontsize; + } else { + if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = fontval; + } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = -1; + } else { + /* + * Default font size is 12, if none given. This is to + * have a known usedfontsize value. + */ + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); + usedfontsize = 12; + } + defaultfontsize = usedfontsize; + } + + if (xloadfont(&dc.font, pattern)) + die("can't open font %s\n", fontstr); + + if (usedfontsize < 0) { + FcPatternGetDouble(dc.font.match->pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + if (fontsize == 0) + defaultfontsize = fontval; + } + + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cw_scale); + win.ch = ceilf(dc.font.height * ch_scale); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadfont(&dc.ifont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadfont(&dc.ibfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDestroy(pattern); } int ximopen(Display *dpy) { - XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; - XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; - - xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); - if (xw.ime.xim == NULL) - return 0; - - if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) - fprintf(stderr, "XSetIMValues: " - "Could not set XNDestroyCallback.\n"); - - xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, - NULL); - - if (xw.ime.xic == NULL) { - xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, xw.win, - XNDestroyCallback, &icdestroy, - NULL); - } - if (xw.ime.xic == NULL) - fprintf(stderr, "XCreateIC: Could not create input context.\n"); - - return 1; + XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; + XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; + + xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); + if (xw.ime.xim == NULL) + return 0; + + if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) + fprintf(stderr, "XSetIMValues: " + "Could not set XNDestroyCallback.\n"); + + xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, + NULL); + + if (xw.ime.xic == NULL) { + xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, + XNDestroyCallback, &icdestroy, + NULL); + } + if (xw.ime.xic == NULL) + fprintf(stderr, "XCreateIC: Could not create input context.\n"); + + return 1; } void ximinstantiate(Display *dpy, XPointer client, XPointer call) { - if (ximopen(dpy)) - XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); + if (ximopen(dpy)) + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); } void ximdestroy(XIM xim, XPointer client, XPointer call) { - xw.ime.xim = NULL; - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); - XFree(xw.ime.spotlist); + xw.ime.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + XFree(xw.ime.spotlist); } int xicdestroy(XIC xim, XPointer client, XPointer call) { - xw.ime.xic = NULL; - return 1; + xw.ime.xic = NULL; + return 1; } void xinit(int cols, int rows) { - XGCValues gcvalues; - Cursor cursor; - Window parent; - pid_t thispid = getpid(); - XColor xmousefg, xmousebg; - - if (!(xw.dpy = XOpenDisplay(NULL))) - die("can't open display\n"); - xw.scr = XDefaultScreen(xw.dpy); - xw.vis = XDefaultVisual(xw.dpy, xw.scr); - - /* font */ - if (!FcInit()) - die("could not init fontconfig.\n"); - - xloadfonts(fontconfig, 0); - - /* colors */ - xw.cmap = XDefaultColormap(xw.dpy, xw.scr); - xloadcols(); - - /* adjust fixed window geometry */ - win.w = 2 * border_px + cols * win.cw; - win.h = 2 * border_px + rows * win.ch; - if (xw.gm & XNegative) - xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; - if (xw.gm & YNegative) - xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; - - /* Events */ - xw.attrs.background_pixel = dc.col[default_attributes.bg].pixel; - xw.attrs.border_pixel = dc.col[default_attributes.bg].pixel; - xw.attrs.bit_gravity = NorthWestGravity; - xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask - | ExposureMask | VisibilityChangeMask | StructureNotifyMask - | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; - xw.attrs.colormap = xw.cmap; - - parent = XRootWindow(xw.dpy, xw.scr); - xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, - win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, - xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity - | CWEventMask | CWColormap, &xw.attrs); - - memset(&gcvalues, 0, sizeof(gcvalues)); - gcvalues.graphics_exposures = False; - dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, - &gcvalues); - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, - DefaultDepth(xw.dpy, xw.scr)); - XSetForeground(xw.dpy, dc.gc, dc.col[default_attributes.bg].pixel); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); - - /* font spec buffer */ - xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); - - /* Xft rendering context */ - xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); - - /* input methods */ - if (!ximopen(xw.dpy)) { - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); - } - - /* white cursor, black outline */ - cursor = XCreateFontCursor(xw.dpy, XC_xterm); - XDefineCursor(xw.dpy, xw.win, cursor); - - if (XParseColor(xw.dpy, xw.cmap, colors[cursor_fg], &xmousefg) == 0) { - xmousefg.red = 0xffff; - xmousefg.green = 0xffff; - xmousefg.blue = 0xffff; - } - - if (XParseColor(xw.dpy, xw.cmap, colors[cursor_bg], &xmousebg) == 0) { - xmousebg.red = 0x0000; - xmousebg.green = 0x0000; - xmousebg.blue = 0x0000; - } - - XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); - - xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); - xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); - xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); - xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False); - XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); - - xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); - XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, - PropModeReplace, (uint8_t *)&thispid, 1); - - win.mode = MODE_NUMLOCK; - xsettitle(NULL); - xhints(); - XMapWindow(xw.dpy, xw.win); - XSync(xw.dpy, False); - - xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); - if (xtarget == None) - xtarget = XA_STRING; + XGCValues gcvalues; + Cursor cursor; + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); + + /* font */ + if (!FcInit()) + die("could not init fontconfig.\n"); + + xloadfonts(fontconfig, 0); + + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); + + /* adjust fixed window geometry */ + win.w = 2 * border_px + cols * win.cw; + win.h = 2 * border_px + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) + xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; + + /* Events */ + xw.attrs.background_pixel = dc.col[default_attributes.bg].pixel; + xw.attrs.border_pixel = dc.col[default_attributes.bg].pixel; + xw.attrs.bit_gravity = NorthWestGravity; + xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask + | ExposureMask | VisibilityChangeMask | StructureNotifyMask + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + xw.attrs.colormap = xw.cmap; + + parent = XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, + win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + DefaultDepth(xw.dpy, xw.scr)); + XSetForeground(xw.dpy, dc.gc, dc.col[default_attributes.bg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + + /* input methods */ + if (!ximopen(xw.dpy)) { + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + } + + /* white cursor, black outline */ + cursor = XCreateFontCursor(xw.dpy, XC_xterm); + XDefineCursor(xw.dpy, xw.win, cursor); + + if (XParseColor(xw.dpy, xw.cmap, colors[cursor_fg], &xmousefg) == 0) { + xmousefg.red = 0xffff; + xmousefg.green = 0xffff; + xmousefg.blue = 0xffff; + } + + if (XParseColor(xw.dpy, xw.cmap, colors[cursor_bg], &xmousebg) == 0) { + xmousebg.red = 0x0000; + xmousebg.green = 0x0000; + xmousebg.blue = 0x0000; + } + + XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); + xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False); + XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uint8_t *)&thispid, 1); + + win.mode = MODE_NUMLOCK; + xsettitle(NULL); + xhints(); + XMapWindow(xw.dpy, xw.win); + XSync(xw.dpy, False); + + xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + if (xtarget == None) + xtarget = XA_STRING; } int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const struct glyph *glyphs, int len, int x, int y) { - float winx = border_px + x * win.cw, winy = border_px + y * win.ch, xp, yp; - unsigned short mode, prevmode = USHRT_MAX; - Font *font = &dc.font; - int frcflags = FRC_NORMAL; - float runewidth = win.cw; - rune_t rune; - FT_UInt glyphidx; - FcResult fcres; - FcPattern *fcpattern, *fontpattern; - FcFontSet *fcsets[] = { NULL }; - FcCharSet *fccharset; - int i, f, numspecs = 0; - - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current struct glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; - - /* Skip dummy wide-character spacing. */ - if (mode & ATTR_WDUMMY) - continue; - - /* Determine font for struct glyph if different from previous struct glyph. */ - if (prevmode != mode) { - prevmode = mode; - font = &dc.font; - frcflags = FRC_NORMAL; - runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); - if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { - font = &dc.ibfont; - frcflags = FRC_ITALICBOLD; - } else if (mode & ATTR_ITALIC) { - font = &dc.ifont; - frcflags = FRC_ITALIC; - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; - } - yp = winy + font->ascent; - } - - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { - specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; - numspecs++; - continue; - } - - /* Fallback on font cache, search the font cache for match. */ - for (f = 0; f < frclen; f++) { - glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); - /* Everything correct. */ - if (glyphidx && frc[f].flags == frcflags) - break; - /* We got a default font for a not found struct glyph. */ - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; - } - } - - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; - - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the - * font for one single character. - * - * Xft and fontconfig are design failures. - */ - fcpattern = FcPatternDuplicate(font->pattern); - fccharset = FcCharSetCreate(); - - FcCharSetAddChar(fccharset, rune); - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); - - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); - - fontpattern = FcFontSetMatch(0, fcsets, 1, - fcpattern, &fcres); - - /* Allocate memory for the new cache entry. */ - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); - } - - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) - die("XftFontOpenPattern failed seeking fallback font: %s\n", - strerror(errno)); - frc[frclen].flags = frcflags; - frc[frclen].unicodep = rune; - - glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); - - f = frclen; - frclen++; - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); - } - - specs[numspecs].font = frc[f].font; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; - numspecs++; - } - - return numspecs; + float winx = border_px + x * win.cw, winy = border_px + y * win.ch, xp, yp; + unsigned short mode, prevmode = USHRT_MAX; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; + float runewidth = win.cw; + rune_t rune; + FT_UInt glyphidx; + FcResult fcres; + FcPattern *fcpattern, *fontpattern; + FcFontSet *fcsets[] = { NULL }; + FcCharSet *fccharset; + int i, f, numspecs = 0; + + for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + /* Fetch rune and mode for current struct glyph. */ + rune = glyphs[i].u; + mode = glyphs[i].mode; + + /* Skip dummy wide-character spacing. */ + if (mode & ATTR_WDUMMY) + continue; + + /* Determine font for struct glyph if different from previous struct glyph. */ + if (prevmode != mode) { + prevmode = mode; + font = &dc.font; + frcflags = FRC_NORMAL; + runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (mode & ATTR_ITALIC) { + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (mode & ATTR_BOLD) { + font = &dc.bfont; + frcflags = FRC_BOLD; + } + yp = winy + font->ascent; + } + + /* Lookup character index with default font. */ + glyphidx = XftCharIndex(xw.dpy, font->match, rune); + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + continue; + } + + /* Fallback on font cache, search the font cache for match. */ + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ + if (glyphidx && frc[f].flags == frcflags) + break; + /* We got a default font for a not found struct glyph. */ + if (!glyphidx && frc[f].flags == frcflags + && frc[f].unicodep == rune) { + break; + } + } + + /* Nothing was found. Use fontconfig to find matching font. */ + if (f >= frclen) { + if (!font->set) + font->set = FcFontSort(0, font->pattern, + 1, 0, &fcres); + fcsets[0] = font->set; + + /* + * Nothing was found in the cache. Now use + * some dozen of Fontconfig calls to get the + * font for one single character. + * + * Xft and fontconfig are design failures. + */ + fcpattern = FcPatternDuplicate(font->pattern); + fccharset = FcCharSetCreate(); + + FcCharSetAddChar(fccharset, rune); + FcPatternAddCharSet(fcpattern, FC_CHARSET, + fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); + + FcConfigSubstitute(0, fcpattern, + FcMatchPattern); + FcDefaultSubstitute(fcpattern); + + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); + + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } + + frc[frclen].font = XftFontOpenPattern(xw.dpy, + fontpattern); + if (!frc[frclen].font) + die("XftFontOpenPattern failed seeking fallback font: %s\n", + strerror(errno)); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = rune; + + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + + f = frclen; + frclen++; + + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } + + specs[numspecs].font = frc[f].font; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + } + + return numspecs; } void xdrawglyphfontspecs(const XftGlyphFontSpec *specs, struct glyph base, int len, int x, int y) { - int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); - int winx = border_px + x * win.cw, winy = border_px + y * win.ch, - width = charlen * win.cw; - Color *fg, *bg, *temp, revfg, truefg, truebg; - XRenderColor colfg, colbg; - XRectangle r; - - /* Fallback on color display for attributes not supported by the font */ - if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { - if (dc.ibfont.badslant || dc.ibfont.badweight) - base.fg = default_attributes.fg; - } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || - (base.mode & ATTR_BOLD && dc.bfont.badweight)) { - base.fg = default_attributes.fg; - } - - if (IS_TRUECOL(base.fg)) { - colfg.alpha = 0xffff; - colfg.red = TRUERED(base.fg); - colfg.green = TRUEGREEN(base.fg); - colfg.blue = TRUEBLUE(base.fg); - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); - fg = &truefg; - } else { - fg = &dc.col[base.fg]; - } - - if (IS_TRUECOL(base.bg)) { - colbg.alpha = 0xffff; - colbg.green = TRUEGREEN(base.bg); - colbg.red = TRUERED(base.bg); - colbg.blue = TRUEBLUE(base.bg); - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); - bg = &truebg; - } else { - bg = &dc.col[base.bg]; - } - - /* Change basic system colors [0-7] to bright system colors [8-15] */ - if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) - fg = &dc.col[base.fg + 8]; - - if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { - colfg.red = fg->color.red / 2; - colfg.green = fg->color.green / 2; - colfg.blue = fg->color.blue / 2; - colfg.alpha = fg->color.alpha; - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); - fg = &revfg; - } - - if (base.mode & ATTR_REVERSE) { - temp = fg; - fg = bg; - bg = temp; - } - - if (base.mode & ATTR_INVISIBLE) - fg = bg; - - /* Intelligent cleaning up of the borders. */ - if (x == 0) { - xclear(0, (y == 0)? 0 : winy, border_px, - winy + win.ch + - ((winy + win.ch >= border_px + win.th)? win.h : 0)); - } - if (winx + width >= border_px + win.tw) { - xclear(winx + width, (y == 0)? 0 : winy, win.w, - ((winy + win.ch >= border_px + win.th)? win.h : (winy + win.ch))); - } - if (y == 0) - xclear(winx, 0, winx + width, border_px); - if (winy + win.ch >= border_px + win.th) - xclear(winx, winy + win.ch, winx + width, win.h); - - /* Clean up the region we want to draw to. */ - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); - - /* Set the clip region because Xft is sometimes dirty. */ - r.x = 0; - r.y = 0; - r.height = win.ch; - r.width = width; - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); - - /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); - - /* Render underline and strikethrough. */ - if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, - width, 1); - } - - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, - width, 1); - } - - /* Reset clip to none. */ - XftDrawSetClip(xw.draw, 0); + int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); + int winx = border_px + x * win.cw, winy = border_px + y * win.ch, + width = charlen * win.cw; + Color *fg, *bg, *temp, revfg, truefg, truebg; + XRenderColor colfg, colbg; + XRectangle r; + + /* Fallback on color display for attributes not supported by the font */ + if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { + if (dc.ibfont.badslant || dc.ibfont.badweight) + base.fg = default_attributes.fg; + } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || + (base.mode & ATTR_BOLD && dc.bfont.badweight)) { + base.fg = default_attributes.fg; + } + + if (IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; + colfg.red = TRUERED(base.fg); + colfg.green = TRUEGREEN(base.fg); + colfg.blue = TRUEBLUE(base.fg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); + fg = &truefg; + } else { + fg = &dc.col[base.fg]; + } + + if (IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; + colbg.green = TRUEGREEN(base.bg); + colbg.red = TRUERED(base.bg); + colbg.blue = TRUEBLUE(base.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); + bg = &truebg; + } else { + bg = &dc.col[base.bg]; + } + + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) + fg = &dc.col[base.fg + 8]; + + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { + colfg.red = fg->color.red / 2; + colfg.green = fg->color.green / 2; + colfg.blue = fg->color.blue / 2; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); + fg = &revfg; + } + + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } + + if (base.mode & ATTR_INVISIBLE) + fg = bg; + + /* Intelligent cleaning up of the borders. */ + if (x == 0) { + xclear(0, (y == 0)? 0 : winy, border_px, + winy + win.ch + + ((winy + win.ch >= border_px + win.th)? win.h : 0)); + } + if (winx + width >= border_px + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((winy + win.ch >= border_px + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) + xclear(winx, 0, winx + width, border_px); + if (winy + win.ch >= border_px + win.th) + xclear(winx, winy + win.ch, winx + width, win.h); + + /* Clean up the region we want to draw to. */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); + + /* Set the clip region because Xft is sometimes dirty. */ + r.x = 0; + r.y = 0; + r.height = win.ch; + r.width = width; + XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); + + /* Render the glyphs. */ + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + width, 1); + } + + /* Reset clip to none. */ + XftDrawSetClip(xw.draw, 0); } void xdrawglyph(struct glyph g, int x, int y) { - int numspecs; - XftGlyphFontSpec spec; + int numspecs; + XftGlyphFontSpec spec; - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y); } void xdrawcursor(int cx, int cy, int focused) { - LIMIT(cx, 0, screen.col-1); - LIMIT(cy, 0, screen.row-1); - struct glyph g = screen.lines[cy][cx]; - if (IS_SET(MODE_HIDE)) return; - - g.mode &= ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; - g.fg = cursor_bg; - g.bg = cursor_fg; - Color drawcol = dc.col[g.bg]; - - /* draw the new one */ - if (IS_SET(MODE_FOCUSED) && !(get_fb(focused_window)->mode & FB_SELECTION_ON) && focused) { - switch (cursor_shape) { - case 0: // Blinking Block - case 1: // Blinking Block (Default) - case 2: // Steady Block - xdrawglyph(g, cx, cy); - break; - case 3: // Blinking Underline - case 4: // Steady Underline - XftDrawRect(xw.draw, &drawcol, - border_px + cx * win.cw, - border_px + (cy + 1) * win.ch - \ - cursor_thickness, - win.cw, cursor_thickness); - break; - case 5: // Blinking bar - case 6: // Steady bar - XftDrawRect(xw.draw, &drawcol, - border_px + cx * win.cw, - border_px + cy * win.ch, - cursor_thickness, win.ch); - break; - } - } else { - XftDrawRect(xw.draw, &drawcol, - border_px + cx * win.cw, - border_px + cy * win.ch, - win.cw - 1, 1); - XftDrawRect(xw.draw, &drawcol, - border_px + cx * win.cw, - border_px + cy * win.ch, - 1, win.ch - 1); - XftDrawRect(xw.draw, &drawcol, - border_px + (cx + 1) * win.cw - 1, - border_px + cy * win.ch, - 1, win.ch - 1); - XftDrawRect(xw.draw, &drawcol, - border_px + cx * win.cw, - border_px + (cy + 1) * win.ch - 1, - win.cw, 1); - } + LIMIT(cx, 0, screen.col-1); + LIMIT(cy, 0, screen.row-1); + struct glyph g = screen.lines[cy][cx]; + if (IS_SET(MODE_HIDE)) return; + + g.mode &= ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; + g.fg = cursor_bg; + g.bg = cursor_fg; + Color drawcol = dc.col[g.bg]; + + /* draw the new one */ + if (IS_SET(MODE_FOCUSED) && !(get_fb(focused_window)->mode & FB_SELECTION_ON) && focused) { + switch (cursor_shape) { + case 0: // Blinking Block + case 1: // Blinking Block (Default) + case 2: // Steady Block + xdrawglyph(g, cx, cy); + break; + case 3: // Blinking Underline + case 4: // Steady Underline + XftDrawRect(xw.draw, &drawcol, + border_px + cx * win.cw, + border_px + (cy + 1) * win.ch - \ + cursor_thickness, + win.cw, cursor_thickness); + break; + case 5: // Blinking bar + case 6: // Steady bar + XftDrawRect(xw.draw, &drawcol, + border_px + cx * win.cw, + border_px + cy * win.ch, + cursor_thickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, + border_px + cx * win.cw, + border_px + cy * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, + border_px + cx * win.cw, + border_px + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + border_px + (cx + 1) * win.cw - 1, + border_px + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + border_px + cx * win.cw, + border_px + (cy + 1) * win.ch - 1, + win.cw, 1); + } } void xseticontitle(char *p) { - XTextProperty prop; - DEFAULT(p, "se"); - - if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop) != Success) - return; - XSetWMIconName(xw.dpy, xw.win, &prop); - XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); - XFree(prop.value); + XTextProperty prop; + DEFAULT(p, "se"); + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; + XSetWMIconName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); + XFree(prop.value); } void xsettitle(char *p) { - XTextProperty prop; - DEFAULT(p, "se"); - - if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop) != Success) - return; - XSetWMName(xw.dpy, xw.win, &prop); - XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); - XFree(prop.value); + XTextProperty prop; + DEFAULT(p, "se"); + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; + XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); + XFree(prop.value); } void xdrawline(int x1, int y1, int x2) { - LIMIT(y1, 0, screen.row); - LIMIT(x2, 0, screen.col); - LIMIT(x1, 0, x2); - struct glyph* line = screen.lines[y1]; - int i, x, ox, numspecs; - struct glyph base, new; - XftGlyphFontSpec *specs = xw.specbuf; - - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { - new = line[x]; - if (new.mode & ATTR_WDUMMY) - continue; - if (i > 0 && ATTRCMP(base, new)) { - xdrawglyphfontspecs(specs, base, i, ox, y1); - specs += i; - numspecs -= i; - i = 0; - } - if (i == 0) { - ox = x; - base = new; - } - i++; - } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y1); + LIMIT(y1, 0, screen.row); + LIMIT(x2, 0, screen.col); + LIMIT(x1, 0, x2); + struct glyph* line = screen.lines[y1]; + int i, x, ox, numspecs; + struct glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + + numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { + new = line[x]; + if (new.mode & ATTR_WDUMMY) + continue; + if (i > 0 && ATTRCMP(base, new)) { + xdrawglyphfontspecs(specs, base, i, ox, y1); + specs += i; + numspecs -= i; + i = 0; + } + if (i == 0) { + ox = x; + base = new; + } + i++; + } + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1); } void xsetenv(void) { - char buf[sizeof(long) * 8 + 1]; - snprintf(buf, sizeof(buf), "%lu", xw.win); - setenv("WINDOWID", buf, 1); + char buf[sizeof(long) * 8 + 1]; + snprintf(buf, sizeof(buf), "%lu", xw.win); + setenv("WINDOWID", buf, 1); } int xstartdraw(void) {return IS_SET(MODE_VISIBLE);} void xfinishdraw(void) { - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0); - XSetForeground(xw.dpy, dc.gc, dc.col[default_attributes.bg].pixel); + XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, dc.col[default_attributes.bg].pixel); } void expose(XEvent *ev) {} // do nothing void visibility(XEvent *ev) { - XVisibilityEvent *e = &ev->xvisibility; - MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); + XVisibilityEvent *e = &ev->xvisibility; + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); } void unmap(XEvent *ev) {win.mode &= ~MODE_VISIBLE;} @@ -1377,333 +1377,333 @@ void unmap(XEvent *ev) {win.mode &= ~MODE_VISIBLE;} void xsetpointermotion(int set) { - MODBIT(xw.attrs.event_mask, set, PointerMotionMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); } void xseturgency(int add) { - XWMHints *h = XGetWMHints(xw.dpy, xw.win); - MODBIT(h->flags, add, XUrgencyHint); - XSetWMHints(xw.dpy, xw.win, h); - XFree(h); + XWMHints *h = XGetWMHints(xw.dpy, xw.win); + MODBIT(h->flags, add, XUrgencyHint); + XSetWMHints(xw.dpy, xw.win, h); + XFree(h); } void xunloadfonts(void) { - /* Free the loaded fonts in the font cache. */ - while (frclen > 0) - XftFontClose(xw.dpy, frc[--frclen].font); - - xunloadfont(&dc.font); - xunloadfont(&dc.bfont); - xunloadfont(&dc.ifont); - xunloadfont(&dc.ibfont); + /* Free the loaded fonts in the font cache. */ + while (frclen > 0) + XftFontClose(xw.dpy, frc[--frclen].font); + + xunloadfont(&dc.font); + xunloadfont(&dc.bfont); + xunloadfont(&dc.ifont); + xunloadfont(&dc.ibfont); } void xunloadfont(Font *f) { - soft_assert(f, return;); - soft_assert(f->match, return;); - soft_assert(f->pattern, return;); - XftFontClose(xw.dpy, f->match); - FcPatternDestroy(f->pattern); - if (f->set) - FcFontSetDestroy(f->set); + soft_assert(f, return;); + soft_assert(f->match, return;); + soft_assert(f->pattern, return;); + XftFontClose(xw.dpy, f->match); + FcPatternDestroy(f->pattern); + if (f->set) + FcFontSetDestroy(f->set); } void focus(XEvent *ev) { - XFocusChangeEvent *e = &ev->xfocus; - - if (e->mode == NotifyGrab) - return; - - if (ev->type == FocusIn) { - if (xw.ime.xic) - XSetICFocus(xw.ime.xic); - win.mode |= MODE_FOCUSED; - xseturgency(0); - } else { - if (xw.ime.xic) - XUnsetICFocus(xw.ime.xic); - win.mode &= ~MODE_FOCUSED; - } + XFocusChangeEvent *e = &ev->xfocus; + + if (e->mode == NotifyGrab) + return; + + if (ev->type == FocusIn) { + if (xw.ime.xic) + XSetICFocus(xw.ime.xic); + win.mode |= MODE_FOCUSED; + xseturgency(0); + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + } } int match(unsigned int mask, unsigned int state) { - const unsigned int ignoremod = Mod2Mask|XK_SWITCH_MOD; - return mask == XK_ANY_MOD || mask == (state & ~ignoremod); + const unsigned int ignoremod = Mod2Mask|XK_SWITCH_MOD; + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); } static void search_term_string_insert(const char* buf, int buflen) { - static int first = 0; - - struct file_buffer* fb = get_fb(focused_window); - if (!buf) { - first = 1; - return; - } - if (first) { - *fb->search_term = 0; - first = 0; - } - if (buf[0] >= 32 || buflen > 1) { - int len = strlen(fb->search_term); - if (len + buflen + 1 > SEARCH_TERM_MAX_LEN) - return; - memcpy(fb->search_term + len, buf, buflen); - fb->search_term[len + buflen] = 0; - if (fb->mode & FB_SEARCH_BLOCKING_BACKWARDS) - focused_window->cursor_offset = fb_seek_string_backwards(fb, focused_window->cursor_offset, fb->search_term); - else - focused_window->cursor_offset = fb_seek_string(fb, focused_window->cursor_offset, fb->search_term); - writef_to_status_bar("search: %s", fb->search_term); - } + static int first = 0; + + struct file_buffer* fb = get_fb(focused_window); + if (!buf) { + first = 1; + return; + } + if (first) { + *fb->search_term = 0; + first = 0; + } + if (buf[0] >= 32 || buflen > 1) { + int len = strlen(fb->search_term); + if (len + buflen + 1 > SEARCH_TERM_MAX_LEN) + return; + memcpy(fb->search_term + len, buf, buflen); + fb->search_term[len + buflen] = 0; + if (fb->mode & FB_SEARCH_BLOCKING_BACKWARDS) + focused_window->cursor_offset = fb_seek_string_backwards(fb, focused_window->cursor_offset, fb->search_term); + else + focused_window->cursor_offset = fb_seek_string(fb, focused_window->cursor_offset, fb->search_term); + writef_to_status_bar("search: %s", fb->search_term); + } } static int search_term_actions(KeySym keysym, int modkey) { - static int first = 0; - struct file_buffer* fb = get_fb(focused_window); - if (keysym == XK_Return || keysym == XK_Escape) { - int count = fb_count_string_instances(fb, fb->search_term, 0, NULL); - if (!count) { - fb->mode &= ~FB_SEARCH_BLOCKING_MASK; - writef_to_status_bar("no resulrs for \"%s\"", fb->search_term); - } else { - fb->mode &= ~FB_SEARCH_BLOCKING; - fb->mode &= ~FB_SEARCH_BLOCKING_BACKWARDS; - fb->mode |= FB_SEARCH_BLOCKING_IDLE; - - writef_to_status_bar("%d results for \"%s\"", count, fb->search_term); - if (fb->mode & FB_SEARCH_BLOCKING_BACKWARDS) - focused_window->cursor_offset = fb_seek_string_backwards(fb, focused_window->cursor_offset, fb->search_term); - else - focused_window->cursor_offset = fb_seek_string(fb, focused_window->cursor_offset, fb->search_term); - } - first = 1; - search_term_string_insert(NULL, 0); - return 1; - } - if (keysym == XK_BackSpace) { - if (first) { - first = 0; - *fb->search_term = 0; - } else { - utf8_remove_string_end(fb->search_term); - focused_window->cursor_offset = wb_seek_string_wrap(focused_window, focused_window->cursor_offset, fb->search_term); - } - writef_to_status_bar("search: %s", fb->search_term); - return 1; - } - first = 0; - return 0; + static int first = 0; + struct file_buffer* fb = get_fb(focused_window); + if (keysym == XK_Return || keysym == XK_Escape) { + int count = fb_count_string_instances(fb, fb->search_term, 0, NULL); + if (!count) { + fb->mode &= ~FB_SEARCH_BLOCKING_MASK; + writef_to_status_bar("no resulrs for \"%s\"", fb->search_term); + } else { + fb->mode &= ~FB_SEARCH_BLOCKING; + fb->mode &= ~FB_SEARCH_BLOCKING_BACKWARDS; + fb->mode |= FB_SEARCH_BLOCKING_IDLE; + + writef_to_status_bar("%d results for \"%s\"", count, fb->search_term); + if (fb->mode & FB_SEARCH_BLOCKING_BACKWARDS) + focused_window->cursor_offset = fb_seek_string_backwards(fb, focused_window->cursor_offset, fb->search_term); + else + focused_window->cursor_offset = fb_seek_string(fb, focused_window->cursor_offset, fb->search_term); + } + first = 1; + search_term_string_insert(NULL, 0); + return 1; + } + if (keysym == XK_BackSpace) { + if (first) { + first = 0; + *fb->search_term = 0; + } else { + utf8_remove_string_end(fb->search_term); + focused_window->cursor_offset = wb_seek_string_wrap(focused_window, focused_window->cursor_offset, fb->search_term); + } + writef_to_status_bar("search: %s", fb->search_term); + return 1; + } + first = 0; + return 0; } void kpress(XEvent *ev) { - XKeyEvent *e = &ev->xkey; - KeySym ksym; - char buf[64]; - int len; - rune_t c; - Status status; - - if (IS_SET(MODE_KBDLOCK)) - return; - - if (xw.ime.xic) - len = XmbLookupString(xw.ime.xic, e, buf, sizeof(buf), &ksym, &status); - else - len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); - if (len == 1 && e->state & Mod1Mask) { - if (*buf < 0177) { - c = *buf | 0x80; - len = utf8_encode(c, buf); - } - } - - const struct file_buffer* fb = get_fb(focused_window); - // keysym callback - if (fb->mode & FB_SEARCH_BLOCKING) { - if (search_term_actions(ksym, e->state)) - return; - } - if (fb->mode & FB_SEARCH_BLOCKING) { - search_term_string_insert(buf, len); - return; - } - - if (focused_window->mode != WB_NORMAL) { - int override = 0; - call_extension(wn_custom_window_keypress_override, &override, focused_node, ksym, e->state, buf, len); - if (override) - return; - - int wn_custom_window_keypress_override_callback_exists = 0; - extension_callback_exists(wn_custom_window_keypress_override, wn_custom_window_keypress_override_callback_exists = 1;); - soft_assert(wn_custom_window_keypress_override_callback_exists, ); - } - - call_extension(keypress, ksym, e->state, buf, len); + XKeyEvent *e = &ev->xkey; + KeySym ksym; + char buf[64]; + int len; + rune_t c; + Status status; + + if (IS_SET(MODE_KBDLOCK)) + return; + + if (xw.ime.xic) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof(buf), &ksym, &status); + else + len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); + if (len == 1 && e->state & Mod1Mask) { + if (*buf < 0177) { + c = *buf | 0x80; + len = utf8_encode(c, buf); + } + } + + const struct file_buffer* fb = get_fb(focused_window); + // keysym callback + if (fb->mode & FB_SEARCH_BLOCKING) { + if (search_term_actions(ksym, e->state)) + return; + } + if (fb->mode & FB_SEARCH_BLOCKING) { + search_term_string_insert(buf, len); + return; + } + + if (focused_window->mode != WB_NORMAL) { + int override = 0; + call_extension(wn_custom_window_keypress_override, &override, focused_node, ksym, e->state, buf, len); + if (override) + return; + + int wn_custom_window_keypress_override_callback_exists = 0; + extension_callback_exists(wn_custom_window_keypress_override, wn_custom_window_keypress_override_callback_exists = 1;); + soft_assert(wn_custom_window_keypress_override_callback_exists, ); + } + + call_extension(keypress, ksym, e->state, buf, len); } void cmessage(XEvent *e) { - // See xembed specs - // http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html - if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { - if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { - win.mode |= MODE_FOCUSED; - xseturgency(0); - } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { - win.mode &= ~MODE_FOCUSED; - } - } else if (e->xclient.data.l[0] == xw.wmdeletewin) { - exit(0); - } + // See xembed specs + // http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { + if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { + win.mode |= MODE_FOCUSED; + xseturgency(0); + } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { + win.mode &= ~MODE_FOCUSED; + } + } else if (e->xclient.data.l[0] == xw.wmdeletewin) { + exit(0); + } } void resize(XEvent *e) { - if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) - return; + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; - cresize(e->xconfigure.width, e->xconfigure.height); - writef_to_status_bar("window resize: %d:%d", screen.col, screen.row); + cresize(e->xconfigure.width, e->xconfigure.height); + writef_to_status_bar("window resize: %d:%d", screen.col, screen.row); } void run(void) { - XEvent ev; - int w = win.w, h = win.h; - - // Waiting for window mapping - do { - XNextEvent(xw.dpy, &ev); - /* - * This XFilterEvent call is required because of XOpenIM. It - * does filter out the key event and some client message for - * the input method too. - */ - if (XFilterEvent(&ev, None)) - continue; - if (ev.type == ConfigureNotify) { - w = ev.xconfigure.width; - h = ev.xconfigure.height; - } - } while (ev.type != MapNotify); - - cresize(w, h); - - for (;;) { - struct timespec ts_start; - - int xev = 0; - while (XPending(xw.dpy)) { - XNextEvent(xw.dpy, &ev); - if (XFilterEvent(&ev, None)) - continue; - if (handler[ev.type]) { - clock_gettime(CLOCK_MONOTONIC, &ts_start); - (handler[ev.type])(&ev); - xev = 1; - } - } - - if (!xev) { - nanosleep(&(struct timespec){.tv_nsec = 1e6}, NULL); - continue; - } - - screen_set_region(0, 0, screen.col-1, screen.row-1, ' '); - if (screen.row-2 >= 0) - window_node_draw_tree_to_screen(&root_node, 0, 0, screen.col-1, screen.row-1); - draw_status_bar(); - - xfinishdraw(); - XFlush(xw.dpy); - - struct timespec ts_end; - clock_gettime(CLOCK_MONOTONIC, &ts_end); - double dif = 0; - dif = (ts_end.tv_sec - ts_start.tv_sec) * 1e6; - dif += (ts_end.tv_nsec - ts_start.tv_nsec) * 1e-3; - printf("%lf\n", dif); - } + XEvent ev; + int w = win.w, h = win.h; + + // Waiting for window mapping + do { + XNextEvent(xw.dpy, &ev); + /* + * This XFilterEvent call is required because of XOpenIM. It + * does filter out the key event and some client message for + * the input method too. + */ + if (XFilterEvent(&ev, None)) + continue; + if (ev.type == ConfigureNotify) { + w = ev.xconfigure.width; + h = ev.xconfigure.height; + } + } while (ev.type != MapNotify); + + cresize(w, h); + + for (;;) { + struct timespec ts_start; + + int xev = 0; + while (XPending(xw.dpy)) { + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; + if (handler[ev.type]) { + clock_gettime(CLOCK_MONOTONIC, &ts_start); + (handler[ev.type])(&ev); + xev = 1; + } + } + + if (!xev) { + nanosleep(&(struct timespec){.tv_nsec = 1e6}, NULL); + continue; + } + + screen_set_region(0, 0, screen.col-1, screen.row-1, ' '); + if (screen.row-2 >= 0) + window_node_draw_tree_to_screen(&root_node, 0, 0, screen.col-1, screen.row-1); + draw_status_bar(); + + xfinishdraw(); + XFlush(xw.dpy); + + struct timespec ts_end; + clock_gettime(CLOCK_MONOTONIC, &ts_end); + double dif = 0; + dif = (ts_end.tv_sec - ts_start.tv_sec) * 1e6; + dif += (ts_end.tv_nsec - ts_start.tv_nsec) * 1e-3; + printf("%lf\n", dif); + } } int main(int argc, char *argv[]) { - xw.l = xw.t = 0; - xw.isfixed = False; - - setlocale(LC_CTYPE, ""); - XSetLocaleModifiers(""); - int cols = MAX(default_cols, 1); - int rows = MAX(default_rows, 1); - screen_init(cols, rows); - xinit(cols, rows); - xsetenv(); - - if (argc <= 1) { - *focused_window = wb_new(fb_new_entry(NULL)); - } else { - int master_stack = 1; - for (int i = 1; i < argc; i++) { - if (*argv[i] == '-') { - i++; - } else { - if (master_stack < 0) { - window_node_split(focused_node, 0.5, WINDOW_HORISONTAL); - master_stack = 0; - } else if (master_stack > 0) { - *focused_window = wb_new(fb_new_entry(argv[i])); - master_stack = -1; - continue; - } else { - window_node_split(focused_node, 0.5, WINDOW_VERTICAL); - } - - if (focused_node->node2) { - focused_node = focused_node->node2; - focused_window = &focused_node->wb; - if (!master_stack) - *focused_window = wb_new(fb_new_entry(argv[i])); - } - master_stack = 0; - } - } - } - - srand(time(NULL)); - - // TODO: start screen extension - - if (extensions) { - for (int i = 0; !extensions[i].end; i++) { - if (extensions[i].e.init) - extensions[i].e.init(&extensions[i].e); - if (extensions[i].e.enable) - extensions[i].e.enable(); - } - } - - run(); - - return 0; + xw.l = xw.t = 0; + xw.isfixed = False; + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); + int cols = MAX(default_cols, 1); + int rows = MAX(default_rows, 1); + screen_init(cols, rows); + xinit(cols, rows); + xsetenv(); + + if (argc <= 1) { + *focused_window = wb_new(fb_new_entry(NULL)); + } else { + int master_stack = 1; + for (int i = 1; i < argc; i++) { + if (*argv[i] == '-') { + i++; + } else { + if (master_stack < 0) { + window_node_split(focused_node, 0.5, WINDOW_HORISONTAL); + master_stack = 0; + } else if (master_stack > 0) { + *focused_window = wb_new(fb_new_entry(argv[i])); + master_stack = -1; + continue; + } else { + window_node_split(focused_node, 0.5, WINDOW_VERTICAL); + } + + if (focused_node->node2) { + focused_node = focused_node->node2; + focused_window = &focused_node->wb; + if (!master_stack) + *focused_window = wb_new(fb_new_entry(argv[i])); + } + master_stack = 0; + } + } + } + + srand(time(NULL)); + + // TODO: start screen extension + + if (extensions) { + for (int i = 0; !extensions[i].end; i++) { + if (extensions[i].e.init) + extensions[i].e.init(&extensions[i].e); + if (extensions[i].e.enable) + extensions[i].e.enable(); + } + } + + run(); + + return 0; } diff --git a/x.h b/x.h @@ -25,31 +25,31 @@ void set_clipboard_copy(char* buffer, int len); void execute_clipbaord_event(); enum glyph_attribute { - ATTR_NULL = 0, - ATTR_BOLD = 1 << 0, - ATTR_FAINT = 1 << 1, - ATTR_ITALIC = 1 << 2, - ATTR_UNDERLINE = 1 << 3, - ATTR_REVERSE = 1 << 5, - ATTR_INVISIBLE = 1 << 6, - ATTR_STRUCK = 1 << 7, - ATTR_WIDE = 1 << 9, - ATTR_WDUMMY = 1 << 10, - ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + ATTR_NULL = 0, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; struct glyph { - rune_t u; // character code - uint16_t mode; // attribute flags - uint32_t fg; // foreground - uint32_t bg; // background + rune_t u; // character code + uint16_t mode; // attribute flags + uint32_t fg; // foreground + uint32_t bg; // background }; // Internal representation of the screen struct screen { - int row; // row count - int col; // column count - struct glyph** lines; // screen letters 2d array + int row; // row count + int col; // column count + struct glyph** lines; // screen letters 2d array }; extern struct screen screen; @@ -68,27 +68,27 @@ void die(const char *, ...); // the va_args can be used to return; or any other stuff like that // TODO: optionally crash the program for debugging #define soft_assert(condition, ...) \ - do { \ - if(!(condition)) { \ - fprintf(stderr, "SOFT ASSERT ERROR: (%s) failed at %s %s():%d\n", #condition, __FILE__, __func__, __LINE__); \ - writef_to_status_bar("SOFT ASSERT ERROR: (%s) failed at %s %s():%d", #condition, __FILE__, __func__, __LINE__); \ - status_bar_bg = error_color; \ - __VA_ARGS__ \ - } \ - } while(0) \ + do { \ + if(!(condition)) { \ + fprintf(stderr, "SOFT ASSERT ERROR: (%s) failed at %s %s():%d\n", #condition, __FILE__, __func__, __LINE__); \ + writef_to_status_bar("SOFT ASSERT ERROR: (%s) failed at %s %s():%d", #condition, __FILE__, __func__, __LINE__); \ + status_bar_bg = error_color; \ + __VA_ARGS__ \ + } \ + } while(0) \ enum win_mode { - MODE_VISIBLE = 1 << 0, - MODE_FOCUSED = 1 << 1, - MODE_APPKEYPAD = 1 << 2, - MODE_KBDLOCK = 1 << 6, - MODE_HIDE = 1 << 7, - MODE_APPCURSOR = 1 << 8, - MODE_MOUSESGR = 1 << 9, - MODE_BLINK = 1 << 11, - MODE_FBLINK = 1 << 12, - MODE_BRCKTPASTE = 1 << 16, - MODE_NUMLOCK = 1 << 17, + MODE_VISIBLE = 1 << 0, + MODE_FOCUSED = 1 << 1, + MODE_APPKEYPAD = 1 << 2, + MODE_KBDLOCK = 1 << 6, + MODE_HIDE = 1 << 7, + MODE_APPCURSOR = 1 << 8, + MODE_MOUSESGR = 1 << 9, + MODE_BLINK = 1 << 11, + MODE_FBLINK = 1 << 12, + MODE_BRCKTPASTE = 1 << 16, + MODE_NUMLOCK = 1 << 17, }; #define MIN(a, b) ((a) < (b) ? (a) : (b))