📄 memline.c
字号:
* - there is not enough room in the current block
* - appending to the last line in the block
* - not appending to the last line in the file
* insert in front of the next block.
*/
if ((int)dp->db_free < space_needed && db_idx == line_count - 1
&& lnum < buf->b_ml.ml_line_count)
{
/*
* Now that the line is not going to be inserted in the block that we
* expected, the line count has to be adjusted in the pointer blocks
* by using ml_locked_lineadd.
*/
--(buf->b_ml.ml_locked_lineadd);
--(buf->b_ml.ml_locked_high);
if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
return FAIL;
db_idx = -1; /* careful, it is negative! */
/* get line count before the insertion */
line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
dp = (DATA_BL *)(hp->bh_data);
}
++buf->b_ml.ml_line_count;
if ((int)dp->db_free >= space_needed) /* enough room in data block */
{
/*
* Insert new line in existing data block, or in data block allocated above.
*/
dp->db_txt_start -= len;
dp->db_free -= space_needed;
++(dp->db_line_count);
/*
* move the text of the lines that follow to the front
* adjust the indexes of the lines that follow
*/
if (line_count > db_idx + 1) /* if there are following lines */
{
/*
* Offset is the start of the previous line.
* This will become the character just after the new line.
*/
if (db_idx < 0)
offset = dp->db_txt_end;
else
offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
mch_memmove((char *)dp + dp->db_txt_start,
(char *)dp + dp->db_txt_start + len,
(size_t)(offset - (dp->db_txt_start + len)));
for (i = line_count - 1; i > db_idx; --i)
dp->db_index[i + 1] = dp->db_index[i] - len;
dp->db_index[db_idx + 1] = offset - len;
}
else /* add line at the end */
dp->db_index[db_idx + 1] = dp->db_txt_start;
/*
* copy the text into the block
*/
mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
if (mark)
dp->db_index[db_idx + 1] |= DB_MARKED;
/*
* Mark the block dirty.
*/
buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
if (!newfile)
buf->b_ml.ml_flags |= ML_LOCKED_POS;
}
else /* not enough space in data block */
{
/*
* If there is not enough room we have to create a new data block and copy some
* lines into it.
* Then we have to insert an entry in the pointer block.
* If this pointer block also is full, we go up another block, and so on, up
* to the root if necessary.
* The line counts in the pointer blocks have already been adjusted by
* ml_find_line().
*/
long line_count_left, line_count_right;
int page_count_left, page_count_right;
BHDR *hp_left;
BHDR *hp_right;
BHDR *hp_new;
int lines_moved;
int data_moved = 0; /* init to shut up gcc */
int total_moved = 0; /* init to shut up gcc */
DATA_BL *dp_right, *dp_left;
int stack_idx;
int in_left;
int lineadd;
blocknr_t bnum_left, bnum_right;
linenr_t lnum_left, lnum_right;
int pb_idx;
PTR_BL *pp_new;
/*
* We are going to allocate a new data block. Depending on the
* situation it will be put to the left or right of the existing
* block. If possible we put the new line in the left block and move
* the lines after it to the right block. Otherwise the new line is
* also put in the right block. This method is more efficient when
* inserting a lot of lines at one place.
*/
if (db_idx < 0) /* left block is new, right block is existing */
{
lines_moved = 0;
in_left = TRUE;
/* space_needed does not change */
}
else /* left block is existing, right block is new */
{
lines_moved = line_count - db_idx - 1;
if (lines_moved == 0)
in_left = FALSE; /* put new line in right block */
/* space_needed does not change */
else
{
data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
dp->db_txt_start;
total_moved = data_moved + lines_moved * INDEX_SIZE;
if ((int)dp->db_free + total_moved >= space_needed)
{
in_left = TRUE; /* put new line in left block */
space_needed = total_moved;
}
else
{
in_left = FALSE; /* put new line in right block */
space_needed += total_moved;
}
}
}
page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
{
/* correct line counts in pointer blocks */
--(buf->b_ml.ml_locked_lineadd);
--(buf->b_ml.ml_locked_high);
return FAIL;
}
if (db_idx < 0) /* left block is new */
{
hp_left = hp_new;
hp_right = hp;
line_count_left = 0;
line_count_right = line_count;
}
else /* right block is new */
{
hp_left = hp;
hp_right = hp_new;
line_count_left = line_count;
line_count_right = 0;
}
dp_right = (DATA_BL *)(hp_right->bh_data);
dp_left = (DATA_BL *)(hp_left->bh_data);
bnum_left = hp_left->bh_bnum;
bnum_right = hp_right->bh_bnum;
page_count_left = hp_left->bh_page_count;
page_count_right = hp_right->bh_page_count;
/*
* May move the new line into the right/new block.
*/
if (!in_left)
{
dp_right->db_txt_start -= len;
dp_right->db_free -= len + INDEX_SIZE;
dp_right->db_index[0] = dp_right->db_txt_start;
if (mark)
dp_right->db_index[0] |= DB_MARKED;
mch_memmove((char *)dp_right + dp_right->db_txt_start,
line, (size_t)len);
++line_count_right;
}
/*
* may move lines from the left/old block to the right/new one.
*/
if (lines_moved)
{
/*
*/
dp_right->db_txt_start -= data_moved;
dp_right->db_free -= total_moved;
mch_memmove((char *)dp_right + dp_right->db_txt_start,
(char *)dp_left + dp_left->db_txt_start,
(size_t)data_moved);
offset = dp_right->db_txt_start - dp_left->db_txt_start;
dp_left->db_txt_start += data_moved;
dp_left->db_free += total_moved;
/*
* update indexes in the new block
*/
for (to = line_count_right, from = db_idx + 1;
from < line_count_left; ++from, ++to)
dp_right->db_index[to] = dp->db_index[from] + offset;
line_count_right += lines_moved;
line_count_left -= lines_moved;
}
/*
* May move the new line into the left (old or new) block.
*/
if (in_left)
{
dp_left->db_txt_start -= len;
dp_left->db_free -= len + INDEX_SIZE;
dp_left->db_index[line_count_left] = dp_left->db_txt_start;
if (mark)
dp_left->db_index[line_count_left] |= DB_MARKED;
mch_memmove((char *)dp_left + dp_left->db_txt_start,
line, (size_t)len);
++line_count_left;
}
if (db_idx < 0) /* left block is new */
{
lnum_left = lnum + 1;
lnum_right = 0;
}
else /* right block is new */
{
lnum_left = 0;
if (in_left)
lnum_right = lnum + 2;
else
lnum_right = lnum + 1;
}
dp_left->db_line_count = line_count_left;
dp_right->db_line_count = line_count_right;
/*
* release the two data blocks
* The new one (hp_new) already has a correct blocknumber.
* The old one (hp, in ml_locked) gets a positive blocknumber if
* we changed it and we are not editing a new file.
*/
if (lines_moved || in_left)
buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
if (!newfile && db_idx >= 0 && in_left)
buf->b_ml.ml_flags |= ML_LOCKED_POS;
mf_put(mfp, hp_new, TRUE, FALSE);
/*
* flush the old data block
* set ml_locked_lineadd to 0, because the updating of the
* pointer blocks is done below
*/
lineadd = buf->b_ml.ml_locked_lineadd;
buf->b_ml.ml_locked_lineadd = 0;
ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush data block */
/*
* update pointer blocks for the new data block
*/
for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
--stack_idx)
{
ip = &(buf->b_ml.ml_stack[stack_idx]);
pb_idx = ip->ip_index;
if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
return FAIL;
pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
if (pp->pb_id != PTR_ID)
{
EMSG("pointer block id wrong 3");
mf_put(mfp, hp, FALSE, FALSE);
return FAIL;
}
/*
* TODO: If the pointer block is full and we are adding at the end
* try to insert in front of the next block
*/
if (pp->pb_count < pp->pb_count_max) /* block not full, add one entry */
{
if (pb_idx + 1 < (int)pp->pb_count)
mch_memmove(&pp->pb_pointer[pb_idx + 2],
&pp->pb_pointer[pb_idx + 1],
(size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
++pp->pb_count;
pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
if (lnum_left != 0)
pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
if (lnum_right != 0)
pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
mf_put(mfp, hp, TRUE, FALSE);
buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
if (lineadd)
{
--(buf->b_ml.ml_stack_top);
/* fix line count for rest of blocks in the stack */
ml_lineadd(buf, lineadd);
/* fix stack itself */
buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
lineadd;
++(buf->b_ml.ml_stack_top);
}
return OK;
}
else /* pointer block full */
{
/*
* split the pointer block
* allocate a new pointer block
* move some of the pointer into the new block
* prepare for updating the parent block
*/
for (;;) /* do this twice when splitting block 1 */
{
hp_new = ml_new_ptr(mfp);
if (hp_new == NULL) /* TODO: try to fix tree */
return FAIL;
pp_new = (PTR_BL *)(hp_new->bh_data);
if (hp->bh_bnum != 1)
break;
/*
* if block 1 becomes full the tree is given an extra level
* The pointers from block 1 are moved into the new block.
* block 1 is updated to point to the new block
* then continue to split the new block
*/
mch_memmove(pp_new, pp, (size_t)page_size);
pp->pb_count = 1;
pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
pp->pb_pointer[0].pe_old_lnum = 1;
pp->pb_pointer[0].pe_page_count = 1;
mf_put(mfp, hp, TRUE, FALSE); /* release block 1 */
hp = hp_new; /* new block is to be split */
pp = pp_new;
CHECK(stack_idx != 0, "stack_idx should be 0");
ip->ip_index = 0;
++stack_idx; /* do block 1 again later */
}
/*
* move the pointers after the current one to the new block
* If there are none, the new entry will be in the new block.
*/
total_moved = pp->pb_count - pb_idx - 1;
if (total_moved)
{
mch_memmove(&pp_new->pb_pointer[0],
&pp->pb_pointer[pb_idx + 1],
(size_t)(total_moved) * sizeof(PTR_EN));
pp_new->pb_count = total_moved;
pp->pb_count -= total_moved - 1;
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
if (lnum_right)
pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
}
else
{
pp_new->pb_count = 1;
pp_new->pb_pointer[0].pe_bnum = bnum_right;
pp_new->pb_pointer[0].pe_line_count = line_count_right;
pp_new->pb_pointer[0].pe_page_count = page_count_right;
pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
}
pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
if (lnum_left)
pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
lnum_left = 0;
lnum_right = 0;
/*
* recompute line counts
*/
line_count_right = 0;
for (i = 0; i < (int)pp_new->pb_count; ++i)
line_count_right += pp_new->pb_pointer[i].pe_line_count;
line_count_left = 0;
for (i = 0; i < (int)pp->pb_count; ++i)
line_count_left += pp->pb_pointer[i].pe_line_count;
bnum_left = hp->bh_bnum;
bnum_right = hp_new->bh_bnum;
page_count_left = 1;
page_count_right = 1;
mf_put(mfp, hp, TRUE, FALSE);
mf_put(mfp, hp_new, TRUE, FALSE);
}
}
EMSG("Updated too many blocks?");
buf->b_ml.ml_stack_top = 0; /* invalidate stack */
}
return OK;
}
/*
* replace line lnum, with buffering, in current buffer
*
* If copy is TRUE, make a copy of the line, otherwise the line has been
* copied to allocated memory already.
* NOTE: For syntax highlighting, need to call syn_changed() when
* update_screenline() is not used.
*
* return FAIL for failure, OK otherwise
*/
int
ml_replace(lnum, line, copy)
linenr_t lnum;
char_u *line;
int copy;
{
if (line == NULL) /* just checking... */
return FAIL;
if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
ml_flush_line(curbuf); /* flush it */
else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
vim_free(curbuf->b_ml.ml_line_ptr); /* free it */
if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
return FAIL;
curbuf->b_ml.ml_line_ptr = line;
curbuf->b_ml.ml_line_lnum = lnum;
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
return OK;
}
/*
* delete line 'lnum'
*
* return FAIL for failure, OK otherwise
*/
int
ml_delete(lnum, message)
linenr_t lnum;
int message;
{
#ifdef SYNTAX_HL
if (curbuf->b_syn_change_lnum > lnum)
curbuf->b_syn_change_lnum = lnum;
#endif
ml_flush_line(curbuf);
return ml_delete_int(curbuf, lnum, message);
}
static int
ml_delete_int(buf, lnum, message)
BUF *buf;
linenr_t l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -