#help_index "DolDoc"

I64 ParseDocFlagSingle(CCompCtrl *cc, I64 *_de_flags, U32 *_type, Bool turn_on)
{
        I64                              res = -1;
        CHashGeneric    *tmph;

        if (cc->token == TK_IDENT && (tmph = HashFind(cc->cur_str, doldoc.hash, DHT_DOC_FLAG)))
        {
                res = tmph->user_data0;
                if (res < 64)
                {
                        BEqual(_de_flags, res, turn_on);
                        switch (res)
                        {
                                case DOCEf_BLINK:
                                case DOCEf_INVERT:
                                case DOCEf_UNDERLINE:
                                case DOCEf_SEL:
                                        BEqual(_type, res, turn_on);
                                        break;
                        }
                }
                Lex(cc);                //skip flag
        }

        return res;
}

I64 ParseDocFlags(CCompCtrl *cc, I64 *_de_flags, U32 *_type)
{
        I64  res = -1;
        Bool turn_on;

        while (TRUE)
        {
                if (cc->token == '+')
                        turn_on = TRUE;
                else if (cc->token == '-')
                        turn_on = FALSE;
                else
                        break;
                Lex(cc);
                res = ParseDocFlagSingle(cc, _de_flags, _type, turn_on);
        }

        return res;
}

