#help_index "DolDoc/Editor"

public I64 EdCurU8(CDoc *doc)
{//Return cur U8. See EdRenumAsm for an example.
    Bool         unlock = DocLock(doc);
    CDocEntry   *doc_ce = doc->cur_entry;
    I64          res = -1;

    if (doc_ce->type_u8 == DOCT_TEXT && doc_ce->min_col <= doc->cur_col < doc_ce->max_col)
        res = doc_ce->tag[doc->cur_col];
    else if (doc_ce->type_u8 == DOCT_TAB)
        res = '\t';
    else if (doc_ce->type_u8 == DOCT_NEW_LINE || doc_ce->type_u8 == DOCT_SOFT_NEW_LINE)
        res = '\n';

    if (unlock)
        DocUnlock(doc);
    return res;
}

public U0 EdCursorLeft(CDoc *doc, I64 sc=I64_MIN)
{//Move cursor left. Might need a call to DocRecalc().
//See EdRenumAsm for an example.
    U8          *dst;
    Bool         unlock = DocLock(doc);
    CDocEntry   *doc_ce = doc->cur_entry, *original_ce = doc_ce, *doc_ne;
    I64          cc = doc->cur_col, y = doc_ce->y;

    if (sc != I64_MIN)
        sc = sc.u32[0];
    if (sc >= 0 && sc & SCF_CTRL)
    {
        while (doc_ce->last != doc && (doc_ce->last->y == y || doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP)))
            doc_ce = doc_ce->last;  //TODO: sel? recurse?
        cc = doc_ce->min_col;
    }
    else
    {
        if (cc > doc_ce->min_col)
        {
            if (IsEditableText(doc_ce) && cc < doc_ce->max_col)
            {
                dst = doc_ce->tag + cc;
                doc_ne = DocEntryNewTag(doc, doc_ce, dst);
                *dst = 0;
                doc_ce->max_col = cc;
                QueueInsert(doc_ne, doc_ce);
            }
            cc--;
            if (IsEditableText(doc_ce) && cc > doc_ce->min_col)
            {
                dst = doc_ce->tag + cc;
                doc_ne = DocEntryNewTag(doc, doc_ce, dst);
                *dst = 0;
                doc_ce->max_col = cc;
                QueueInsert(doc_ne, doc_ce);
                doc_ce = doc_ne;
                cc = doc_ce->min_col;
            }
            if (sc >= 0)
                BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
        }
        else
        {
            cc = doc_ce->min_col;
            while (doc_ce->last != doc &&
                  (doc_ce->last->type_u8 == DOCT_SOFT_NEW_LINE ||
                   doc_ce->last->type_u8 == DOCT_INDENT ||
                   doc_ce->last->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP)))
            {
                doc_ce = doc_ce->last;
                if (sc >= 0)
                    BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
            }
            if (doc_ce->last != doc)
            {
                doc_ce = doc_ce->last;
                if (doc_ce->max_col > doc_ce->min_col)
                {
                    cc = doc_ce->max_col - 1;
                    if (IsEditableText(doc_ce) && cc > doc_ce->min_col)
                    {
                        dst = doc_ce->tag + cc;
                        doc_ne = DocEntryNewTag(doc, doc_ce, dst);
                        *dst = 0;
                        doc_ce->max_col = cc;
                        QueueInsert(doc_ne, doc_ce);
                        doc_ce = doc_ne;
                        cc = doc_ce->min_col;
                    }
                }
                else
                    cc = doc_ce->max_col;
                if (sc >= 0)
                    BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
            }
        }
    }
    doc->cur_col   = cc;
    doc->cur_entry = doc_ce;
    if (doc_ce != original_ce)
        DocFormBwd(doc);
    if (unlock)
        DocUnlock(doc);
}

