Mercurial > vim
comparison src/charset.c @ 32981:2415680a2554 v9.0.1783
commit b557f4898208105b674df605403cac1b1292707b
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue Aug 22 22:07:34 2023 +0200
patch 9.0.1783: Display issues with virt text smoothscroll and showbreak
Problem: Wrong display with wrapping virtual text or unprintable chars,
'showbreak' and 'smoothscroll'.
Solution: Don't skip cells taken by 'showbreak' in screen lines before
"w_skipcol". Combined "n_skip" and "skip_cells".
closes: #12597
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 24 Aug 2023 07:47:10 +0200 |
parents | 5d17e74a756d |
children | 68a12270d21b ebb36e3d5299 |
comparison
equal
deleted
inserted
replaced
32964:c7a332a34fe7 | 32981:2415680a2554 |
---|---|
1095 * Return the screen size of the character indicated by "cts". | 1095 * Return the screen size of the character indicated by "cts". |
1096 * "cts->cts_cur_text_width" is set to the extra size for a text property that | 1096 * "cts->cts_cur_text_width" is set to the extra size for a text property that |
1097 * inserts text. | 1097 * inserts text. |
1098 * This function is used very often, keep it fast!!!! | 1098 * This function is used very often, keep it fast!!!! |
1099 * | 1099 * |
1100 * If "headp" not NULL, set *headp to the size of what we for 'showbreak' | 1100 * If "headp" not NULL, set "*headp" to the size of 'showbreak'/'breakindent' |
1101 * string at start of line. Warning: *headp is only set if it's a non-zero | 1101 * included in the return value. |
1102 * value, init to 0 before calling. | 1102 * When "cts->cts_max_head_vcol" is positive, only count in "*headp" the size |
1103 * of 'showbreak'/'breakindent' before "cts->cts_max_head_vcol". | |
1104 * When "cts->cts_max_head_vcol" is negative, only count in "*headp" the size | |
1105 * of 'showbreak'/'breakindent' before where cursor should be placed. | |
1106 * | |
1107 * Warning: "*headp" may not be set if it's 0, init to 0 before calling. | |
1103 */ | 1108 */ |
1104 int | 1109 int |
1105 win_lbr_chartabsize( | 1110 win_lbr_chartabsize( |
1106 chartabsize_T *cts, | 1111 chartabsize_T *cts, |
1107 int *headp UNUSED) | 1112 int *headp UNUSED) |
1116 int c; | 1121 int c; |
1117 int size; | 1122 int size; |
1118 colnr_T col2; | 1123 colnr_T col2; |
1119 colnr_T col_adj = 0; // vcol + screen size of tab | 1124 colnr_T col_adj = 0; // vcol + screen size of tab |
1120 colnr_T colmax; | 1125 colnr_T colmax; |
1121 int added; | |
1122 int mb_added = 0; | 1126 int mb_added = 0; |
1123 int numberextra; | |
1124 char_u *ps; | 1127 char_u *ps; |
1125 int tab_corr = (*s == TAB); | 1128 int tab_corr = (*s == TAB); |
1126 int n; | 1129 int n; |
1127 char_u *sbr; | 1130 char_u *sbr; |
1128 int no_sbr = FALSE; | 1131 int no_sbr = FALSE; |
1254 { | 1257 { |
1255 /* | 1258 /* |
1256 * Count all characters from first non-blank after a blank up to next | 1259 * Count all characters from first non-blank after a blank up to next |
1257 * non-blank after a blank. | 1260 * non-blank after a blank. |
1258 */ | 1261 */ |
1259 numberextra = win_col_off(wp); | 1262 int numberextra = win_col_off(wp); |
1260 col2 = vcol; | 1263 col2 = vcol; |
1261 colmax = (colnr_T)(wp->w_width - numberextra - col_adj); | 1264 colmax = (colnr_T)(wp->w_width - numberextra - col_adj); |
1262 if (vcol >= colmax) | 1265 if (vcol >= colmax) |
1263 { | 1266 { |
1264 colmax += col_adj; | 1267 colmax += col_adj; |
1294 } | 1297 } |
1295 | 1298 |
1296 /* | 1299 /* |
1297 * May have to add something for 'breakindent' and/or 'showbreak' | 1300 * May have to add something for 'breakindent' and/or 'showbreak' |
1298 * string at start of line. | 1301 * string at start of line. |
1299 * Set *headp to the size of what we add. | |
1300 * Do not use 'showbreak' at the NUL after the text. | 1302 * Do not use 'showbreak' at the NUL after the text. |
1301 */ | 1303 */ |
1302 added = 0; | 1304 int head = mb_added; |
1303 sbr = (c == NUL || no_sbr) ? empty_option : get_showbreak_value(wp); | 1305 sbr = (c == NUL || no_sbr) ? empty_option : get_showbreak_value(wp); |
1304 if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) | 1306 if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap) |
1305 { | 1307 { |
1306 colnr_T sbrlen = 0; | 1308 int col_off_prev = win_col_off(wp); |
1307 int numberwidth = win_col_off(wp); | 1309 int width2 = wp->w_width - col_off_prev + win_col_off2(wp); |
1308 | 1310 vcol += mb_added; |
1309 numberextra = numberwidth; | |
1310 vcol += numberextra + mb_added; | |
1311 #ifdef FEAT_PROP_POPUP | 1311 #ifdef FEAT_PROP_POPUP |
1312 vcol -= wp->w_virtcol_first_char; | 1312 vcol -= wp->w_virtcol_first_char; |
1313 #endif | 1313 #endif |
1314 if (vcol >= (colnr_T)wp->w_width) | 1314 colnr_T wcol = vcol + col_off_prev; |
1315 { | 1315 // cells taken by 'showbreak'/'breakindent' before current char |
1316 vcol -= wp->w_width; | 1316 int head_prev = 0; |
1317 numberextra = wp->w_width - (numberextra - win_col_off2(wp)); | 1317 if (wcol >= wp->w_width) |
1318 if (vcol >= numberextra && numberextra > 0) | 1318 { |
1319 vcol %= numberextra; | 1319 wcol -= wp->w_width; |
1320 col_off_prev = wp->w_width - width2; | |
1321 if (wcol >= width2 && width2 > 0) | |
1322 wcol %= width2; | |
1320 if (*sbr != NUL) | 1323 if (*sbr != NUL) |
1321 { | 1324 head_prev += vim_strsize(sbr); |
1322 sbrlen = (colnr_T)MB_CHARLEN(sbr); | 1325 if (wp->w_p_bri) |
1323 if (vcol >= sbrlen) | 1326 head_prev += get_breakindent_win(wp, line); |
1324 vcol -= sbrlen; | 1327 if (wcol < head_prev) |
1325 } | 1328 wcol = head_prev; |
1326 if (vcol >= numberextra && numberextra > 0) | 1329 wcol += col_off_prev; |
1327 vcol = vcol % numberextra; | 1330 } |
1328 else if (vcol > 0 && numberextra > 0) | 1331 |
1329 vcol += numberwidth - win_col_off2(wp); | 1332 if ((vcol > 0 && wcol == col_off_prev + head_prev) |
1330 | 1333 || wcol + size > wp->w_width) |
1331 numberwidth -= win_col_off2(wp); | 1334 { |
1332 } | 1335 int added = 0; |
1333 if (vcol == 0 || vcol + size + sbrlen > (colnr_T)wp->w_width) | 1336 colnr_T max_head_vcol = cts->cts_max_head_vcol; |
1334 { | 1337 |
1335 added = 0; | 1338 if (vcol > 0 && wcol == col_off_prev + head_prev) |
1339 { | |
1340 added += head_prev; | |
1341 if (max_head_vcol <= 0 || vcol < max_head_vcol) | |
1342 head += head_prev; | |
1343 } | |
1344 | |
1345 // cells taken by 'showbreak'/'breakindent' halfway current char | |
1346 int head_mid = 0; | |
1336 if (*sbr != NUL) | 1347 if (*sbr != NUL) |
1337 { | 1348 head_mid += vim_strsize(sbr); |
1338 if (size + sbrlen + numberwidth > (colnr_T)wp->w_width) | 1349 if (wp->w_p_bri) |
1350 head_mid += get_breakindent_win(wp, line); | |
1351 if (head_mid > 0) | |
1352 { | |
1353 if (wcol + size > wp->w_width) | |
1339 { | 1354 { |
1340 // calculate effective window width | 1355 // calculate effective window width |
1341 int width = (colnr_T)wp->w_width - sbrlen - numberwidth; | 1356 int prev_rem = wp->w_width - wcol; |
1342 int prev_width = vcol | 1357 int width = width2 - head_mid; |
1343 ? ((colnr_T)wp->w_width - (sbrlen + vcol)) : 0; | |
1344 | 1358 |
1345 if (width <= 0) | 1359 if (width <= 0) |
1346 width = (colnr_T)1; | 1360 width = 1; |
1347 added += ((size - prev_width) / width) * vim_strsize(sbr); | 1361 // divide "size - prev_width" by "width", rounding up |
1348 if ((size - prev_width) % width) | 1362 int cnt = (size - prev_rem + width - 1) / width; |
1349 // wrapped, add another length of 'sbr' | 1363 added += cnt * head_mid; |
1350 added += vim_strsize(sbr); | 1364 |
1365 if (max_head_vcol == 0 | |
1366 || vcol + size + added < max_head_vcol) | |
1367 head += cnt * head_mid; | |
1368 else if (max_head_vcol > vcol + head_prev + prev_rem) | |
1369 head += (max_head_vcol - (vcol + head_prev + prev_rem) | |
1370 + width2 - 1) / width2 * head_mid; | |
1371 #ifdef FEAT_PROP_POPUP | |
1372 else if (max_head_vcol < 0) | |
1373 { | |
1374 int off = 0; | |
1375 if ((State & MODE_NORMAL) || cts->cts_start_incl) | |
1376 off += cts->cts_cur_text_width; | |
1377 if (off >= prev_rem) | |
1378 head += (1 + (off - prev_rem) / width) * head_mid; | |
1379 } | |
1380 #endif | |
1351 } | 1381 } |
1352 else | 1382 } |
1353 added += vim_strsize(sbr); | |
1354 } | |
1355 if (wp->w_p_bri) | |
1356 added += get_breakindent_win(wp, line); | |
1357 | 1383 |
1358 size += added; | 1384 size += added; |
1359 if (vcol != 0) | |
1360 added = 0; | |
1361 } | 1385 } |
1362 } | 1386 } |
1363 if (headp != NULL) | 1387 if (headp != NULL) |
1364 *headp = added + mb_added; | 1388 *headp = head; |
1365 return size; | 1389 return size; |
1366 # endif | 1390 # endif |
1367 #endif | 1391 #endif |
1368 } | 1392 } |
1369 | 1393 |
1481 // always start on the first byte | 1505 // always start on the first byte |
1482 posptr -= (*mb_head_off)(line, posptr); | 1506 posptr -= (*mb_head_off)(line, posptr); |
1483 } | 1507 } |
1484 | 1508 |
1485 init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); | 1509 init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); |
1510 cts.cts_max_head_vcol = -1; | |
1486 | 1511 |
1487 /* | 1512 /* |
1488 * This function is used very often, do some speed optimizations. | 1513 * This function is used very often, do some speed optimizations. |
1489 * When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set | 1514 * When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set |
1490 * and there are no text properties with "text" use a simple loop. | 1515 * and there are no text properties with "text" use a simple loop. |