U8 *Doc2PlainText(CDoc *doc, CDocEntry *doc_e)
{//TODO: break strs
        I64 i, j, attr = doc_e->attr, t1, f1, de_flags, type;
        U8 *buf, *buf2;

        if (doc_e->type_u8 == DOCT_FOREGROUND && doc->flags & DOCF_COLOR_NAMES && 0 <= attr < COLORS_NUM)
        {
                buf = StrNew(DefineSub(attr, "ST_COLORS"));
                attr = DOC_DEFAULT;
        }
        else
                buf = StrNew(DefineSub(doc_e->type_u8, "ST_DOC_CMDS"));
        if (doc_e->type_u8 != DOCT_ERROR)
        {
                f1 = doldoc.default_de_flags[doc_e->type_u8];
                t1 = doc_e->type_u8 | doldoc.default_type_flags[doc_e->type_u8];

                de_flags = doc_e->de_flags & ~(DOCG_BL_IV_UL | DOCEF_SEL | DOCEF_HIGHLIGHT |
                                                                           DOCEF_WORD_WRAP | DOCEF_SKIP | DOCEF_FILTER_SKIP);

                for (i = 0; i < DOCEf_FLAGS_NUM;i++)
                        if (Bt(&f1, i) != Bt(&de_flags, i))
                {
                                if (Bt(&de_flags, i))
                                {
                                        if (!(1 << i & DOCEG_HAS_ARG))
                                        {
                                                buf2 =MStrPrint("%s+%Z", buf, i, "ST_DOC_FLAGS");
                                                Free(buf);
                                                buf = buf2;
                                        }
                                }
                                else
                                {
                                        buf2 = MStrPrint("%s-%Z", buf, i, "ST_DOC_FLAGS");
                                        Free(buf);
                                        buf = buf2;
                                }
                        }
                type = doc_e->type & ~DOCET_SEL;
                for (i = DOCEt_BLINK; i <= DOCEt_UNDERLINE; i++)
                        if (Bt(&t1, i) != Bt(&type, i))
                        {
                                if (Bt(&type, i))
                                        buf2 = MStrPrint("%s+%Z", buf, i, "ST_DOC_FLAGS");
                                else
                                        buf2 = MStrPrint("%s-%Z", buf, i, "ST_DOC_FLAGS");
                                Free(buf);
                                buf = buf2;
                        }
                buf2 = MStrPrint("%s,", buf);
                Free(buf);
                buf = buf2;
                switch [doc_e->type_u8]
                {
                        case DOCT_HEX_ED:
                                buf2 = MStrPrint("%s%d,", buf, doc_e->len);
                                Free(buf);
                                buf  =buf2;
                                buf2 = MStrPrint("%s%d,", buf, doc_e->hex_ed_width);
                                Free(buf);
                                buf = buf2;
                                break;

                        case DOCT_FOREGROUND:
                        case DOCT_BACKGROUND:
                        case DOCT_DEFAULT_FOREGROUND:
                        case DOCT_DEFAULT_BACKGROUND:
                                if (doc->flags & DOCF_COLOR_NAMES && 0 <= attr < COLORS_NUM)
                                {
                                        buf2 = MStrPrint("%s%Z,", buf, doc_e->attr, "ST_COLORS");
                                        Free(buf);
                                        buf = buf2;
                                        break;
                                }
                        case DOCT_PAGE_LEN:
                        case DOCT_LEFT_MARGIN:
                        case DOCT_RIGHT_MARGIN:
                        case DOCT_HEADER:
                        case DOCT_FOOTER:
                        case DOCT_INDENT:
                        case DOCT_WORD_WRAP:
                        case DOCT_HIGHLIGHT:
                        case DOCT_BLINK:
                        case DOCT_INVERT:
                        case DOCT_UNDERLINE:
                        case DOCT_SHIFTED_X:
                        case DOCT_SHIFTED_Y:
                                if (attr != DOC_DEFAULT)
                                {
                                        buf2 = MStrPrint("%s%d,", buf, doc_e->attr);
                                        Free(buf);
                                        buf = buf2;
                                }
                        case DOCT_TYPES_NUM - 1: //nobound switch
                                break;
                }
                de_flags = doc_e->de_flags & DOCEG_HAS_ARG;
                while (de_flags)
                {
                        j = Bsf(de_flags);
                        Btr(&de_flags, j);
                        switch [j]
                        {
                                case DOCEf_TAG:
                                        if (doc_e->type_u8 == DOCT_DATA || doc_e->type_u8 == DOCT_MACRO &&
                                                (doc_e->de_flags & DOCEF_LEFT_MACRO &&
                                                 !StrCompare(doc_e->tag, doc_e->left_macro) ||
                                                 doc_e->de_flags & DOCEF_RIGHT_MACRO &&
                                                 !StrCompare(doc_e->tag, doc_e->right_macro)) ||
                                                doc_e->de_flags & DOCEF_LIST && !StrCompare(doc_e->tag, "[]") && doc_e->de_flags & DOCEF_DEFINE)
                                        {
                                                buf2 = buf;
                                                buf = NULL;
                                        }
                                        else
                                        {
                                                if (doc_e->type_u8 == DOCT_CHECK_BOX)
                                                {
                                                        if (StrLen(doc_e->tag) >= 4)
                                                                buf2 = doc_e->tag + 4;
                                                        else
                                                                buf2 = "";
                                                }
                                                else if (doc_e->de_flags & DOCEF_TREE)
                                                {
                                                        if (StrLen(doc_e->tag) >= 3)
                                                                buf2 = doc_e->tag + 3;
                                                        else
                                                                buf2 = "";
                                                }
                                                else
                                                        buf2 = doc_e->tag;
                                                if (Bt(&doldoc.default_de_flags[doc_e->type_u8], DOCEf_TAG))
                                                        buf2 = MStrPrint("%s\"%$Q\",", buf, buf2);
                                                else
                                                        buf2 = MStrPrint("%sT=\"%$Q\",", buf, buf2);
                                        }
                                        break;
                                case DOCEf_LEN:
                                        buf2 = MStrPrint("%sLEN=%d,", buf, doc_e->len);
                                        break;

                                case DOCEf_AUX_STR:
                                        buf2 = MStrPrint("%sA=\"%$Q\",", buf, doc_e->aux_str);
                                        break;

                                case DOCEf_DEFINE:
                                        buf2 = MStrPrint("%sD=\"%$Q\",", buf, doc_e->define_str);
                                        break;

                                case DOCEf_HTML_LINK:
                                        buf2 = MStrPrint("%sHTML=\"%$Q\",", buf, doc_e->html_link);
                                        break;

                                case DOCEf_LEFT_EXP:
                                        buf2 = MStrPrint("%sLE=%d,", buf, doc_e->left_exp);
                                        break;

                                case DOCEf_LEFT_MACRO:
                                        buf2 = MStrPrint("%sLM=\"%$Q\",", buf, doc_e->left_macro);
                                        break;

                                case DOCEf_RIGHT_EXP:
                                        buf2 = MStrPrint("%sRE=%d,", buf, doc_e->right_exp);
                                        break;

                                case DOCEf_RIGHT_MACRO:
                                        buf2 = MStrPrint("%sRM=\"%$Q\",", buf, doc_e->right_macro);
                                        break;

                                case DOCEf_HAS_BIN:
                                        buf2 = MStrPrint("%sBI=%d,", buf, doc_e->bin_num);
                                        break;

                                case DOCEf_BIN_PTR_LINK:
                                        buf2 = MStrPrint("%sBP=\"%$Q\",", buf, doc_e->bin_ptr_link);
                                        break;

                                case DOCEf_RAW_TYPE:
                                        if (doc_e->type_u8 == DOCT_CHECK_BOX && doc_e->raw_type != RT_I8 ||
                                                        doc_e->type_u8 != DOCT_CHECK_BOX && doc_e->raw_type != RT_I64)

                                                buf2 = MStrPrint("%sRT=%Z,", buf, doc_e->raw_type, "ST_RAW_TYPES");
                                        break;

                                case DOCEf_SHIFTED_X:
                                        j = doc_e->type.u16[1] & 0x1F;
                                        if (j & 0x10)
                                                j |= 0xFFFFFFF0;
                                        buf2 = MStrPrint("%sSX=%d,", buf, j);
                                        break;

                                case DOCEf_SHIFTED_Y:
                                        j = doc_e->type >> 21 & 0x1F;
                                        if (j & 0x10)
                                                j |= 0xFFFFFFF0;
                                        buf2 = MStrPrint("%sSY=%d,", buf, j);
                                        break;

                                case DOCEf_SCROLLING_X:
                                        buf2 = MStrPrint("%sSCX=%d,", buf, doc_e->scroll_len);
                                        break;

                                case DOCEf_USER_DATA:
                                        buf2 = MStrPrint("%sU=0x%X,", buf, doc_e->user_data);
                                        break;

                                case DOCEf_FLAGS_NUM - 1: //nobound switch
                                        break;
                        }
                        Free(buf);
                        buf = buf2;
                }
                buf[StrLen(buf) - 1] = 0;  //Kill last comma
        }
        buf2 = StrNew(buf, doc->mem_task); //exact allocation
        Free(buf);

        return buf2;
}