public U0 EdCursorRight(CDoc *doc, I64 sc=I64_MIN)
{//Move cursor right. Might need a call to DocRecalc().
//See EdRenumAsm for an example.
    Bool         unlock = DocLock(doc);
    U8          *dst;
    CDocEntry   *doc_ce = doc->cur_entry, *original_ce = doc_ce, *doc_ne;
    I64          cc = doc->cur_col, y = doc_ce->y, old_de_flags, old_color;

    if (sc != I64_MIN)
        sc = sc.u32[0];
    if (sc >= 0 && sc & SCF_CTRL)
    {
        while (doc_ce != doc && doc_ce->next->y == y &&
               doc_ce->next->type_u8 != DOCT_SOFT_NEW_LINE && doc_ce->next != doc &&
              (doc_ce->next->type_u8 != DOCT_NEW_LINE || !(doc->flags & DOCF_FORM)) ||
               doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP))
            doc_ce = doc_ce->next;
        if (doc_ce->max_col > doc_ce->min_col)
            cc = doc_ce->max_col - 1;
        else
            cc = doc_ce->min_col;
    }
    else
    {
        if (cc < doc_ce->max_col)
        {
            if (IsEditableText(doc_ce) && cc > doc_ce->min_col)
            {
                dst = doc_ce->tag + cc;
                doc_ne = DocEntryNewTag(doc, doc_ce, dst);
                *dst = 0;
                doc_ce->max_col = cc;
                QueueInsert(doc_ne, doc_ce);
                doc_ce = doc_ne;
                cc = doc_ce->min_col;
            }
            cc++;
            old_de_flags = doc_ce->de_flags;
            old_color = doc_ce->type;
            if (sc >= 0)
                BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
            if (IsEditableText(doc_ce) && cc < doc_ce->max_col)
            {
                dst = doc_ce->tag+cc;
                doc_ne = DocEntryNewTag(doc, doc_ce, dst);
                *dst = 0;
                doc_ne->type     = DOCT_TEXT | old_color & -0x100;
                doc_ne->de_flags = old_de_flags | doldoc.default_de_flags[DOCT_TEXT];
                doc_ce->max_col  = cc;
                QueueInsert(doc_ne, doc_ce);
                doc_ce = doc_ne;
                cc = doc_ce->min_col;
            }
            else if (cc >= doc_ce->max_col)
            {
                doc_ce = doc_ce->next;
                cc = doc_ce->min_col;
            }
        }
        else
        {
            if (doc_ce != doc)
            {
                if (cc <= doc_ce->min_col && sc >= 0)
                    BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
                doc_ce = doc_ce->next;
                while (doc_ce != doc && doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP))
                {
                    if (sc >= 0)
                        BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
                    doc_ce = doc_ce->next;
                }
                cc = doc_ce->min_col;
                if (doc_ce->type_u8 == DOCT_SOFT_NEW_LINE)
                {
                    if (sc >= 0)
                        BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
                    doc_ce = doc_ce->next;
                    cc = doc_ce->min_col;
                }
            }
        }
    }
    doc->cur_col   = cc;
    doc->cur_entry = doc_ce;
    if (doc_ce != original_ce)
        DocFormFwd(doc);
    if (unlock)
        DocUnlock(doc);
}

