comparison src/memline.c @ 15292:ba6f0f1bb9d0 v8.1.0654

patch 8.1.0654: when deleting a line text property flags are not adjusted commit https://github.com/vim/vim/commit/c1a9bc1a7284bd0e60f9bddfef6a4ee733bfc838 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Dec 28 21:59:29 2018 +0100 patch 8.1.0654: when deleting a line text property flags are not adjusted Problem: When deleting a line text property flags are not adjusted. Solution: Adjust text property flags in preceding and following lines.
author Bram Moolenaar <Bram@vim.org>
date Fri, 28 Dec 2018 22:00:05 +0100
parents 27783a6f430b
children 2d8225cc1315
comparison
equal deleted inserted replaced
15291:11c4950be418 15292:ba6f0f1bb9d0
3212 curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; 3212 curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
3213 3213
3214 return OK; 3214 return OK;
3215 } 3215 }
3216 3216
3217 #ifdef FEAT_TEXT_PROP
3218 /*
3219 * Adjust text properties in line "lnum" for a deleted line.
3220 * When "above" is true this is the line above the deleted line.
3221 * "del_props" are the properties of the deleted line.
3222 */
3223 static void
3224 adjust_text_props_for_delete(
3225 buf_T *buf,
3226 linenr_T lnum,
3227 char_u *del_props,
3228 int del_props_len,
3229 int above)
3230 {
3231 int did_get_line = FALSE;
3232 int done_del;
3233 int done_this;
3234 textprop_T prop_del;
3235 textprop_T prop_this;
3236 bhdr_T *hp;
3237 DATA_BL *dp;
3238 int idx;
3239 int line_start;
3240 long line_size;
3241 int this_props_len;
3242 char_u *text;
3243 size_t textlen;
3244 int found;
3245
3246 for (done_del = 0; done_del < del_props_len; done_del += sizeof(textprop_T))
3247 {
3248 mch_memmove(&prop_del, del_props + done_del, sizeof(textprop_T));
3249 if ((above && (prop_del.tp_flags & TP_FLAG_CONT_PREV)
3250 && !(prop_del.tp_flags & TP_FLAG_CONT_NEXT))
3251 || (!above && (prop_del.tp_flags & TP_FLAG_CONT_NEXT)
3252 && !(prop_del.tp_flags & TP_FLAG_CONT_PREV)))
3253 {
3254 if (!did_get_line)
3255 {
3256 did_get_line = TRUE;
3257 if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
3258 return;
3259
3260 dp = (DATA_BL *)(hp->bh_data);
3261 idx = lnum - buf->b_ml.ml_locked_low;
3262 line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3263 if (idx == 0) // first line in block, text at the end
3264 line_size = dp->db_txt_end - line_start;
3265 else
3266 line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
3267 text = (char_u *)dp + line_start;
3268 textlen = STRLEN(text) + 1;
3269 if ((long)textlen >= line_size)
3270 {
3271 if (above)
3272 internal_error("no text property above deleted line");
3273 else
3274 internal_error("no text property below deleted line");
3275 return;
3276 }
3277 this_props_len = line_size - textlen;
3278 }
3279
3280 found = FALSE;
3281 for (done_this = 0; done_this < this_props_len; done_this += sizeof(textprop_T))
3282 {
3283 mch_memmove(&prop_this, text + textlen + done_del, sizeof(textprop_T));
3284 if (prop_del.tp_id == prop_this.tp_id
3285 && prop_del.tp_type == prop_this.tp_type)
3286 {
3287 int flag = above ? TP_FLAG_CONT_NEXT : TP_FLAG_CONT_PREV;
3288
3289 found = TRUE;
3290 if (prop_this.tp_flags & flag)
3291 {
3292 prop_this.tp_flags &= ~flag;
3293 mch_memmove(text + textlen + done_del, &prop_this, sizeof(textprop_T));
3294 }
3295 else if (above)
3296 internal_error("text property above deleted line does not continue");
3297 else
3298 internal_error("text property below deleted line does not continue");
3299 }
3300 }
3301 if (!found)
3302 {
3303 if (above)
3304 internal_error("text property above deleted line not found");
3305 else
3306 internal_error("text property below deleted line not found");
3307 }
3308
3309 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3310 }
3311 }
3312 }
3313 #endif
3314
3217 /* 3315 /*
3218 * Delete line "lnum" in the current buffer. 3316 * Delete line "lnum" in the current buffer.
3219 * When "message" is TRUE may give a "No lines in buffer" message. 3317 * When "message" is TRUE may give a "No lines in buffer" message.
3220 * 3318 *
3221 * Check: The caller of this function should probably also call 3319 * Check: The caller of this function should probably also call
3243 int stack_idx; 3341 int stack_idx;
3244 int text_start; 3342 int text_start;
3245 int line_start; 3343 int line_start;
3246 long line_size; 3344 long line_size;
3247 int i; 3345 int i;
3346 int ret = FAIL;
3347 #ifdef FEAT_TEXT_PROP
3348 char_u *textprop_save = NULL;
3349 int textprop_save_len;
3350 #endif
3248 3351
3249 if (lnum < 1 || lnum > buf->b_ml.ml_line_count) 3352 if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
3250 return FAIL; 3353 return FAIL;
3251 3354
3252 if (lowest_marked && lowest_marked > lnum) 3355 if (lowest_marked && lowest_marked > lnum)
3270 3373
3271 return i; 3374 return i;
3272 } 3375 }
3273 3376
3274 /* 3377 /*
3275 * find the data block containing the line 3378 * Find the data block containing the line.
3276 * This also fills the stack with the blocks from the root to the data block 3379 * This also fills the stack with the blocks from the root to the data block.
3277 * This also releases any locked block. 3380 * This also releases any locked block..
3278 */ 3381 */
3279 mfp = buf->b_ml.ml_mfp; 3382 mfp = buf->b_ml.ml_mfp;
3280 if (mfp == NULL) 3383 if (mfp == NULL)
3281 return FAIL; 3384 return FAIL;
3282 3385
3298 line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start; 3401 line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
3299 3402
3300 #ifdef FEAT_NETBEANS_INTG 3403 #ifdef FEAT_NETBEANS_INTG
3301 if (netbeans_active()) 3404 if (netbeans_active())
3302 netbeans_removed(buf, lnum, 0, (long)line_size); 3405 netbeans_removed(buf, lnum, 0, (long)line_size);
3406 #endif
3407 #ifdef FEAT_TEXT_PROP
3408 // If there are text properties, make a copy, so that we can update
3409 // properties in preceding and following lines.
3410 if (buf->b_has_textprop)
3411 {
3412 size_t textlen = STRLEN((char_u *)dp + line_start) + 1;
3413
3414 if ((long)textlen < line_size)
3415 {
3416 textprop_save_len = line_size - textlen;
3417 textprop_save = vim_memsave((char_u *)dp + line_start + textlen,
3418 textprop_save_len);
3419 }
3420 }
3303 #endif 3421 #endif
3304 3422
3305 /* 3423 /*
3306 * special case: If there is only one line in the data block it becomes empty. 3424 * special case: If there is only one line in the data block it becomes empty.
3307 * Then we have to remove the entry, pointing to this data block, from the 3425 * Then we have to remove the entry, pointing to this data block, from the
3320 { 3438 {
3321 buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */ 3439 buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
3322 ip = &(buf->b_ml.ml_stack[stack_idx]); 3440 ip = &(buf->b_ml.ml_stack[stack_idx]);
3323 idx = ip->ip_index; 3441 idx = ip->ip_index;
3324 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) 3442 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3325 return FAIL; 3443 goto theend;
3326 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */ 3444 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
3327 if (pp->pb_id != PTR_ID) 3445 if (pp->pb_id != PTR_ID)
3328 { 3446 {
3329 IEMSG(_("E317: pointer block id wrong 4")); 3447 IEMSG(_("E317: pointer block id wrong 4"));
3330 mf_put(mfp, hp, FALSE, FALSE); 3448 mf_put(mfp, hp, FALSE, FALSE);
3331 return FAIL; 3449 goto theend;
3332 } 3450 }
3333 count = --(pp->pb_count); 3451 count = --(pp->pb_count);
3334 if (count == 0) /* the pointer block becomes empty! */ 3452 if (count == 0) /* the pointer block becomes empty! */
3335 mf_free(mfp, hp); 3453 mf_free(mfp, hp);
3336 else 3454 else
3382 } 3500 }
3383 3501
3384 #ifdef FEAT_BYTEOFF 3502 #ifdef FEAT_BYTEOFF
3385 ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE); 3503 ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
3386 #endif 3504 #endif
3387 return OK; 3505 ret = OK;
3388 } 3506
3389 3507 theend:
3390 /* 3508 #ifdef FEAT_TEXT_PROP
3391 * set the B_MARKED flag for line 'lnum' 3509 if (textprop_save != NULL)
3510 {
3511 // Adjust text properties in the line above and below.
3512 if (lnum > 1)
3513 adjust_text_props_for_delete(buf, lnum - 1, textprop_save, textprop_save_len, TRUE);
3514 if (lnum <= buf->b_ml.ml_line_count)
3515 adjust_text_props_for_delete(buf, lnum, textprop_save, textprop_save_len, FALSE);
3516 }
3517 vim_free(textprop_save);
3518 #endif
3519 return ret;
3520 }
3521
3522 /*
3523 * set the DB_MARKED flag for line 'lnum'
3392 */ 3524 */
3393 void 3525 void
3394 ml_setmarked(linenr_T lnum) 3526 ml_setmarked(linenr_T lnum)
3395 { 3527 {
3396 bhdr_T *hp; 3528 bhdr_T *hp;
3415 dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED; 3547 dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
3416 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY; 3548 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3417 } 3549 }
3418 3550
3419 /* 3551 /*
3420 * find the first line with its B_MARKED flag set 3552 * find the first line with its DB_MARKED flag set
3421 */ 3553 */
3422 linenr_T 3554 linenr_T
3423 ml_firstmarked(void) 3555 ml_firstmarked(void)
3424 { 3556 {
3425 bhdr_T *hp; 3557 bhdr_T *hp;
3648 3780
3649 return hp; 3781 return hp;
3650 } 3782 }
3651 3783
3652 /* 3784 /*
3653 * lookup line 'lnum' in a memline 3785 * Lookup line 'lnum' in a memline.
3654 * 3786 *
3655 * action: if ML_DELETE or ML_INSERT the line count is updated while searching 3787 * action: if ML_DELETE or ML_INSERT the line count is updated while searching
3656 * if ML_FLUSH only flush a locked block 3788 * if ML_FLUSH only flush a locked block
3657 * if ML_FIND just find the line 3789 * if ML_FIND just find the line
3658 * 3790 *