diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2023-11-09 23:19:53 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2023-11-09 23:19:53 +0100 |
| commit | 1566b6faa8534118c3566188181367cd0868468f (patch) | |
| tree | 1de8d4b369efb5e592685a31088f798a6b63ffa1 /examples/dte/indent.c | |
| parent | 349991bf6efe473ab9a5cbdae0a8114d72b997e3 (diff) | |
| download | crep-1566b6faa8534118c3566188181367cd0868468f.tar.gz | |
Added partial matching and introduced threads
Diffstat (limited to 'examples/dte/indent.c')
| -rw-r--r-- | examples/dte/indent.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/examples/dte/indent.c b/examples/dte/indent.c new file mode 100644 index 0000000..0d5d2ae --- /dev/null +++ b/examples/dte/indent.c @@ -0,0 +1,193 @@ +#include <sys/types.h> +#include "indent.h" +#include "regexp.h" +#include "util/xmalloc.h" + +char *make_indent(const LocalOptions *options, size_t width) +{ + if (width == 0) { + return NULL; + } + + if (use_spaces_for_indent(options)) { + char *str = xmalloc(width + 1); + str[width] = '\0'; + return memset(str, ' ', width); + } + + size_t tw = options->tab_width; + size_t ntabs = indent_level(width, tw); + size_t nspaces = indent_remainder(width, tw); + size_t n = ntabs + nspaces; + char *str = xmalloc(n + 1); + memset(str + ntabs, ' ', nspaces); + str[n] = '\0'; + return memset(str, '\t', ntabs); +} + +static bool indent_inc(const LocalOptions *options, const StringView *line) +{ + static regex_t re1, re2; + static bool compiled; + if (!compiled) { + // TODO: Make these patterns configurable via a local option + static const char pat1[] = "\\{[\t ]*(//.*|/\\*.*\\*/[\t ]*)?$"; + static const char pat2[] = "\\}[\t ]*(//.*|/\\*.*\\*/[\t ]*)?$"; + regexp_compile_or_fatal_error(&re1, pat1, REG_NEWLINE | REG_NOSUB); + regexp_compile_or_fatal_error(&re2, pat2, REG_NEWLINE | REG_NOSUB); + compiled = true; + } + + if (options->brace_indent) { + regmatch_t m; + if (regexp_exec(&re1, line->data, line->length, 0, &m, 0)) { + return true; + } + if (regexp_exec(&re2, line->data, line->length, 0, &m, 0)) { + return false; + } + } + + const InternedRegexp *ir = options->indent_regex; + if (!ir) { + return false; + } + + BUG_ON(ir->str[0] == '\0'); + regmatch_t m; + return regexp_exec(&ir->re, line->data, line->length, 0, &m, 0); +} + +char *get_indent_for_next_line(const LocalOptions *options, const StringView *line) +{ + size_t width = get_indent_width(options, line); + if (indent_inc(options, line)) { + width = next_indent_width(width, options->indent_width); + } + return make_indent(options, width); +} + +IndentInfo get_indent_info(const LocalOptions *options, const StringView *line) +{ + const char *buf = line->data; + const size_t len = line->length; + const size_t tw = options->tab_width; + const size_t iw = options->indent_width; + const bool space_indent = use_spaces_for_indent(options); + IndentInfo info = {.sane = true}; + size_t spaces = 0; + size_t tabs = 0; + size_t pos = 0; + + for (; pos < len; pos++) { + if (buf[pos] == ' ') { + info.width++; + spaces++; + } else if (buf[pos] == '\t') { + info.width = next_indent_width(info.width, tw); + tabs++; + } else { + break; + } + if (indent_remainder(info.width, iw) == 0 && info.sane) { + info.sane = space_indent ? !tabs : !spaces; + } + } + + info.level = indent_level(info.width, iw); + info.wsonly = (pos == len); + info.bytes = spaces + tabs; + return info; +} + +size_t get_indent_width(const LocalOptions *options, const StringView *line) +{ + const char *buf = line->data; + size_t width = 0; + for (size_t i = 0, n = line->length, tw = options->tab_width; i < n; i++) { + if (buf[i] == ' ') { + width++; + } else if (buf[i] == '\t') { + width = next_indent_width(width, tw); + } else { + break; + } + } + return width; +} + +static ssize_t get_current_indent_bytes(const LocalOptions *options, const char *buf, size_t cursor_offset) +{ + const size_t tw = options->tab_width; + const size_t iw = options->indent_width; + size_t ibytes = 0; + size_t iwidth = 0; + + for (size_t i = 0; i < cursor_offset; i++) { + if (indent_remainder(iwidth, iw) == 0) { + ibytes = 0; + iwidth = 0; + } + switch (buf[i]) { + case '\t': + iwidth = next_indent_width(iwidth, tw); + break; + case ' ': + iwidth++; + break; + default: + // Cursor not at indentation + return -1; + } + ibytes++; + } + + if (indent_remainder(iwidth, iw)) { + // Cursor at middle of indentation level + return -1; + } + + return (ssize_t)ibytes; +} + +size_t get_indent_level_bytes_left(const LocalOptions *options, BlockIter *cursor) +{ + StringView line; + size_t cursor_offset = fetch_this_line(cursor, &line); + if (!cursor_offset) { + return 0; + } + ssize_t ibytes = get_current_indent_bytes(options, line.data, cursor_offset); + return (ibytes < 0) ? 0 : (size_t)ibytes; +} + +size_t get_indent_level_bytes_right(const LocalOptions *options, BlockIter *cursor) +{ + StringView line; + size_t cursor_offset = fetch_this_line(cursor, &line); + ssize_t ibytes = get_current_indent_bytes(options, line.data, cursor_offset); + if (ibytes < 0) { + return 0; + } + + const size_t tw = options->tab_width; + const size_t iw = options->indent_width; + size_t iwidth = 0; + for (size_t i = cursor_offset, n = line.length; i < n; i++) { + switch (line.data[i]) { + case '\t': + iwidth = next_indent_width(iwidth, tw); + break; + case ' ': + iwidth++; + break; + default: + // No full indentation level at cursor position + return 0; + } + if (indent_remainder(iwidth, iw) == 0) { + return i - cursor_offset + 1; + } + } + return 0; +} |
