예제 #1
0
/*
 * InsertLines - insert a set of lines after specified number in current file
 */
vi_rc InsertLines( linenum s, fcb_list *fcblist, undo_stack *us )
{
    fcb         *sfcb, *cfcb;
    linenum     l, e;
    vi_rc       rc;

    rc = ModificationTest();
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    if( s < 0 ) {
        return( ERR_NO_SUCH_LINE );
    }

    /*
     * find the number of lines inserted
     */
    e = 0;
    for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) {
        e += cfcb->end_line - cfcb->start_line + 1;
    }
    e += s;

    /*
     * see if there is a null fcb at the head; if so, ditch
     * the null fcb and then reset line ranges
     */
    if( CurrentFile->fcbs.head->nullfcb ) {
        FreeEntireFcb( CurrentFile->fcbs.head );
        CurrentFile->fcbs = *fcblist;
        e = e - s;
        s = 0;
    /*
     * if we are to insert after line 0, then make this block of
     * fcbs the first set in the text
     */
    } else if( s == 0 ) {
        fcblist->tail->next = CurrentFile->fcbs.head;
        CurrentFile->fcbs.head->prev = fcblist->tail;
        CurrentFile->fcbs.head = fcblist->head;
    } else {
        /*
         * if we are inserting after the last fcb in the file,
         * make this block of fcbs the last set in the text
         */
        rc = FindFcbWithLine( s + 1, CurrentFile, &sfcb );
        if( rc != ERR_NO_ERR ) {
            if( rc != ERR_NO_SUCH_LINE ) {
                return( rc );
            }
            fcblist->head->prev = CurrentFile->fcbs.tail;
            CurrentFile->fcbs.tail->next = fcblist->head;
            CurrentFile->fcbs.tail = fcblist->tail;
        /*
         * put the lines after the line to be have text inserted
         * into a new fcb, then insert the block of fcb's after
         * the fcb containing the line to have text inserted
         */
        } else {
            rc = SplitFcbAtLine( s + 1, CurrentFile, sfcb );
            if( rc > ERR_NO_ERR ) {
                return( rc );
            }
            /*
             * line we want to split at is already the first line
             * in the fcb, so chain the new fcb block before
             * the fcb containg the line we want to split at
             */
            if( rc == NO_SPLIT_CREATED_AT_START_LINE ) {
                if( sfcb->prev != NULL ) {
                    sfcb->prev->next = fcblist->head;
                }
                fcblist->head->prev = sfcb->prev;
                sfcb->prev = fcblist->tail;
                fcblist->tail->next = sfcb;
            /*
             * chain the new fcb block after the fcb that used
             * to containing the line we wanted to split at, and
             * before the new fcb containing the line we want
             * to split at
             */
            } else {
                if( rc == NO_SPLIT_CREATED_AT_END_LINE ) {
//                  Die( "Impossible, can't be past last line");
                }
                if( sfcb->next != NULL ) {
                    sfcb->next->prev = fcblist->tail;
                }
                fcblist->tail->next = sfcb->next;
                sfcb->next = fcblist->head;
                fcblist->head->prev = sfcb;
            }
        }
    }

    /*
     * now, resequence line numbers and set proper file ptr
     */
    for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) {
        cfcb->f = CurrentFile;
        l = cfcb->end_line - cfcb->start_line;
        if( cfcb->prev != NULL ) {
            cfcb->start_line = cfcb->prev->end_line + 1;
        } else {
            cfcb->start_line = 1;
        }
        cfcb->end_line = cfcb->start_line + l;
    }

    /*
     * finish up: collect fcbs, point to corrent line, and
     * build undo for operation
     */
    rc = MergeAllFcbs( &CurrentFile->fcbs );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    StartUndoGroup( us );
    rc = ValidateCurrentLine();
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    Modified( true );
    UndoInsert( s + 1, e, us );
    EndUndoGroup( us );

    return( ERR_NO_ERR );

} /* InsertLines */
예제 #2
0
/*
 * PatchDeleteUndo - go and patch together undo deletes
 */
void PatchDeleteUndo( undo_stack *stack )
{
    undo        *top, *next, *del, *topdel, *after, *tmp;
    bool        merge;

    /*
     * see if we can merge this with the last undo record
     * (provided we are in an open undo group)
     *
     * we need the following undo sequence, after the first one:
     * END_UNDO_GROUP
     * UNDO_DELETE_FCBS
     *      - must have same start line as the first one
     * START_UNDO_GROUP
     */
    if( stack == NULL || stack->OpenUndo <= 0 || stack->current < 0 ||
        !EditFlags.Undo ) {
        return;
    }
    top = stack->stack[stack->current];
    topdel = top->next;
    next = top->next->next->next;   /* go past first delete group */
    if( next == NULL || next->type != END_UNDO_GROUP ) {
        return;
    }
    next = next->next;
    if( next == NULL || next->type != UNDO_DELETE_FCBS ) {
        return;
    }
    del = next;
    next = next->next;
    if( next == NULL || next->type != START_UNDO_GROUP ) {
        return;
    }
    after = next->next;

    /*
     * if two starts are the same, then these are back-to-back deletes
     * and we can merge them.
     */
    merge = FALSE;
    if( del->data.fcbs.head->start_line == topdel->data.fcbs.head->start_line ) {
        merge = TRUE;
    }

    /*
     * merge data two records together
     */
    if( merge ) {
        /*
         * join fcbs from the two undo records: the fcbs
         * from the 2nd record become the head fcbs, and
         * the fcbs from the 2nd record follow them.
         */
        del->data.fcbs.tail->next = topdel->data.fcbs.head;
        topdel->data.fcbs.head->prev = del->data.fcbs.tail;
        topdel->data.fcbs.head = del->data.fcbs.head;
        numberLines( topdel->data.fcbs.head, topdel->data.fcbs.head->start_line );

        /*
         * join the top undo sequence with the third one
         */
        next = top->next->next->next;   /* go past first delete group */
        top->next->next->next = after;  /* join first undo group to third */

        /*
         * delete the END_UNDO_GROUP, UNDO_DELETE_FCBS,
         * and START_UNDO_GROUP records for the 2nd entry
         */
        tmp = next->next;
        MemFree( next );
        next = tmp;
        tmp = next->next;
        MemFree( next );
        MemFree( tmp );

        /*
         * merge the line data from the fcbs together
         */
        MergeAllFcbs( &topdel->data.fcbs );
    }

} /* PatchDeleteUndo */