summaryrefslogtreecommitdiff
path: root/examples/dte/indent.c
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2023-11-09 23:19:53 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2023-11-09 23:19:53 +0100
commit1566b6faa8534118c3566188181367cd0868468f (patch)
tree1de8d4b369efb5e592685a31088f798a6b63ffa1 /examples/dte/indent.c
parent349991bf6efe473ab9a5cbdae0a8114d72b997e3 (diff)
downloadcrep-1566b6faa8534118c3566188181367cd0868468f.tar.gz
Added partial matching and introduced threads
Diffstat (limited to 'examples/dte/indent.c')
-rw-r--r--examples/dte/indent.c193
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;
+}