public U0 EdLineUp(CDoc *doc, I64 sc=I64_MIN)
{//Move cursor up. Might need a call to DocRecalc().
//See EdRenumAsm for an example.
    Bool         unlock = DocLock(doc);
    U8          *dst;
    I64          y, x;
    CDocEntry   *doc_ce = doc->cur_entry, *doc_ne;

    if (sc != I64_MIN)
        sc = sc.u32[0];
    if (doc_ce->type_u8 == DOCT_HEX_ED)
    {
        doc->cur_col = doc->cur_col - doc_ce->hex_ed_width * 3;
        if (doc->cur_col >= 0)
        {
            if (unlock)
                DocUnlock(doc);
            return;
        }
        else
            doc->cur_col = 0;
    }
    x = doc->x;
    y = doc->y;
    if (IsEditableText(doc_ce))
    {
        if (doc_ce->min_col < doc->cur_col < doc_ce->max_col - 1)
        {
            dst = doc_ce->tag + doc->cur_col;
            doc_ne = DocEntryNewTag(doc, doc_ce, dst);
            *dst = 0;
            doc_ne->x       = doc_ce->x + doc->cur_col;
            doc_ce->max_col = doc->cur_col;
            QueueInsert(doc_ne, doc_ce);
        }
        else if (doc->cur_col == doc_ce->min_col && doc_ce->last != doc)
            doc_ce = doc_ce->last;
    }
    else if (doc_ce->last != doc)
        doc_ce = doc_ce->last;
    if (sc >= 0)
        BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
    doc->cur_entry = doc_ce;
    DocFormBwd(doc);
    doc_ce = doc->cur_entry;
    while (doc_ce->last != doc && (doc_ce->y >= y || doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP)))
    {
        doc_ce = doc_ce->last;
        if (sc >= 0)
            BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
    }
    y = doc_ce->y;
    doc->y = y;
    while (doc_ce != doc && (doc_ce->y >= y && doc_ce->x >= x || doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP)))
    {
        if (sc >= 0)
            BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
        doc_ce=  doc_ce->last;
    }

    if (doc_ce == doc || doc_ce->y < y)
        doc_ce = doc_ce->next;
    else
    {
        if (!IsEditableText(doc_ce))
        {
            if (sc >= 0)
                BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
        }
        else
        {
            if (doc_ce->next->x == x)
            {
                doc_ce = doc_ce->next;
                if (doc->flags & DOCF_FORM)
                    while (doc_ce->next->x == x &&
                          (!Bt(doldoc.type_flags_form, doc_ce->type_u8) &&
                           !(doc_ce->de_flags & DOCEF_LINK) ||
                           doc_ce->de_flags & DOCEF_SKIP_IN_FORM))
                        doc_ce = doc_ce->next;
            }
        }
    }
    if (doc_ce->de_flags & DOCEF_TAG)
    {
        doc->cur_col = x-doc_ce->x;
        if (IsEditableText(doc_ce))
        {
            if (doc->cur_col > doc_ce->max_col)
                doc->cur_col = doc_ce->max_col;
        }
        else if (doc->cur_col >= doc_ce->max_col)
            doc->cur_col = doc_ce->max_col - 1;
        if (doc->cur_col < doc_ce->min_col)
            doc->cur_col = doc_ce->min_col;
    }
    else
    {
        if (doc_ce->type_u8 == DOCT_HEX_ED)
        {
            doc->cur_col = RoundI64((doc_ce->len - 1) * 3, doc_ce->hex_ed_width * 3);
            if (doc->cur_col < 0)
                doc->cur_col = 0;
        }
        else
            doc->cur_col = doc_ce->min_col;
    }
    if (IsEditableText(doc_ce) && doc_ce->x < x)
    {
        if (doc->cur_col < doc_ce->max_col - 1)
        {
            dst = doc_ce->tag + doc->cur_col;
            doc_ne = DocEntryNewTag(doc, doc_ce, dst);
            *dst = 0;
            if (sc >= 0)
            {
                if (sc & SCF_SHIFT)
                    doc_ne->type = doc_ce->type | DOCET_SEL;
                else
                    doc_ne->type = doc_ce->type & ~DOCET_SEL;
            }
            doc_ne->x       = doc_ce->x + doc->cur_col;
            doc_ce->max_col = doc->cur_col;
            QueueInsert(doc_ne, doc_ce);
            doc_ce = doc_ne;
            doc->cur_col = doc_ce->min_col;
        }
    }
    doc->cur_entry = doc_ce;
    DocFormFwd(doc);
    doc->x = doc->cur_entry->x + doc->cur_col;
    if (unlock)
        DocUnlock(doc);
}

