diff options
Diffstat (limited to 'examples/dte/buffer.c')
| -rw-r--r-- | examples/dte/buffer.c | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/examples/dte/buffer.c b/examples/dte/buffer.c deleted file mode 100644 index 705ec0c..0000000 --- a/examples/dte/buffer.c +++ /dev/null @@ -1,480 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include "buffer.h" -#include "editor.h" -#include "file-option.h" -#include "filetype.h" -#include "lock.h" -#include "syntax/state.h" -#include "util/debug.h" -#include "util/intern.h" -#include "util/log.h" -#include "util/numtostr.h" -#include "util/path.h" -#include "util/str-util.h" -#include "util/time-util.h" -#include "util/xmalloc.h" - -void set_display_filename(Buffer *buffer, char *name) -{ - free(buffer->display_filename); - buffer->display_filename = name; -} - -/* - * Mark line range min...max (inclusive) "changed". These lines will be - * redrawn when screen is updated. This is called even when content has not - * been changed, but selection has or line has been deleted and all lines - * after the deleted line move up. - * - * Syntax highlighter has different logic. It cares about contents of the - * lines, not about selection or if the lines have been moved up or down. - */ -void buffer_mark_lines_changed(Buffer *buffer, long min, long max) -{ - if (min > max) { - long tmp = min; - min = max; - max = tmp; - } - buffer->changed_line_min = MIN(min, buffer->changed_line_min); - buffer->changed_line_max = MAX(max, buffer->changed_line_max); -} - -const char *buffer_filename(const Buffer *buffer) -{ - const char *name = buffer->display_filename; - return name ? name : "(No name)"; -} - -void buffer_set_encoding(Buffer *buffer, Encoding encoding, bool utf8_bom) -{ - if ( - buffer->encoding.type != encoding.type - || buffer->encoding.name != encoding.name - ) { - const EncodingType type = encoding.type; - if (type == UTF8) { - buffer->bom = utf8_bom; - } else { - buffer->bom = type < NR_ENCODING_TYPES && !!get_bom_for_encoding(type); - } - buffer->encoding = encoding; - } -} - -Buffer *buffer_new(PointerArray *buffers, const GlobalOptions *gopts, const Encoding *encoding) -{ - static unsigned long id; - Buffer *buffer = xnew0(Buffer, 1); - list_init(&buffer->blocks); - buffer->cur_change = &buffer->change_head; - buffer->saved_change = &buffer->change_head; - buffer->id = ++id; - buffer->crlf_newlines = gopts->crlf_newlines; - - if (encoding) { - buffer_set_encoding(buffer, *encoding, gopts->utf8_bom); - } else { - buffer->encoding.type = ENCODING_AUTODETECT; - } - - static_assert(sizeof(*gopts) >= sizeof(CommonOptions)); - memcpy(&buffer->options, gopts, sizeof(CommonOptions)); - buffer->options.brace_indent = 0; - buffer->options.filetype = str_intern("none"); - buffer->options.indent_regex = NULL; - - ptr_array_append(buffers, buffer); - return buffer; -} - -Buffer *open_empty_buffer(PointerArray *buffers, const GlobalOptions *gopts) -{ - Encoding enc = encoding_from_type(UTF8); - Buffer *buffer = buffer_new(buffers, gopts, &enc); - - // At least one block required - Block *blk = block_new(1); - list_add_before(&blk->node, &buffer->blocks); - - return buffer; -} - -void free_blocks(Buffer *buffer) -{ - ListHead *item = buffer->blocks.next; - while (item != &buffer->blocks) { - ListHead *next = item->next; - Block *blk = BLOCK(item); - free(blk->data); - free(blk); - item = next; - } -} - -void free_buffer(Buffer *buffer) -{ - if (buffer->locked) { - unlock_file(buffer->abs_filename); - } - - free_changes(&buffer->change_head); - free(buffer->line_start_states.ptrs); - free(buffer->views.ptrs); - free(buffer->display_filename); - free(buffer->abs_filename); - - if (buffer->stdout_buffer) { - return; - } - - free_blocks(buffer); - free(buffer); -} - -void remove_and_free_buffer(PointerArray *buffers, Buffer *buffer) -{ - ptr_array_remove(buffers, buffer); - free_buffer(buffer); -} - -static bool same_file(const Buffer *buffer, const struct stat *st) -{ - return (st->st_dev == buffer->file.dev) && (st->st_ino == buffer->file.ino); -} - -Buffer *find_buffer(const PointerArray *buffers, const char *abs_filename) -{ - struct stat st; - bool st_ok = stat(abs_filename, &st) == 0; - for (size_t i = 0, n = buffers->count; i < n; i++) { - Buffer *buffer = buffers->ptrs[i]; - const char *f = buffer->abs_filename; - if ((f && streq(f, abs_filename)) || (st_ok && same_file(buffer, &st))) { - return buffer; - } - } - return NULL; -} - -Buffer *find_buffer_by_id(const PointerArray *buffers, unsigned long id) -{ - for (size_t i = 0, n = buffers->count; i < n; i++) { - Buffer *buffer = buffers->ptrs[i]; - if (buffer->id == id) { - return buffer; - } - } - return NULL; -} - -bool buffer_detect_filetype(Buffer *buffer, const PointerArray *filetypes) -{ - StringView line = STRING_VIEW_INIT; - if (BLOCK(buffer->blocks.next)->size) { - BlockIter bi = block_iter(buffer); - fill_line_ref(&bi, &line); - } else if (!buffer->abs_filename) { - return false; - } - - const char *ft = find_ft(filetypes, buffer->abs_filename, line); - if (ft && !streq(ft, buffer->options.filetype)) { - buffer->options.filetype = str_intern(ft); - return true; - } - - return false; -} - -void update_short_filename_cwd(Buffer *buffer, const StringView *home, const char *cwd) -{ - const char *abs = buffer->abs_filename; - if (!abs) { - return; - } - char *name = cwd ? short_filename_cwd(abs, cwd, home) : xstrdup(abs); - set_display_filename(buffer, name); -} - -void update_short_filename(Buffer *buffer, const StringView *home) -{ - BUG_ON(!buffer->abs_filename); - set_display_filename(buffer, short_filename(buffer->abs_filename, home)); -} - -void buffer_update_syntax(EditorState *e, Buffer *buffer) -{ - Syntax *syn = NULL; - if (buffer->options.syntax) { - // Even "none" can have syntax - syn = find_syntax(&e->syntaxes, buffer->options.filetype); - if (!syn) { - syn = load_syntax_by_filetype(e, buffer->options.filetype); - } - } - if (syn == buffer->syn) { - return; - } - - buffer->syn = syn; - if (syn) { - // Start state of first line is constant - PointerArray *s = &buffer->line_start_states; - if (!s->alloc) { - ptr_array_init(s, 64); - } - s->ptrs[0] = syn->start_state; - s->count = 1; - } - - mark_all_lines_changed(buffer); -} - -static bool allow_odd_indent(uint8_t indents_bitmask) -{ - static_assert(INDENT_WIDTH_MAX == 8); - return !!(indents_bitmask & 0x55); // 0x55 == 0b01010101 -} - -static int indent_len(StringView line, uint8_t indents_bitmask, bool *tab_indent) -{ - bool space_before_tab = false; - size_t spaces = 0; - size_t tabs = 0; - size_t pos = 0; - - for (size_t n = line.length; pos < n; pos++) { - switch (line.data[pos]) { - case '\t': - tabs++; - if (spaces) { - space_before_tab = true; - } - continue; - case ' ': - spaces++; - continue; - } - break; - } - - *tab_indent = false; - if (pos == line.length) { - return -1; // Whitespace only - } - if (pos == 0) { - return 0; // Not indented - } - if (space_before_tab) { - return -2; // Mixed indent - } - if (tabs) { - // Tabs and possible spaces after tab for alignment - *tab_indent = true; - return tabs * 8; - } - if (line.length > spaces && line.data[spaces] == '*') { - // '*' after indent, could be long C style comment - if (spaces & 1 || allow_odd_indent(indents_bitmask)) { - return spaces - 1; - } - } - return spaces; -} - -UNITTEST { - bool tab; - int len = indent_len(strview_from_cstring(" 4 space"), 0, &tab); - BUG_ON(len != 4); - BUG_ON(tab); - - len = indent_len(strview_from_cstring("\t\t2 tab"), 0, &tab); - BUG_ON(len != 16); - BUG_ON(!tab); - - len = indent_len(strview_from_cstring("no indent"), 0, &tab); - BUG_ON(len != 0); - - len = indent_len(strview_from_cstring(" \t mixed"), 0, &tab); - BUG_ON(len != -2); - - len = indent_len(strview_from_cstring("\t \t "), 0, &tab); - BUG_ON(len != -1); // whitespace only - - len = indent_len(strview_from_cstring(" * 5 space"), 0, &tab); - BUG_ON(len != 4); - - StringView line = strview_from_cstring(" * 4 space"); - len = indent_len(line, 0, &tab); - BUG_ON(len != 4); - len = indent_len(line, 1 << 2, &tab); - BUG_ON(len != 3); -} - -static bool detect_indent(Buffer *buffer) -{ - LocalOptions *options = &buffer->options; - unsigned int bitset = options->detect_indent; - BlockIter bi = block_iter(buffer); - unsigned int tab_count = 0; - unsigned int space_count = 0; - int current_indent = 0; - int counts[INDENT_WIDTH_MAX + 1] = {0}; - BUG_ON((bitset & ((1u << INDENT_WIDTH_MAX) - 1)) != bitset); - - for (size_t i = 0, j = 1; i < 200 && j > 0; i++, j = block_iter_next_line(&bi)) { - StringView line; - fill_line_ref(&bi, &line); - bool tab; - int indent = indent_len(line, bitset, &tab); - switch (indent) { - case -2: // Ignore mixed indent because tab width might not be 8 - case -1: // Empty line; no change in indent - continue; - case 0: - current_indent = 0; - continue; - } - - BUG_ON(indent <= 0); - int change = indent - current_indent; - if (change >= 1 && change <= INDENT_WIDTH_MAX) { - counts[change]++; - } - - if (tab) { - tab_count++; - } else { - space_count++; - } - current_indent = indent; - } - - if (tab_count == 0 && space_count == 0) { - return false; - } - - if (tab_count > space_count) { - options->emulate_tab = false; - options->expand_tab = false; - options->indent_width = options->tab_width; - return true; - } - - size_t m = 0; - for (size_t i = 1; i < ARRAYLEN(counts); i++) { - unsigned int bit = 1u << (i - 1); - if ((bitset & bit) && counts[i] > counts[m]) { - m = i; - } - } - - if (m == 0) { - return false; - } - - options->emulate_tab = true; - options->expand_tab = true; - options->indent_width = m; - return true; -} - -void buffer_setup(EditorState *e, Buffer *buffer) -{ - const char *filename = buffer->abs_filename; - buffer->setup = true; - buffer_detect_filetype(buffer, &e->filetypes); - set_file_options(e, buffer); - set_editorconfig_options(buffer); - buffer_update_syntax(e, buffer); - if (buffer->options.detect_indent && filename) { - detect_indent(buffer); - } - sanity_check_local_options(&buffer->options); -} - -void buffer_count_blocks_and_bytes(const Buffer *buffer, uintmax_t counts[2]) -{ - uintmax_t blocks = 0; - uintmax_t bytes = 0; - Block *blk; - block_for_each(blk, &buffer->blocks) { - blocks += 1; - bytes += blk->size; - } - counts[0] = blocks; - counts[1] = bytes; -} - -// TODO: Human-readable size (MiB/GiB/etc.) for "Bytes" and FileInfo::size -String dump_buffer(const Buffer *buffer) -{ - uintmax_t counts[2]; - buffer_count_blocks_and_bytes(buffer, counts); - BUG_ON(counts[0] < 1); - BUG_ON(!buffer->setup); - String buf = string_new(1024); - - string_sprintf ( - &buf, - "%s %s\n%s %lu\n%s %s\n%s %s\n%s %ju\n%s %zu\n%s %ju\n", - " Name:", buffer_filename(buffer), - " ID:", buffer->id, - " Encoding:", buffer->encoding.name, - " Filetype:", buffer->options.filetype, - " Blocks:", counts[0], - " Lines:", buffer->nl, - " Bytes:", counts[1] - ); - - if ( - buffer->stdout_buffer || buffer->temporary || buffer->readonly - || buffer->locked || buffer->crlf_newlines || buffer->bom - ) { - string_sprintf ( - &buf, - " Flags:%s%s%s%s%s%s\n", - buffer->stdout_buffer ? " STDOUT" : "", - buffer->temporary ? " TMP" : "", - buffer->readonly ? " RO" : "", - buffer->locked ? " LOCKED" : "", - buffer->crlf_newlines ? " CRLF" : "", - buffer->bom ? " BOM" : "" - ); - } - - if (buffer->views.count > 1) { - string_sprintf(&buf, " Views: %zu\n", buffer->views.count); - } - - if (!buffer->abs_filename) { - return buf; - } - - const FileInfo *file = &buffer->file; - unsigned int perms = file->mode & 07777; - char modestr[12]; - char timestr[64]; - if (!timespec_to_str(&file->mtime, timestr, sizeof(timestr))) { - memcpy(timestr, STRN("[error]") + 1); - } - - string_sprintf ( - &buf, - "\nLast stat:\n----------\n\n" - "%s %s\n%s %s\n%s -%s (%04o)\n%s %jd\n%s %jd\n%s %ju\n%s %jd\n%s %ju\n", - " Path:", buffer->abs_filename, - " Modified:", timestr, - " Mode:", filemode_to_str(file->mode, modestr), perms, - " User:", (intmax_t)file->uid, - " Group:", (intmax_t)file->gid, - " Size:", (uintmax_t)file->size, - " Device:", (intmax_t)file->dev, - " Inode:", (uintmax_t)file->ino - ); - - return buf; -} |
