<commit_before>/* A unique cursorless text editor. (c) 2015 <NAME> */
#include <ctype.h>
#include <curses.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define C_D 4
#define C_U 21
#define C_W 23

static char *filename, *buffer, *start, *end;
char errbuf[256];
static int bufsize, gap, lwe_scroll;

static int gapsize(void)
{
	return bufsize - gap;
}

static void err(const char *str)
{
	snprintf(errbuf, sizeof(errbuf), "%s", str);
}

static bool bext(void)
{
	int newsize = bufsize * 2;
	buffer = realloc(buffer, newsize);
	if (buffer == NULL) {
		err("memory");
		return false;
	}
	bufsize = newsize;
	return true;
}

static bool bins(char c, char *t)
{
	int sz;
	sz = gap - (t - buffer);
	memmove(t + 1, t, sz);
	*t = c;
	gap++;
	if (gapsize() == 0)
		return bext();
	else
		return true;
}

static bool initbuf(int sz)
{
	bufsize = sz + 4096;
	gap = sz;
	buffer = malloc(bufsize);
	if (buffer == NULL) {
		err("memory");
		return false;
	}
	return true;
}

static bool filetobuf(int sz)
{
	FILE *f = fopen(filename, "r");
	if (f == NULL) {
		err("read");
		return false;
	}
	int rsz = fread(buffer, 1, sz, f);
	if (rsz != sz) {
		err("read");
		return false;
	}
	return true;
}

static bool bread(void)
{
	struct stat st;
	errno = 0;
	stat(filename, &st);
	if (errno == 0) {
		bool ok = initbuf(st.st_size);
		if (!ok)
			return false;
		return filetobuf(st.st_size);
	} else if (errno == ENOENT) {
		return initbuf(0);
	} else {
		err(strerror(errno));
		return false;
	}
}

int breload()
{
	free(buffer);
	return bread();
}

static int bsave(void)
{
	FILE *f = fopen(filename, "w");
	if (f == NULL) {
		const char msg1[] = "Error: Failed to write to: ";
		const char msg2[] = "Press any key to continue.";
		char nstr[strlen(msg1) + strlen(filename) + 1];
		snprintf(nstr, sizeof(nstr), "%s%s", msg1, filename);
		attron(A_STANDOUT);
		mvaddstr(LINES-2, 0, nstr);
		mvaddstr(LINES-1, 0, msg2);
		attroff(A_STANDOUT);
		refresh();
		getch();
		return 1;
	}
	fwrite(buffer, 1, bufsize - gapsize(), f);
	fclose(f);
	return 1;
}

static int isend(const char *s)
{
	return s >= (buffer + bufsize - gapsize());
}

static void winbounds(void)
{
	int r, c, i;
	r = c = 0;
	for (i = lwe_scroll, start = buffer; i > 0 && !isend(start); (start)++)
		if (*start == '\n')
			i--;
	end = start;
	loop:if (isend(end))
		return;
	c++;
	if (*end == '\n') {
		c = 0;
	}
	c %= COLS;
	if (c == 0)
		r++;
	end++;
	if (r < LINES)
		goto loop;
	else
		end--;
}

static void pc(char c)
{
	if (!isgraph(c) && !isspace(c))
		c = '?';
	addch(c);
}

static void draw(void)
{
	char *i;
	erase();
	move(0, 0);
	winbounds();
	for (i = start; i != end; i++)
		pc(*i);
	refresh();
}

static void doscrl(int d)
{
	lwe_scroll += d;
	if (lwe_scroll < 0)
		lwe_scroll = 0;
}

static void jumptoline(void)
{
	char buf[32], c;
	int i;
	memset(buf, '\0', 32);
	for (i = 0; i < 32; i++) {
		c = getch();
		if (isdigit(c))
			buf[i] = c;
		else
			break;
	}
	i = atoi(buf);
	if (i == 0)
		return;
	lwe_scroll = i;
	doscrl(-LINES / 2);
}

static char *find(char c, int n)
{
	char *i;
	for (i = start; i < end; i++) {
		if (*i == c) {
			if (n <= 0)
				return i;
			else
				n--;
		}
	}
	return 0;
}

static int count(char c)
{
	int ct;
	char *i;
	ct = 0;
	for (i = start; i != end; i++)
		if (*i == c)
			ct++;
	return ct;
}

static int findcharcount(char *s, char *e, char c)
{
	int count = 0;
	if(!s || !e){
		return count;
	}
	while(s != e){
		if(*s == c){
			count++;
		}
		s++;
	}
	return count;
}

