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 + 8) & ~7;
                                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 + 8) & ~7;
                                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;
}