public U0 EdLineDown(CDoc *doc, I64 sc=I64_MIN)
{//Move cursor down. Might need a call to DocRecalc().
//See EdRenumAsm for an example.
    Bool        unlock = DocLock(doc);
    U8          *dst;
    I64          y, x, old_de_flags = 0, old_color;
    CDocEntry   *doc_ce = doc->cur_entry, *doc_ne, *doc_ce2;

    if (sc != I64_MIN)
        sc = sc.u32[0];
    if (doc_ce->type_u8 == DOCT_HEX_ED)
    {
        doc->cur_col = doc->cur_col + doc_ce->hex_ed_width * 3;
        if (doc->cur_col >= doc_ce->len * 3)
        {
            doc->cur_entry  = doc_ce = doc_ce->next;
            doc->cur_col    = doc_ce->min_col;
            doc->x          = doc_ce->x + doc->cur_col;
            doc->y          = doc_ce->y;
        }
        if (unlock)
            DocUnlock(doc);
        return;
    }
    x = doc->x;
    y = doc->y;
    if (IsEditableText(doc_ce))
    {
        if (doc->cur_col > doc_ce->min_col && doc->cur_col < doc_ce->max_col - 1)
        {
            dst = doc_ce->tag + doc->cur_col;
            doc_ne = DocEntryNewTag(doc, doc_ce, dst);
            *dst = 0;
            if (sc >= 0)
            {
                if (sc & SCF_SHIFT)
                    doc_ne->type = doc_ce->type | DOCET_SEL;
                else
                    doc_ne->type = doc_ce->type & ~DOCET_SEL;
            }
            doc_ne->x       = doc_ce->x + doc->cur_col;
            doc_ce->max_col = doc->cur_col;
            QueueInsert(doc_ne, doc_ce);
            doc_ce = doc_ne;
            doc->cur_col = doc_ce->min_col;
        }
    }
    doc_ce2 = doc_ce;
    while (doc_ce != doc && (doc_ce->y <= y || doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP)))
        doc_ce = doc_ce->next;
    y = doc_ce->y;
    doc->y = y;
    while (doc_ce != doc && (doc_ce->y <= y && doc_ce->x <= x || doc_ce->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP)))
    {
        old_de_flags = doc_ce->de_flags;
        old_color = doc_ce->type;
        doc_ce = doc_ce->next;
    }
    if (doc_ce->last != doc && (doc_ce->x > x && doc_ce->last->y >= y || doc_ce->y > y))
    {
        doc_ce = doc_ce->last;
        doc->cur_entry = doc_ce;
        if (!((doc_ce->type_u8 == DOCT_NEW_LINE ||
               doc_ce->type_u8 == DOCT_SOFT_NEW_LINE ||
               doc_ce->type_u8 == DOCT_INDENT) &&
              (doc_ce->last->type_u8 == DOCT_NEW_LINE ||
               doc_ce->last->type_u8 == DOCT_SOFT_NEW_LINE ||
               doc_ce->last->type_u8 == DOCT_INDENT)))
            DocFormBwd(doc);
        doc_ce = doc->cur_entry;
    }
    while (doc_ce2 != doc && (doc_ce2 != doc_ce || IsEditableText(doc_ce)))
    {
        if ((doc_ce2->y < y || doc_ce2->x < x ||
             doc_ce2->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP) ||
             doc_ce2->x == x && !doc_ce2->max_col &&
             Bt(doldoc.type_flags_nontag_invis, doc_ce2->type_u8))
             && sc >= 0)
            BEqual(&doc_ce2->type, DOCEt_SEL, sc & SCF_SHIFT);
        if (doc_ce2 == doc_ce)
            break;
        doc_ce2 = doc_ce2->next;
    }
    if (doc_ce->de_flags & DOCEF_TAG)
    {
        doc->cur_col = x - doc_ce->x;
        if (IsEditableText(doc_ce))
        {
            if (doc->cur_col > doc_ce->max_col)
                doc->cur_col = doc_ce->max_col;
        }
        else if (doc->cur_col >= doc_ce->max_col)
            doc->cur_col = doc_ce->max_col - 1;
        if (doc->cur_col < doc_ce->min_col)
            doc->cur_col = doc_ce->min_col;
    }
    else
        doc->cur_col = doc_ce->min_col;
    if (IsEditableText(doc_ce) && doc_ce->min_col < doc->cur_col < doc_ce->max_col - 1)
    {
        dst = doc_ce->tag + doc->cur_col;
        doc_ne = DocEntryNewTag(doc, doc_ce, dst);
        *dst = 0;
        doc_ne->type        = DOCT_TEXT | old_color & -0x100;
        doc_ne->de_flags    = old_de_flags | doldoc.default_de_flags[DOCT_TEXT];
        doc_ce->max_col     = doc->cur_col;
        doc_ne->x           = doc_ce->x + doc->cur_col;
        QueueInsert(doc_ne, doc_ce);
        doc_ce = doc_ne;
        doc->cur_col = doc_ce->min_col;
    }
    doc->cur_entry = doc_ce;
    DocFormFwd(doc);
    if (!(doc->flags & DOCF_FORM))
        while (doc_ce != doc && doc_ce != doc->cur_entry)
        {
            if (sc >= 0)
                BEqual(&doc_ce->type, DOCEt_SEL, sc & SCF_SHIFT);
            doc_ce = doc_ce->next;
        }
    doc->x = doc->cur_entry->x + doc->cur_col;
    if (unlock)
        DocUnlock(doc);
}