static void ptarg(int count)
{
	char a;
	a = 'a' + (count % 26);
	attron(A_STANDOUT);
	pc(a);
	attroff(A_STANDOUT);
}

static int skips(int lvl)
{
	if (lvl == 0)
		return 0;
	int i = 1;
	while (lvl > 0) {
		lvl--;
		i *= 26;
	}
	return i - 1;
}

static void drawdisambchar(char c, int toskip, char *i, int *tcount)
{
	if (*i == c && toskip <= 0) {
		ptarg(*tcount);
		(*tcount)++;
	} else {
		pc(*i);
	}
}

static void drawdisamb(char c, int lvl, int toskip)
{
	erase();
	move(0, 0);
	int tcount = 0;
	for (char *i = start; i < end; i++) {
		drawdisambchar(c, toskip, i, &tcount);
		if (*i != c)
			continue;
		toskip = (toskip > 0) ? (toskip - 1) : skips(lvl);
	}
	refresh();
}

static bool onlymatch(char c, int lvl, int toskip)
{
	// If the initial skip + this level's skip in between matches is
	// greater than the count of matching characters in the window,
	// then we have narrowed it down to just one choice.  The second
	// match would have to be past the end of the window.
	return skips(lvl) + toskip >= count(c);
}

static char *disamb(char c)
{
	int lvl = 0;
	int toskip = 0;
	while (!onlymatch(c, lvl, toskip)) {
		drawdisamb(c, lvl, toskip);
		char input = getch();
		int i = input - 'a';
		if (i < 0 || i >= 26)
			return NULL;
		toskip += i * (skips(lvl) + 1);
		lvl++;
	}
	return find(c, toskip);
}

static char *hunt(void)
{
	char c;
	if (gapsize() == bufsize)
		return buffer;
	draw();
	c = getch();
	return disamb(c);
}

static void drawlinelbls(int lvl, int off)
{
	erase();
	move(0, 0);
	winbounds();
	for (char *i = start; i != end; i++)
		pc(*i);
	int count = 0;
	int step = skips(lvl) + 1;
	step = step < 1 ? 1 : step;
	for (int line = off; line < LINES; line += step) {
		move(line, 0);
		ptarg(count++);
	}
	refresh();
}

static bool lineselected(int lvl, int off)
{
	return off + skips(lvl) > LINES;
}

static int getoffset(int lvl, int off)
{
	char c = getch();
	int i = c - 'a';
	if (i < 0 || i >= 26)
		return -1;
	int delta = (skips(lvl) + 1) * i;
	return off + delta;
}

static char *startofline(int off)
{
	char *result = start;
	while (off > 0) {
		if (result >= end)
			return NULL;
		if (*result == '\n')
			off--;
		result++;
	}
	return result;
}

static char *endofline(int off)
{
	char *nextstart = startofline(off + 1);
	return nextstart - 1;
}

static int linehunt(void)
{
	int lvl = 0;
	int off = 0;
	if (gapsize() == bufsize)
		return -1;
	while (!lineselected(lvl, off)) {
		drawlinelbls(lvl, off);
		off = getoffset(lvl, off);
		if (off < 0)
			return -1;
		lvl++;
	}
	return off;
}

static void rubout(char *t)
{
	int sz;
	sz = gap - (t + 1 - buffer);
	memmove(t, t + 1, sz);
	gap--;
}

static void delete(char *start, char *end)
{
	int n, tn;
	if (end != buffer + bufsize)
		end++;
	n = buffer + bufsize - end;
	tn = end - start;
	memmove(start, end, n);
	gap -= tn;
}

