class CLine
{
	CLine	*next, *last;
	U8		*line;
};

U0 EdLiteUpdate(CLine *head, CLine *cur_line, I64 cur_col, I64 line_start_col)
{
	I64		 ch, i, j, k, k2, cursor_col, cursor_row = -1;
	U8		*st;
	CLine	*tmpl = cur_line;
	Bool	 done_eof = FALSE;

	text.raw_col = 0;
	for (i = 0; i < text.rows / 2; i++)
		if (tmpl->last != head)
			tmpl = tmpl->last;
	for (i = 0; i < text.rows; i++)
	{
		if (cursor_row < 0 && tmpl == cur_line)
		{
			k = 0;
			for (j = 0; j < cur_col; j++)
				if (tmpl->line[j] == '\t')
					k = (k + 4) & ~3;
				else
					k++;
			cursor_col = k;
			cursor_row = i;
		}
		if (tmpl != head)
		{
			st = tmpl->line;
			k = 0;
			j= 0 ;
			while (ch = *st++)
			{
				if (ch == '\t')
					k2 = (k + 4) & ~3;
				else
					k2 = k + 1;
				if (line_start_col <= k < line_start_col + text.cols)
				{
					'' ch;
					j = k2 - line_start_col;
				}
				k = k2;
			}
			if (j < text.cols)
				'\n';
			tmpl = tmpl->next;
		}
		else
		{
			if (!done_eof)
			{
				'<EOF>';
				done_eof = TRUE;
			}
			'\n';
		}
	}
	text.raw_col = text.cols * cursor_row + cursor_col - line_start_col;
	RawPutChar(0x7F);
}

Bool EdLite(U8 *filename, I64 num=1, I64 edf_dof_flags=0)
{//Light weight text editor for debugging.
	U8		*src, *src2, *src3, *dst, *buf, *bin_data = NULL;
	I64		 i, count = 0, ch, sc, size, bin_size = 0, line_start_col = 0, cur_col = 0, old_raw_flags = text.raw_flags;
	CLine	 head, *tmpl, *tmpl1, *cur_line;
	Bool	 res		= FALSE,
			 old_raw	= Raw(ON),
			 old_debug	= DebugMode(ON),
			 old_single	= SingleUser(ON);

	if (!filename)
		filename = blkdev.tmp_filename;
	buf = FileRead(filename, &size);

	PUSHFD
	CLI
	text.raw_flags = text.raw_flags & ~RAWF_SCROLL | RAWF_SHOW_DOLLAR;
	kbd.scan_code = 0;
	QueueInit(&head);
	head.line = StrNew("");

	if (buf)
	{
		src = buf;
		while (*src)
		{
			src2 = src;
			while ((ch = *src++) && ch != '\r' && ch != '\n');
			src--;
			*src++ = 0;
			if (!ch)
				src--;
			while (ch == '\r' && *src == '\n' || *src == CH_CURSOR)
				src++;
			dst = src3 = src2;
			while (ch = *src3++)
				if (ch != '\n' && ch != CH_CURSOR)
					*dst++ = ch;
			*dst = 0;

			tmpl = MAlloc(sizeof(CLine));
			tmpl->line = StrNew(src2);
			QueueInsert(tmpl, head.last);
			count++;
		}

		if (src + 1 - buf<size)
		{
			bin_data = MAlloc(bin_size = size - (src - buf));
			MemCopy(bin_data, src, bin_size);
		}
		Free(buf);
		res = TRUE;
	}

	cur_line = head.next;
	if (--num < 0)
		res = FALSE;
	else
	{
		if (num <= count)
			while (num--)
				cur_line = cur_line->next;
		else
		{
			cur_line = &head;
			res = FALSE;
		}
	}
	do
	{
		if (cur_line == &head)
			cur_col = 0;
		while (cur_col - line_start_col < 0)
			line_start_col -= 8;
		while (cur_col - line_start_col >= text.cols)
			line_start_col += 8;
		EdLiteUpdate(&head, cur_line, cur_col, line_start_col);
		switch (ch = KeyGet(&sc, FALSE, TRUE))
		{
			case 0:
				switch (sc.u8[0])
				{
					case SC_CURSOR_UP:
						if (cur_line->last != &head)
							cur_line = cur_line->last;
						if (cur_col > StrLen(cur_line->line))
							cur_col = StrLen(cur_line->line);
						break;

					case SC_CURSOR_DOWN:
						if (cur_line != &head)
							cur_line = cur_line->next;
						if (cur_col > StrLen(cur_line->line))
							cur_col = StrLen(cur_line->line);
						break;

					case SC_CURSOR_RIGHT:
						cur_col++;
						if (cur_col > StrLen(cur_line->line))
						{
							tmpl = cur_line->next;
							if (tmpl != &head)
							{
								cur_col = 0;
								cur_line = tmpl;
							}
							else
								cur_col = StrLen(cur_line->line);
						}
						break;

					case SC_CURSOR_LEFT:
						if (cur_col)
							cur_col--;
						else
						{
							tmpl = cur_line->last;
							if (tmpl != &head)
							{
								cur_line = tmpl;
								cur_col = StrLen(tmpl->line);
							}
						}
						break;

					case SC_PAGE_UP:
						for (i = 1; i < text.rows; i++)
						{
							if (cur_line->last != &head)
								cur_line = cur_line->last;
							if (cur_col > StrLen(cur_line->line))
								cur_col = StrLen(cur_line->line);
						}
						break;

					case SC_PAGE_DOWN:
						for (i = 1; i < text.rows; i++)
						{
							if (cur_line != &head)
								cur_line = cur_line->next;
							if (cur_col > StrLen(cur_line->line))
								cur_col = StrLen(cur_line->line);
						}
						break;

					case SC_DELETE:
						if (cur_col == StrLen(cur_line->line))
						{
							tmpl = cur_line->next;
							if (cur_line != &head && tmpl != &head) {
								src = MStrPrint("%s%s", cur_line->line, tmpl->line);
								Free(cur_line->line);
								Free(tmpl->line);
								cur_line->line = src;
								QueueRemove(tmpl);
								Free(tmpl);
							}
						}
						else
							StrCopy(cur_line->line + cur_col, cur_line->line + cur_col + 1);
						break;
				}
				break;

			case '\n':
			case '\r':
				tmpl = MAlloc(sizeof(CLine));
				tmpl->line = StrNew(cur_line->line + cur_col);
				cur_line->line[cur_col] = 0;
				QueueInsert(tmpl, cur_line);
				cur_line = tmpl;
				cur_col = 0;
				break;

			case CH_BACKSPACE:
				if (cur_col) {
					StrCopy(cur_line->line + cur_col - 1, cur_line->line + cur_col);
					cur_col--;
				}
				else if (cur_line!=&head && cur_line->last!=&head)
				{
					tmpl = cur_line->last;
					src = MStrPrint("%s%s", tmpl->line, cur_line->line);
					cur_col = StrLen(tmpl->line);
					Free(cur_line->line);
					Free(tmpl->line);
					tmpl->line = src;
					QueueRemove(cur_line);
					Free(cur_line);
					cur_line = tmpl;
				}
				break;

			case CH_CTRLY:
				if (cur_line != &head)
				{
					tmpl = cur_line;
					cur_line = cur_line->next;
					QueueRemove(tmpl);
					Free(tmpl->line);
					Free(tmpl);
					cur_col = 0;
				}
				break;

			default:
				if (Bt(char_bmp_printable, ch))
				{
					if (cur_line == &head) {
						cur_line = MAlloc(sizeof(CLine));
						cur_line->line = StrNew("");
						QueueInsert(cur_line, head.last);
					}
					src = MAlloc(StrLen(cur_line->line) + 2);
					MemCopy(src, cur_line->line, cur_col);
					src[cur_col] = ch;
					if (cur_col < StrLen(cur_line->line))
						StrCopy(src + cur_col + 1, cur_line->line + cur_col);
					else
						src[cur_col + 1] = 0;
					Free(cur_line->line);
					cur_line->line = src;
					cur_col++;
				}
		}
	}
	while (ch != CH_SHIFT_ESC && ch != CH_ESC);

	if (ch != CH_ESC)
	{
		if (edf_dof_flags & EDF_WAS_WRITE)
			res = FALSE;
	}
	else
	{
		size = bin_size;

		tmpl = head.next;
		while (tmpl != &head)
		{
			size += StrLen(tmpl->line) + 1;
			tmpl = tmpl->next;
		}

		buf = dst = MAlloc(size);
		tmpl = head.next;
		while (tmpl != &head)
		{
			i = StrLen(tmpl->line);
			MemCopy(dst, tmpl->line, i);
			dst += i;
			*dst++ = '\n';
			tmpl = tmpl->next;
		}
		if (bin_data)
			MemCopy(dst, bin_data, bin_size);
		FileWrite(filename, buf, size);
		Free(buf);

		if (edf_dof_flags & EDF_WAS_WRITE)
			res = TRUE;
	}

	tmpl = head.next;
	while (tmpl != &head)
	{
		tmpl1 = tmpl->next;
		QueueRemove(tmpl);
		Free(tmpl->line);
		Free(tmpl);
		tmpl = tmpl1;
	}
	Free(head.line);
	Free(bin_data);
	Raw(old_raw);
	DebugMode(old_debug);
	SingleUser(old_single);
	text.raw_flags = text.raw_flags & ~RAWF_SHOW_DOLLAR | old_raw_flags & RAWF_SHOW_DOLLAR;
	POPFD

	return res;
}