CDocEntry *ParseDollarCmd(CDoc *doc, U8 *st)
{//Uses Lex() to parse a string and make Doc entries.
        I64                              i, j, de_flags, processed_flags, attr = DOC_DEFAULT;
        U8                              *ptr, *st2;
        CDocEntry               *doc_e = NULL;
        CHashGeneric    *tmph;
        CCompCtrl               *cc = CompCtrlNew(st, CCF_DONT_FREE_BUF);
        CHashTable              *old_hash_table_list = cc->htc.hash_table_list;

        try
        {
                cc->htc.hash_table_list = NULL;
                if (Lex(cc) == TK_IDENT)
                {
                        if (tmph = HashFind(cc->cur_str, doldoc.hash, DHT_DOC_CMD | DHT_COLOR))
                        {
                                if (tmph->type & DHT_DOC_CMD)
                                        i = tmph->user_data0;
                                else
                                {//DHT_COLOR
                                        i = DOCT_FOREGROUND;
                                        attr = tmph->user_data0;
                                }
                        }
                        else
                                goto pd_err;
                        Lex(cc); //skip cmd code
                        doc_e = CAlloc(sizeof(CDocEntry), doc->mem_task);
                        doc_e->type             =  i;
                        doc_e->de_flags =  doldoc.default_de_flags[i];
                        doc_e->type             |= doldoc.default_type_flags[i];
                        doc_e->raw_type =  RT_I64;
                        doc_e->len              =  DOCE_LEN_DEFAULT;
                        j=ParseDocFlags(cc, &doc_e->de_flags, &doc_e->type);
                        cc->htc.hash_table_list = old_hash_table_list;
                        switch [i]
                        {
                                case DOCT_CHECK_BOX:
                                        doc_e->raw_type = RT_I8;
                                        break;

                                case DOCT_HEX_ED:
                                        while (cc->token == ',')
                                                Lex(cc);
                                        if (cc->token)
                                                doc_e->len = LexExpressionI64(cc);
                                        else
                                                goto pd_err;
                                        while (cc->token == ',')
                                                Lex(cc);
                                        if (cc->token)
                                                doc_e->hex_ed_width = LexExpressionI64(cc);
                                        else
                                                goto pd_err;
                                        break;

                                case DOCT_PAGE_LEN:
                                case DOCT_LEFT_MARGIN:
                                case DOCT_RIGHT_MARGIN:
                                case DOCT_HEADER:
                                case DOCT_FOOTER:
                                case DOCT_INDENT:
                                case DOCT_FOREGROUND:
                                case DOCT_BACKGROUND:
                                case DOCT_DEFAULT_FOREGROUND:
                                case DOCT_DEFAULT_BACKGROUND:
                                case DOCT_WORD_WRAP:
                                case DOCT_HIGHLIGHT:
                                case DOCT_BLINK:
                                case DOCT_INVERT:
                                case DOCT_UNDERLINE:
                                case DOCT_SHIFTED_X:
                                case DOCT_SHIFTED_Y:
                                        while (cc->token == ',')
                                                Lex(cc);
                                        if (cc->token)
                                                doc_e->attr = LexExpressionI64(cc);
                                        else
                                                doc_e->attr = attr;
                                        break;
#assert DOCT_ERROR == DOCT_TYPES_NUM - 1

                                case DOCT_ERROR:
                                        goto pd_err;
                        }

                        processed_flags = 0;
                        while (TRUE)
                        {
                                cc->htc.hash_table_list = NULL;
                                while (cc->token == ',')
                                        Lex(cc);
                                cc->htc.hash_table_list = old_hash_table_list;
                                j=ParseDocFlagSingle(cc, &doc_e->de_flags, &doc_e->type, TRUE);
                                if (!(de_flags = ~processed_flags & doc_e->de_flags & DOCEG_HAS_ARG))
                                        break;
                                if (cc->token == '=')
                                        Lex(cc);
                                else
                                        j = Bsf(de_flags);
                                if (j < 0 || Bts(&processed_flags, j))
                                        goto pd_err;
                                switch [j]
                                {//TODO: Might check for expression errors
                                        case DOCEf_TAG:
                                                if (!doc_e->tag)
                                                {
//If a $MA,LM=""$, Tag is filled when the LM is processed.
                                                        //if doc_e->df_flags&DOCEF_LIST,
                                                        // Tag is filled when the Define is processed.
                                                        //(The default_flag1.tag calls this after.)
                                                        if (cc->token == TK_STR)
                                                        {
                                                                st2 = LexExtStr(cc);
                                                                if (i == DOCT_CHECK_BOX)
                                                                {
                                                                        st = MStrPrint("[X] %s", st2);
                                                                        Free(st2);
                                                                        doc_e->min_col = 1;
                                                                }
                                                                else if (doc_e->de_flags & DOCEF_LIST)
                                                                {
                                                                        if (*st2 != '[')
                                                                        {
                                                                                st = MStrPrint("[%s]", st2);
                                                                                Free(st2);
                                                                        }
                                                                        else
                                                                                st = st2;
                                                                        doc_e->min_col = 1;
                                                                }
                                                                else if (doc_e->de_flags & DOCEF_TREE)
                                                                {
                                                                        st = MStrPrint("+] %s", st2);
                                                                        Free(st2);
                                                                        doc_e->min_col = 1;
                                                                }
                                                                else
                                                                        st = st2;
                                                                doc_e->tag = StrNew(st, doc->mem_task);
                                                                Free(st);
                                                        }
                                                        else
                                                                goto pd_err;
                                                }
                                                break;

                                        case DOCEf_LEN:
                                                if (cc->token)
                                                {
                                                        doc_e->len              =  LexExpression(cc);
                                                        doc_e->de_flags &= ~DOCEF_DEFAULT_LEN;
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_AUX_STR:
                                                if (cc->token == TK_STR)
                                                {
                                                        st2 = LexExtStr(cc);
                                                        doc_e->aux_str = StrNew(st2, doc->mem_task);
                                                        Free(st2);
//Anchor
                                                        if (i == DOCT_DATA)
                                                        { //See DocForm()
                                                                if (ptr = StrMatch(":", doc_e->aux_str))
                                                                        doc_e->min_col = ptr - doc_e->aux_str + 1;

                                                                doc_e->tag = MAlloc(doc_e->len + doc_e->min_col + 2, doc->mem_task); //+2 because "_\0"
                                                        }
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_DEFINE:
                                                if (cc->token == TK_STR)
                                                {
                                                        st2 = LexExtStr(cc);
                                                        doc_e->define_str = StrNew(st2, doc->mem_task);
                                                        Free(st2);
                                                        if (doc_e->de_flags & DOCEF_LIST && !doc_e->tag)
                                                                doc_e->tag = StrNew("[]", doc->mem_task);
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_HTML_LINK:
                                                if (cc->token == TK_STR)
                                                {
                                                        st2 = LexExtStr(cc);
                                                        doc_e->html_link = StrNew(st2, doc->mem_task);
                                                        Free(st2);
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_LEFT_EXP:
                                                if (cc->token)
                                                        doc_e->left_exp = LexExpression(cc);
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_LEFT_MACRO:
                                                if (cc->token == TK_STR)
                                                {
                                                        st2 = LexExtStr(cc);
                                                        doc_e->left_macro = StrNew(st2, doc->mem_task);
                                                        Free(st2);
                                                        if (i == DOCT_MACRO && !doc_e->tag)
                                                                doc_e->tag = StrNew(doc_e->left_macro, doc->mem_task);
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_RIGHT_EXP:
                                                if (cc->token)
                                                        doc_e->right_exp = LexExpression(cc);
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_RIGHT_MACRO:
                                                if (cc->token == TK_STR)
                                                {
                                                        st2 = LexExtStr(cc);
                                                        doc_e->right_macro = StrNew(st2, doc->mem_task);
                                                        Free(st2);
                                                        if (i == DOCT_MACRO && !doc_e->tag)
                                                                doc_e->tag = StrNew(doc_e->right_macro, doc->mem_task);
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_HAS_BIN:
                                                if (cc->token)
                                                        doc_e->bin_num = LexExpressionI64(cc);
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_BIN_PTR_LINK:
                                                if (cc->token == TK_STR)
                                                {
                                                        st2 = LexExtStr(cc);
                                                        doc_e->bin_ptr_link = StrNew(st2, doc->mem_task);
                                                        Free(st2);
                                                        if (!DocBinPtrReset(doc, doc_e))
                                                                doc_e->type = DOCT_ERROR;
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_RAW_TYPE:
                                                if (cc->token == TK_IDENT)
                                                {
                                                        j = DefineMatch(cc->cur_str, "ST_RAW_TYPES");
                                                        if (j < 0)
                                                                goto pd_err;
                                                        doc_e->raw_type =  j;
                                                        doc_e->de_flags &= ~DOCEF_DEFAULT_RAW_TYPE;
                                                        Lex(cc);
                                                }
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_SHIFTED_X:
                                                if (cc->token)
                                                        doc_e->type |= (LexExpressionI64(cc) & 0x1F) << 16;
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_SHIFTED_Y:
                                                if (cc->token)
                                                        doc_e->type |= (LexExpressionI64(cc) & 0x1F) << 21;
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_SCROLLING_X:
                                                if (cc->token)
                                                        doc_e->scroll_len = LexExpressionI64(cc);
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_USER_DATA:
                                                if (cc->token)
                                                        doc_e->user_data = LexExpression(cc);
                                                else
                                                        goto pd_err;
                                                break;

                                        case DOCEf_FLAGS_NUM - 1: //nobound switch
                                                break;
                                }
                        }
                }
                else
                {
pd_err:
                        if (!doc_e)
                                doc_e = CAlloc(sizeof(CDocEntry), doc->mem_task);
                        doc_e->type             = DOCT_ERROR;
                        doc_e->de_flags = 0;
                }
                if (doc_e->de_flags & DOCEF_LIST && (doc_e->de_flags & DOCEF_REMALLOC_DATA || !(doc_e->de_flags & DOCEF_DEREF_DATA)))
                {
                        DocDataScan(doc, doc_e);
                        DocDataFormat(doc, doc_e);
                }
                CompCtrlDel(cc);
        }
        catch
        {
                Fs->catch_except = TRUE;
                if (!doc_e)
                        doc_e = CAlloc(sizeof(CDocEntry), doc->mem_task);
                doc_e->type             = DOCT_ERROR;
                doc_e->de_flags = 0;
        }

        return doc_e;
}

U0 DocEntryToggle(CDoc *doc)
{
        Bool             unlock = DocLock(doc), old_color_names;
        CDocEntry       *doc_ce = doc->cur_entry, *cl1, *doc_ce2;
        U8                       ch, *st, *st2;
        I64                      i, j, k;

        if (doc_ce != doc && !(doc->flags & (DOCF_PLAIN_TEXT | DOCF_PLAIN_TEXT_TABS)))
        {
                if (doc_ce->type_u8 == DOCT_TEXT &&
                        !(doc_ce->de_flags &
                         ~(DOCEF_TAG | DOCG_BL_IV_UL | DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT | DOCEF_SKIP | DOCEF_FILTER_SKIP)) &&
                        !(doc_ce->type&DOCG_BL_IV_UL))
                {
                        doc_ce2 = doc_ce->last;
                        for (k = 0; k < 20; k++)
                        {
                                if (doc_ce2 != doc)
                                {
                                        cl1 = doc_ce2->last;
                                        if (doc_ce2->type_u8 == DOCT_TEXT &&
                                                doc_ce->de_flags == doc_ce2->de_flags &&
                                                doc_ce->type == doc_ce2->type)
                                        {
                                                i = StrLen(doc_ce2->tag);
                                                j = StrLen(doc_ce->tag);
                                                st = MAlloc(i + j + 1, doc->mem_task);
                                                MemCopy(st, doc_ce2->tag, i);
                                                MemCopy(st + i, doc_ce->tag, j + 1);
                                                Free(doc_ce->tag);
                                                doc_ce->tag             =  st;
                                                doc_ce->max_col =  i + j;
                                                doc->cur_col    += i;
                                                DocEntryDel(doc, doc_ce2);
                                        }
                                        else if (doc_ce2->type_u8 == DOCT_SOFT_NEW_LINE)
                                                DocEntryDel(doc, doc_ce2);
                                        else
                                                break;
                                        doc_ce2 = cl1;
                                }
                                else
                                        break;
                        }
                        doc_ce2 = doc_ce->next;
                        for (k = 0; k < 20; k++)
                        {
                                if (doc_ce2 != doc)
                                {
                                        cl1 = doc_ce2->next;
                                        if (doc_ce2->type_u8 == DOCT_TEXT &&
                                                doc_ce->de_flags == doc_ce2->de_flags &&
                                                doc_ce->type == doc_ce2->type)
                                        {
                                                i = StrLen(doc_ce->tag);
                                                j = StrLen(doc_ce2->tag);
                                                st = MAlloc(i + j + 1, doc->mem_task);
                                                MemCopy(st, doc_ce->tag, i);
                                                MemCopy(st + i, doc_ce2->tag, j + 1);
                                                Free(doc_ce->tag);
                                                doc_ce->tag             = st;
                                                doc_ce->max_col = i + j;
                                                DocEntryDel(doc, doc_ce2);
                                        }
                                        else if (doc_ce2->type_u8 == DOCT_SOFT_NEW_LINE)
                                                DocEntryDel(doc, doc_ce2);
                                        else
                                                break;
                                        doc_ce2 = cl1;
                                }
                                else
                                        break;
                        }
                        i = doc->cur_col;
                        while (i > doc_ce->min_col && doc_ce->tag[i] != '$')
                                i--;
                        j = doc->cur_col + 1;
                        while (j < doc_ce->max_col && doc_ce->tag[j] != '$')
                                j++;
                        if (i < j - 1 && doc_ce->min_col <= i < j < doc_ce->max_col && doc_ce->tag[i] == '$' && doc_ce->tag[j] == '$')
                        {
                                ch = doc_ce->tag[j + 1];
                                doc_ce->tag[j + 1] = 0;
                                st = StrNew(doc_ce->tag + i);
                                doc_ce->tag[j + 1] = ch;
                                StrCopy(doc_ce->tag + i, doc_ce->tag + j + 1);
                                doc->cur_col = i;
                                st2 = MStrPrint("%q", st);
                                if (doc_ce = DocPrint(doc, st2))
                                {
                                        doc->cur_entry  = doc_ce;
                                        doc->cur_col    = doc_ce->min_col;
                                }
                                Free(st);
                                Free(st2);
                        }
                }
                else
                {
                        old_color_names = LBts(&doc->flags, DOCf_COLOR_NAMES);
                        st = Doc2PlainText(doc, doc_ce);
                        LBEqual(&doc->flags, DOCf_COLOR_NAMES, old_color_names);
                        DocEntryDel(doc, doc_ce);
                        DocPrint(doc, "$$%$Q$$", st);
                }
                DocRecalc(doc);
        }
        if (unlock)
                DocUnlock(doc);
}

U0 DocFlagsToggle(CDoc *doc, I64 tog_flags)
{
        Bool             unlock = DocLock(doc);
        I64                      size, flags = doc->flags ^ tog_flags;
        U8                      *st;
        CDocUndo        *u_next, *u_last;

        doc->flags = doc->flags & ~DOCF_NO_CURSOR | DOCF_COLOR_NAMES;
        st = DocSave(doc, &size);

        u_next = doc->undo_head.next;
        u_last = doc->undo_head.last;
        doc->undo_head.next = doc->undo_head.last = &doc->undo_head;

        DocReset(doc, TRUE);
        doc->undo_head.next = u_next;
        doc->undo_head.last = u_last;
        DocUndoCountSet(doc);
        doc->flags = flags & ~(DOCF_NO_CURSOR | DOCG_BL_IV_UL | DOCF_WORD_WRAP);
        DocLoad(doc, st, size);
        doc->flags |= flags & DOCF_NO_CURSOR;
        DocCenter(doc);
        if (unlock)
                DocUnlock(doc);
        Free(st);
}