static void movecursor(char *t){
	if (!t) 
		return;
	// Figure out line number, number of tabs on the line,
	// along with how much space each tab is actually taking up
	// so we can figure out the offset in order to highlight the cursor
	int offset = 0;
	int numtabs = 0;
	int linenumber = findcharcount(start, t, '\n');
	char* linestart = startofline(linenumber);
	if (linestart) {
		char* iter = linestart;
			while (iter != t) {
				if (*iter == '\t') {
					if (iter != linestart) {
						const char* const prev = iter - 1;
						if (*prev == '\t') {
							offset += TABSIZE;
							iter++;
							continue;
						}
					}
					int lineidx = iter - linestart;
					offset += (TABSIZE - (lineidx % TABSIZE));
				}
				else {
					offset++;<commit_msg>Missed a no longer used variable.<commit_after>/* A unique cursorless text editor. (c) 2015 <NAME> */
#include <ctype.h>
#include <curses.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define C_D 4
#define C_U 21
#define C_W 23

static char *filename, *buffer, *start, *end;
char errbuf[256];
static int bufsize, gap, lwe_scroll;

static int gapsize(void)
{
	return bufsize - gap;
}

static void err(const char *str)
{
	snprintf(errbuf, sizeof(errbuf), "%s", str);
}

static bool bext(void)
{
	int newsize = bufsize * 2;
	buffer = realloc(buffer, newsize);
	if (buffer == NULL) {
		err("memory");
		return false;
	}
	bufsize = newsize;
	return true;
}

static bool bins(char c, char *t)
{
	int sz;
	sz = gap - (t - buffer);
	memmove(t + 1, t, sz);
	*t = c;
	gap++;
	if (gapsize() == 0)
		return bext();
	else
		return true;
}

static bool initbuf(int sz)
{
	bufsize = sz + 4096;
	gap = sz;
	buffer = malloc(bufsize);
	if (buffer == NULL) {
		err("memory");
		return false;
	}
	return true;
}

static bool filetobuf(int sz)
{
	FILE *f = fopen(filename, "r");
	if (f == NULL) {
		err("read");
		return false;
	}
	int rsz = fread(buffer, 1, sz, f);
	if (rsz != sz) {
		err("read");
		return false;
	}
	return true;
}

static bool bread(void)
{
	struct stat st;
	errno = 0;
	stat(filename, &st);
	if (errno == 0) {
		bool ok = initbuf(st.st_size);
		if (!ok)
			return false;
		return filetobuf(st.st_size);
	} else if (errno == ENOENT) {
		return initbuf(0);
	} else {
		err(strerror(errno));
		return false;
	}
}

int breload()
{
	free(buffer);
	return bread();
}

static int bsave(void)
{
	FILE *f = fopen(filename, "w");
	if (f == NULL) {
		const char msg1[] = "Error: Failed to write to: ";
		const char msg2[] = "Press any key to continue.";
		char nstr[strlen(msg1) + strlen(filename) + 1];
		snprintf(nstr, sizeof(nstr), "%s%s", msg1, filename);
		attron(A_STANDOUT);
		mvaddstr(LINES-2, 0, nstr);
		mvaddstr(LINES-1, 0, msg2);
		attroff(A_STANDOUT);
		refresh();
		getch();
		return 1;
	}
	fwrite(buffer, 1, bufsize - gapsize(), f);
	fclose(f);
	return 1;
}

static int isend(const char *s)
{
	return s >= (buffer + bufsize - gapsize());
}

static void winbounds(void)
{
	int r, c, i;
	r = c = 0;
	for (i = lwe_scroll, start = buffer; i > 0 && !isend(start); (start)++)
		if (*start == '\n')
			i--;
	end = start;
	loop:if (isend(end))
		return;
	c++;
	if (*end == '\n') {
		c = 0;
	}
	c %= COLS;
	if (c == 0)
		r++;
	end++;
	if (r < LINES)
		goto loop;
	else
		end--;
}

static void pc(char c)
{
	if (!isgraph(c) && !isspace(c))
		c = '?';
	addch(c);
}

static void draw(void)
{
	char *i;
	erase();
	move(0, 0);
	winbounds();
	for (i = start; i != end; i++)
		pc(*i);
	refresh();
}

static void doscrl(int d)
{
	lwe_scroll += d;
	if (lwe_scroll < 0)
		lwe_scroll = 0;
}

static void jumptoline(void)
{
	char buf[32], c;
	int i;
	memset(buf, '\0', 32);
	for (i = 0; i < 32; i++) {
		c = getch();
		if (isdigit(c))
			buf[i] = c;
		else
			break;
	}
	i = atoi(buf);
	if (i == 0)
		return;
	lwe_scroll = i;
	doscrl(-LINES / 2);
}

static char *find(char c, int n)
{
	char *i;
	for (i = start; i < end; i++) {
		if (*i == c) {
			if (n <= 0)
				return i;
			else
				n--;
		}
	}
	return 0;
}

static int count(char c)
{
	int ct;
	char *i;
	ct = 0;
	for (i = start; i != end; i++)
		if (*i == c)
			ct++;
	return ct;
}

static int findcharcount(char *s, char *e, char c)
{
	int count = 0;
	if(!s || !e){
		return count;
	}
	while(s != e){
		if(*s == c){
			count++;
		}
		s++;
	}
	return count;
}

static void ptarg(int count)
{
	char a;
	a = 'a' + (count % 26);
	attron(A_STANDOUT);
	pc(a);
	attroff(A_STANDOUT);
}

static int skips(int lvl)
{
	if (lvl == 0)
		return 0;
	int i = 1;
	while (lvl > 0) {
		lvl--;
		i *= 26;
	}
	return i - 1;
}

static void drawdisambchar(char c, int toskip, char *i, int *tcount)
{
	if (*i == c && toskip <= 0) {
		ptarg(*tcount);
		(*tcount)++;
	} else {
		pc(*i);
	}
}

static void drawdisamb(char c, int lvl, int toskip)
{
	erase();
	move(0, 0);
	int tcount = 0;
	for (char *i = start; i < end; i++) {
		drawdisambchar(c, toskip, i, &tcount);
		if (*i != c)
			continue;
		toskip = (toskip > 0) ? (toskip - 1) : skips(lvl);
	}
	refresh();
}

static bool onlymatch(char c, int lvl, int toskip)
{
	// If the initial skip + this level's skip in between matches is
	// greater than the count of matching characters in the window,
	// then we have narrowed it down to just one choice.  The second
	// match would have to be past the end of the window.
	return skips(lvl) + toskip >= count(c);
}

static char *disamb(char c)
{
	int lvl = 0;
	int toskip = 0;
	while (!onlymatch(c, lvl, toskip)) {
		drawdisamb(c, lvl, toskip);
		char input = getch();
		int i = input - 'a';
		if (i < 0 || i >= 26)
			return NULL;
		toskip += i * (skips(lvl) + 1);
		lvl++;
	}
	return find(c, toskip);
}

static char *hunt(void)
{
	char c;
	if (gapsize() == bufsize)
		return buffer;
	draw();
	c = getch();
	return disamb(c);
}

static void drawlinelbls(int lvl, int off)
{
	erase();
	move(0, 0);
	winbounds();
	for (char *i = start; i != end; i++)
		pc(*i);
	int count = 0;
	int step = skips(lvl) + 1;
	step = step < 1 ? 1 : step;
	for (int line = off; line < LINES; line += step) {
		move(line, 0);
		ptarg(count++);
	}
	refresh();
}

static bool lineselected(int lvl, int off)
{
	return off + skips(lvl) > LINES;
}

static int getoffset(int lvl, int off)
{
	char c = getch();
	int i = c - 'a';
	if (i < 0 || i >= 26)
		return -1;
	int delta = (skips(lvl) + 1) * i;
	return off + delta;
}

static char *startofline(int off)
{
	char *result = start;
	while (off > 0) {
		if (result >= end)
			return NULL;
		if (*result == '\n')
			off--;
		result++;
	}
	return result;
}

static char *endofline(int off)
{
	char *nextstart = startofline(off + 1);
	return nextstart - 1;
}

static int linehunt(void)
{
	int lvl = 0;
	int off = 0;
	if (gapsize() == bufsize)
		return -1;
	while (!lineselected(lvl, off)) {
		drawlinelbls(lvl, off);
		off = getoffset(lvl, off);
		if (off < 0)
			return -1;
		lvl++;
	}
	return off;
}

static void rubout(char *t)
{
	int sz;
	sz = gap - (t + 1 - buffer);
	memmove(t, t + 1, sz);
	gap--;
}

static void delete(char *start, char *end)
{
	int n, tn;
	if (end != buffer + bufsize)
		end++;
	n = buffer + bufsize - end;
	tn = end - start;
	memmove(start, end, n);
	gap -= tn;
}

static void movecursor(char *t){
	if (!t) 
		return;
	// Figure out line number, number of tabs on the line,
	// along with how much space each tab is actually taking up
	// so we can figure out the offset in order to highlight the cursor
	int offset = 0;
	int linenumber = findcharcount(start, t, '\n');
	char* linestart = startofline(linenumber);
	if (linestart) {
		char* iter = linestart;
			while (iter != t) {
				if (*iter == '\t') {
					if (iter != linestart) {
						const char* const prev = iter - 1;
						if (*prev == '\t') {
							offset += TABSIZE;
							iter++;
							continue;
						}
					}
					int lineidx = iter - linestart;
					offset += (TABSIZE - (lineidx % TABSIZE));
				}
				else {
					offset++;
{'fraction_non_alphanumeric': 0.17843109738984003, 'fraction_numerical': 0.01452427729441482, 'mean_word_length': 2.9657762938230383, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2787177', 'n_tokens_mistral': 6618, 'n_tokens_neox': 6052, 'n_words': 1851}