U0 EdCharDel(CDoc *doc)
{
    Bool         unlock = DocLock(doc);
    CDocEntry   *doc_ce = doc->cur_entry;

    if (doc_ce == doc)
    {
        if (unlock)
            DocUnlock(doc);
        return;
    }
    if (doc_ce->max_col != 0 && (IsEditableText(doc_ce) || doc_ce->type_u8 == DOCT_DATA))
    {
        if (doc_ce->type_u8 == DOCT_DATA && doc_ce->de_flags & DOCEF_HAS_TERMINATOR && doc->cur_col == doc_ce->max_col - 1)
        {
            if (unlock)
                DocUnlock(doc);
            return;
        }
        if (doc->cur_col < doc_ce->max_col)
            StrCopy(doc_ce->tag + doc->cur_col, doc_ce->tag + doc->cur_col + 1);
        if (doc->cur_col >= doc_ce->max_col - 1)
        {
            doc->cur_entry  = doc_ce->next;
            doc->cur_col    = doc->cur_entry->min_col;
        }
        DocRemSoftNewLines(doc, doc->cur_entry);
        if (unlock)
            DocUnlock(doc);
        return;
    }
    doc->cur_entry  = doc_ce->next;
    doc->cur_col    = doc->cur_entry->min_col;
    if (!(doc_ce->de_flags & DOCEF_FILTER_SKIP))
        DocEntryDel(doc, doc_ce);
    DocRemSoftNewLines(doc, doc->cur_entry);
    if (unlock)
        DocUnlock(doc);
}

U0 CheckDollarBufSize(CDoc *doc)
{
    U8 *b;

    if (doc->dollar_buf_ptr >= doc->dollar_buf_size - 2)
    {
        doc->dollar_buf_size <<= 1;
        b = MAlloc(doc->dollar_buf_size, doc->mem_task);
        MemCopy(b, doc->dollar_buf, doc->dollar_buf_ptr);
        Free(doc->dollar_buf);
        doc->dollar_buf = b;
    }
}