U0 ToFileLine(U8 *_fl_file_line, U8 **_filename, I64 *_linenum)
{//"FI:D:/Dir/File.CC,123" to "D:/Dir/File.CC" and 123.
	U8 *st, *fl_file_line = StrNew(_fl_file_line);
	I64 linenum;

	StrFirstRemove(fl_file_line, ":");
	st = StrNew(fl_file_line);
	StrLastRemove(fl_file_line, ",", st);
	linenum = Str2I64(st);
	Free(st);
	*_filename = fl_file_line;
	*_linenum = linenum;
}

Bool EdLiteFileLine(U8 *fl_file_line, I64 edf_dof_flags=0)
{
	Bool res;
	U8  *filename;
	I64  linenum;

	ToFileLine(fl_file_line, &filename, &linenum);
	res = EdLite(filename, linenum, edf_dof_flags);
	Free(filename);

	return res;
}

U0 FixSet(U8 *filename, I64 line)
{//Compiler calls this to set file line for Fix
	U8 *st = MStrPrint("FL:%s,%d", filename, line);

	while (LBts(&sys_semas[SEMA_FIX], 0))
		Yield;
	Free(debug.fix_file_line);
	debug.fix_file_line = ZStrNew(st);
	LBtr(&sys_semas[SEMA_FIX], 0);
}

Bool Fix(I64 edf_dof_flags=0)
{//Jump to last error src code to fix it.
	U8  *st;
	Bool res = FALSE;

	while (LBts(&sys_semas[SEMA_FIX], 0))
		Yield;
	st = StrNew(debug.fix_file_line);
	LBtr(&sys_semas[SEMA_FIX], 0);

	if (st)
	{
		if (IsRaw)
			res = EdLiteFileLine(st, edf_dof_flags);
		else
			res = Ed(st, edf_dof_flags);
	}
	Free(st);

	return res;
}