U0 EdCharIns(I64 ch, I64 sc, CDoc *doc)
{
    Bool         unlock = DocLock(doc);
    U8          *st, *src, *dst;
    CDocEntry   *doc_ce = doc->cur_entry, *doc_ne;
    I64          i, j, m, y = doc_ce->y;

    if (doc->flags & DOCF_IN_DOLLAR)
    {
        if (!Bt(char_bmp_printable, ch))
            goto ic_done;
        CheckDollarBufSize(doc);
        doc->dollar_buf[doc->dollar_buf_ptr++] = ch;
        if (ch == '$')
        {
            if (doc->dollar_buf_ptr == 2)
            {
                doc->flags          &= ~DOCF_IN_DOLLAR;
                doc->dollar_buf_ptr  = 0;
                goto ic_cont;
            }
            else
            {
                doc->dollar_buf[doc->dollar_buf_ptr] = 0;
                doc->flags &= ~DOCF_IN_DOLLAR;
                DocPrint(doc, "%s", doc->dollar_buf);
                doc->dollar_buf_ptr = 0;
                goto ic_done;
            }
        }
        else
            goto ic_done;
    }
    if (ch == '$' && !(doc->flags & (DOCF_PLAIN_TEXT | DOCF_PLAIN_TEXT_TABS)))
    {
        doc->flags          |= DOCF_IN_DOLLAR;
        doc->dollar_buf_ptr  = 0;
        doc->dollar_buf[doc->dollar_buf_ptr++] = ch;
        goto ic_done;
    }
    if (ch == '\r') goto ic_done;

        ic_cont:
    if ((ch == CH_SPACE || ch == '\n') &&
        !(sc & (SCF_CTRL | SCF_SHIFT)) &&
        doc_ce->de_flags &
        (DOCEF_LINK | DOCEF_TREE | DOCEF_LIST | DOCEF_CHECK_COLLAPSABLE |
        DOCEF_LEFT_MACRO | DOCEF_LEFT_EXP | DOCEF_LEFT_CB | DOCEF_LEFT_IN_STR |
        DOCEF_RIGHT_MACRO | DOCEF_RIGHT_EXP | DOCEF_RIGHT_CB | DOCEF_RIGHT_IN_STR))
    {
        doc->cmd_U8 = ch;
        DocEntryRun(doc, doc_ce, FALSE);
        DocLock(doc);
        goto ic_done;
    }
    if (doc_ce->type_u8 == DOCT_HEX_ED)
    {
        if (doc_ce->de_flags & DOCEF_DEREF_DATA && !(doc_ce->de_flags & DOCEF_REMALLOC_DATA))
            st = doc_ce->data;
        else
            st = &doc_ce->data;
        i = doc->cur_col;
        j = i % (doc_ce->hex_ed_width * 3);
        m = i / (doc_ce->hex_ed_width * 3) * doc_ce->hex_ed_width;
        if (j >= doc_ce->hex_ed_width << 1)
            st[j - doc_ce->hex_ed_width << 1 + m] = ch;
        else
        {
            ch = ToUpper(ch) - '0';
            if (ch > 9)
            {
                ch += '0' - 'A' + 10;
                if (!(10 <= ch <= 15))
                    goto ic_done;
            }
            m = j >> 1 + m;
            if (j & 1)
                st[m] = st[m] & 0xF0 | ch;
            else
                st[m] = st[m] & 0xF | ch << 4;
        }
        doc->cur_col++;
        goto ic_done;
    }
    if (doc->flags & DOCF_OVERSTRIKE)
    {
        if (Bt(char_bmp_displayable, ch))
        {
ic_overstrike:
            if (IsEditableText(doc_ce))
            {
                if (doc->cur_col < doc_ce->max_col)
                {
                    if (doc_ce->tag[doc->cur_col])
                    {
                        doc_ce->tag[doc->cur_col++] = ch;
                        goto ic_done;
                    }
                }
                else
                {
                    doc_ce = doc_ce->next;
                    doc->cur_entry  = doc_ce;
                    doc->cur_col    = doc_ce->min_col;
                    goto ic_overstrike;
                }
            }
            else if (doc_ce->type_u8 == DOCT_DATA)
            {
                if (doc_ce->de_flags & DOCEF_HAS_TERMINATOR)
                {
                    if (doc_ce->tag[doc->cur_col] && doc->cur_col < doc_ce->min_col + doc_ce->len)
                    {
                        doc_ce->tag[doc->cur_col++] = ch;
                        if (!doc_ce->tag[doc->cur_col])
                        {
                            doc_ce->tag[doc->cur_col]       = '_';
                            doc_ce->tag[doc->cur_col + 1]   = 0;
                        }
                    }
                    else if (doc_ce->de_flags & DOCEF_REMALLOC_DATA)
                        goto ic_not_overstrike;
                }
                else if (doc_ce->tag[doc->cur_col])
                    doc_ce->tag[doc->cur_col++] = ch;
                goto ic_done;
            }
            doc_ne = DocEntryNewTag(doc, doc_ce, &ch);
            doc_ne->type        = DOCT_TEXT | doc->settings_head.default_text_attr << 8;
            doc_ne->de_flags    = doldoc.default_de_flags[DOCT_TEXT];
            QueueInsert(doc_ne, doc_ce->last);
        }
        else if (ch == '\n')
        {
            while (doc->cur_entry->next != doc && doc->cur_entry->y == y)
                doc->cur_entry = doc->cur_entry->next;
            doc->cur_col = doc->cur_entry->min_col;
        }
        else if (ch == '\t')
        {
            if (doc->flags & DOCF_FORM)
                goto ic_form_tab;
        }
        goto ic_done;
    }
ic_not_overstrike:
    if (ch == '\n')
    {
        if (sc & SCF_CTRL && !(sc & SCF_SHIFT))
        {
            doc_ne = DocEntryNewBase(doc, DOCT_PAGE_BREAK | doc->settings_head.default_text_attr << 8);
        }
        else
        {
            doc_ne = DocEntryNewBase(doc, DOCT_NEW_LINE | doc->settings_head.default_text_attr << 8);
        }
        DocInsEntry(doc, doc_ne);
    }
    else if (ch == '\t')
    {
        if (doc->flags & DOCF_FORM &&
            (Bt(doldoc.type_flags_form, doc->cur_entry->type_u8) ||
            doc->cur_entry->de_flags & DOCEF_LINK) &&
            !(doc->cur_entry->de_flags & DOCEF_SKIP_IN_FORM))
        {
ic_form_tab:
            doc->cur_entry  = doc->cur_entry->next;
            doc->cur_col    = doc->cur_entry->min_col;
            DocFormFwd(doc);
            goto ic_done;
        }
        else
        {
            doc_ne = DocEntryNewBase(doc, DOCT_TAB | doc->settings_head.default_text_attr << 8);
            DocInsEntry(doc, doc_ne);
        }
    }
    else
    {
        if (Bt(char_bmp_displayable, ch))
        {
            if (doc_ce->type_u8 == DOCT_DATA)
            {
                while (TRUE)
                {
                    i = doc_ce->len + doc_ce->min_col;
                    if (doc_ce->de_flags & DOCEF_HAS_TERMINATOR)
                        i++;
                    if (doc_ce->max_col < i)
                    {
                        st = doc_ce->tag;
                        doc_ce->max_col++;
                        for (i = doc_ce->max_col; i > doc->cur_col; i--)
                            st[i] = st[i - 1];
                        st[doc->cur_col++] = ch;
                        break;
                    }
                    else if (doc_ce->de_flags & DOCEF_REMALLOC_DATA)
                    {
                        st = MAlloc(doc_ce->max_col + 8, doc->mem_task);
                        MemCopy(st, doc_ce->tag, doc_ce->max_col + 1);
                        Free(doc_ce->tag);
                        doc_ce->tag  = st;
                        doc_ce->len  = MSize(st) - doc_ce->min_col - 2; //See DataTagWidth
                        Free(doc_ce->data);
                        doc_ce->data = MAlloc(doc_ce->len + 2, doc->mem_task);
                    }
                    else
                        break;
                }
            }
            else if (IsEditableText(doc_ce))
            {
                dst = st = MAlloc(doc_ce->max_col + 2, doc->mem_task);
                src = doc_ce->tag;
                i = doc->cur_col;
                while (i-- > 0)
                    *dst++ = *src++;
                *dst++ = ch;
                while (*dst++ = *src++);
                Free(doc_ce->tag);
                doc_ce->tag = st;
                doc_ce->max_col++;
                doc->cur_col++;
            }
            else
            {
                doc_ne = DocEntryNewTag(doc, doc_ce, &ch);
                doc_ne->type     = DOCT_TEXT | doc->settings_head.default_text_attr << 8;
                doc_ne->de_flags = doldoc.default_de_flags[DOCT_TEXT];
                doc_ne->x        = doc_ce->x + 1;
                QueueInsert(doc_ne, doc_ce->last);
            }
        }
    }
ic_done:
    DocRemSoftNewLines(doc, doc->cur_entry);
    if (doc->cur_entry->de_flags & DOCEF_UPDATE_DATA &&
            (doc->cur_entry->type_u8 == DOCT_DATA ||
            doc->cur_entry->type_u8 == DOCT_CHECK_BOX))
        DocDataScan(doc, doc->cur_entry);
    if (unlock)
        DocUnlock(doc);
}

U0 EdLineDel(CDoc *doc)
{
    CDocEntry   *doc_ce = doc->cur_entry, *doc_ce2;
    I64          y;

    y = doc->y;
    while (doc_ce != doc && doc_ce->y == y)
        doc_ce = doc_ce->next;
    doc->cur_entry  = doc_ce;
    doc->cur_col    = doc_ce->min_col;
    doc_ce = doc_ce->last;
    while (doc_ce != doc && doc_ce->y == y)
    {
        doc_ce2 = doc_ce->last;
        if (!(doc_ce->de_flags & DOCEF_FILTER_SKIP))
            DocEntryDel(doc, doc_ce);
        doc_ce = doc_ce2;
    }
}