comparison src/ops.c @ 20237:918245588b50 v8.2.0674

patch 8.2.0674: some source files are too big Commit: https://github.com/vim/vim/commit/11abd095210fc84e5dcee87b9baed86061caefe4 Author: Bram Moolenaar <Bram@vim.org> Date: Fri May 1 14:26:37 2020 +0200 patch 8.2.0674: some source files are too big Problem: Some source files are too big. Solution: Move text formatting functions to a new file. (Yegappan Lakshmanan, closes #6021)
author Bram Moolenaar <Bram@vim.org>
date Fri, 01 May 2020 14:30:04 +0200
parents aadd1cae2ff5
children d067be761cd7
comparison
equal deleted inserted replaced
20236:366b1c4f8c49 20237:918245588b50
15 #include "vim.h" 15 #include "vim.h"
16 16
17 static void shift_block(oparg_T *oap, int amount); 17 static void shift_block(oparg_T *oap, int amount);
18 static void mb_adjust_opend(oparg_T *oap); 18 static void mb_adjust_opend(oparg_T *oap);
19 static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1); 19 static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1);
20 static int ends_in_white(linenr_T lnum);
21 static int fmt_check_par(linenr_T, int *, char_u **, int do_comments);
22 20
23 // Flags for third item in "opchars". 21 // Flags for third item in "opchars".
24 #define OPF_LINES 1 // operator always works on lines 22 #define OPF_LINES 1 // operator always works on lines
25 #define OPF_CHANGE 2 // operator changes text 23 #define OPF_CHANGE 2 // operator changes text
26 24
589 587
590 State = oldstate; 588 State = oldstate;
591 } 589 }
592 590
593 /* 591 /*
594 * Stuff a string into the typeahead buffer, such that edit() will insert it
595 * literally ("literally" TRUE) or interpret is as typed characters.
596 */
597 void
598 stuffescaped(char_u *arg, int literally)
599 {
600 int c;
601 char_u *start;
602
603 while (*arg != NUL)
604 {
605 // Stuff a sequence of normal ASCII characters, that's fast. Also
606 // stuff K_SPECIAL to get the effect of a special key when "literally"
607 // is TRUE.
608 start = arg;
609 while ((*arg >= ' '
610 #ifndef EBCDIC
611 && *arg < DEL // EBCDIC: chars above space are normal
612 #endif
613 )
614 || (*arg == K_SPECIAL && !literally))
615 ++arg;
616 if (arg > start)
617 stuffReadbuffLen(start, (long)(arg - start));
618
619 // stuff a single special character
620 if (*arg != NUL)
621 {
622 if (has_mbyte)
623 c = mb_cptr2char_adv(&arg);
624 else
625 c = *arg++;
626 if (literally && ((c < ' ' && c != TAB) || c == DEL))
627 stuffcharReadbuff(Ctrl_V);
628 stuffcharReadbuff(c);
629 }
630 }
631 }
632
633 /*
634 * Handle a delete operation. 592 * Handle a delete operation.
635 * 593 *
636 * Return FAIL if undo failed, OK otherwise. 594 * Return FAIL if undo failed, OK otherwise.
637 */ 595 */
638 int 596 int
2169 vim_free(comments); 2127 vim_free(comments);
2170 return ret; 2128 return ret;
2171 } 2129 }
2172 2130
2173 /* 2131 /*
2174 * Return TRUE if the two comment leaders given are the same. "lnum" is
2175 * the first line. White-space is ignored. Note that the whole of
2176 * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
2177 */
2178 static int
2179 same_leader(
2180 linenr_T lnum,
2181 int leader1_len,
2182 char_u *leader1_flags,
2183 int leader2_len,
2184 char_u *leader2_flags)
2185 {
2186 int idx1 = 0, idx2 = 0;
2187 char_u *p;
2188 char_u *line1;
2189 char_u *line2;
2190
2191 if (leader1_len == 0)
2192 return (leader2_len == 0);
2193
2194 /*
2195 * If first leader has 'f' flag, the lines can be joined only if the
2196 * second line does not have a leader.
2197 * If first leader has 'e' flag, the lines can never be joined.
2198 * If fist leader has 's' flag, the lines can only be joined if there is
2199 * some text after it and the second line has the 'm' flag.
2200 */
2201 if (leader1_flags != NULL)
2202 {
2203 for (p = leader1_flags; *p && *p != ':'; ++p)
2204 {
2205 if (*p == COM_FIRST)
2206 return (leader2_len == 0);
2207 if (*p == COM_END)
2208 return FALSE;
2209 if (*p == COM_START)
2210 {
2211 if (*(ml_get(lnum) + leader1_len) == NUL)
2212 return FALSE;
2213 if (leader2_flags == NULL || leader2_len == 0)
2214 return FALSE;
2215 for (p = leader2_flags; *p && *p != ':'; ++p)
2216 if (*p == COM_MIDDLE)
2217 return TRUE;
2218 return FALSE;
2219 }
2220 }
2221 }
2222
2223 /*
2224 * Get current line and next line, compare the leaders.
2225 * The first line has to be saved, only one line can be locked at a time.
2226 */
2227 line1 = vim_strsave(ml_get(lnum));
2228 if (line1 != NULL)
2229 {
2230 for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1)
2231 ;
2232 line2 = ml_get(lnum + 1);
2233 for (idx2 = 0; idx2 < leader2_len; ++idx2)
2234 {
2235 if (!VIM_ISWHITE(line2[idx2]))
2236 {
2237 if (line1[idx1++] != line2[idx2])
2238 break;
2239 }
2240 else
2241 while (VIM_ISWHITE(line1[idx1]))
2242 ++idx1;
2243 }
2244 vim_free(line1);
2245 }
2246 return (idx2 == leader2_len && idx1 == leader1_len);
2247 }
2248
2249 /*
2250 * Implementation of the format operator 'gq'.
2251 */
2252 static void
2253 op_format(
2254 oparg_T *oap,
2255 int keep_cursor) // keep cursor on same text char
2256 {
2257 long old_line_count = curbuf->b_ml.ml_line_count;
2258
2259 // Place the cursor where the "gq" or "gw" command was given, so that "u"
2260 // can put it back there.
2261 curwin->w_cursor = oap->cursor_start;
2262
2263 if (u_save((linenr_T)(oap->start.lnum - 1),
2264 (linenr_T)(oap->end.lnum + 1)) == FAIL)
2265 return;
2266 curwin->w_cursor = oap->start;
2267
2268 if (oap->is_VIsual)
2269 // When there is no change: need to remove the Visual selection
2270 redraw_curbuf_later(INVERTED);
2271
2272 if (!cmdmod.lockmarks)
2273 // Set '[ mark at the start of the formatted area
2274 curbuf->b_op_start = oap->start;
2275
2276 // For "gw" remember the cursor position and put it back below (adjusted
2277 // for joined and split lines).
2278 if (keep_cursor)
2279 saved_cursor = oap->cursor_start;
2280
2281 format_lines(oap->line_count, keep_cursor);
2282
2283 /*
2284 * Leave the cursor at the first non-blank of the last formatted line.
2285 * If the cursor was moved one line back (e.g. with "Q}") go to the next
2286 * line, so "." will do the next lines.
2287 */
2288 if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2289 ++curwin->w_cursor.lnum;
2290 beginline(BL_WHITE | BL_FIX);
2291 old_line_count = curbuf->b_ml.ml_line_count - old_line_count;
2292 msgmore(old_line_count);
2293
2294 if (!cmdmod.lockmarks)
2295 // put '] mark on the end of the formatted area
2296 curbuf->b_op_end = curwin->w_cursor;
2297
2298 if (keep_cursor)
2299 {
2300 curwin->w_cursor = saved_cursor;
2301 saved_cursor.lnum = 0;
2302 }
2303
2304 if (oap->is_VIsual)
2305 {
2306 win_T *wp;
2307
2308 FOR_ALL_WINDOWS(wp)
2309 {
2310 if (wp->w_old_cursor_lnum != 0)
2311 {
2312 // When lines have been inserted or deleted, adjust the end of
2313 // the Visual area to be redrawn.
2314 if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum)
2315 wp->w_old_cursor_lnum += old_line_count;
2316 else
2317 wp->w_old_visual_lnum += old_line_count;
2318 }
2319 }
2320 }
2321 }
2322
2323 #if defined(FEAT_EVAL) || defined(PROTO)
2324 /*
2325 * Implementation of the format operator 'gq' for when using 'formatexpr'.
2326 */
2327 static void
2328 op_formatexpr(oparg_T *oap)
2329 {
2330 if (oap->is_VIsual)
2331 // When there is no change: need to remove the Visual selection
2332 redraw_curbuf_later(INVERTED);
2333
2334 if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0)
2335 // As documented: when 'formatexpr' returns non-zero fall back to
2336 // internal formatting.
2337 op_format(oap, FALSE);
2338 }
2339
2340 int
2341 fex_format(
2342 linenr_T lnum,
2343 long count,
2344 int c) // character to be inserted
2345 {
2346 int use_sandbox = was_set_insecurely((char_u *)"formatexpr",
2347 OPT_LOCAL);
2348 int r;
2349 char_u *fex;
2350
2351 /*
2352 * Set v:lnum to the first line number and v:count to the number of lines.
2353 * Set v:char to the character to be inserted (can be NUL).
2354 */
2355 set_vim_var_nr(VV_LNUM, lnum);
2356 set_vim_var_nr(VV_COUNT, count);
2357 set_vim_var_char(c);
2358
2359 // Make a copy, the option could be changed while calling it.
2360 fex = vim_strsave(curbuf->b_p_fex);
2361 if (fex == NULL)
2362 return 0;
2363
2364 /*
2365 * Evaluate the function.
2366 */
2367 if (use_sandbox)
2368 ++sandbox;
2369 r = (int)eval_to_number(fex);
2370 if (use_sandbox)
2371 --sandbox;
2372
2373 set_vim_var_string(VV_CHAR, NULL, -1);
2374 vim_free(fex);
2375
2376 return r;
2377 }
2378 #endif
2379
2380 /*
2381 * Format "line_count" lines, starting at the cursor position.
2382 * When "line_count" is negative, format until the end of the paragraph.
2383 * Lines after the cursor line are saved for undo, caller must have saved the
2384 * first line.
2385 */
2386 void
2387 format_lines(
2388 linenr_T line_count,
2389 int avoid_fex) // don't use 'formatexpr'
2390 {
2391 int max_len;
2392 int is_not_par; // current line not part of parag.
2393 int next_is_not_par; // next line not part of paragraph
2394 int is_end_par; // at end of paragraph
2395 int prev_is_end_par = FALSE;// prev. line not part of parag.
2396 int next_is_start_par = FALSE;
2397 int leader_len = 0; // leader len of current line
2398 int next_leader_len; // leader len of next line
2399 char_u *leader_flags = NULL; // flags for leader of current line
2400 char_u *next_leader_flags; // flags for leader of next line
2401 int do_comments; // format comments
2402 int do_comments_list = 0; // format comments with 'n' or '2'
2403 int advance = TRUE;
2404 int second_indent = -1; // indent for second line (comment
2405 // aware)
2406 int do_second_indent;
2407 int do_number_indent;
2408 int do_trail_white;
2409 int first_par_line = TRUE;
2410 int smd_save;
2411 long count;
2412 int need_set_indent = TRUE; // set indent of next paragraph
2413 int force_format = FALSE;
2414 int old_State = State;
2415
2416 // length of a line to force formatting: 3 * 'tw'
2417 max_len = comp_textwidth(TRUE) * 3;
2418
2419 // check for 'q', '2' and '1' in 'formatoptions'
2420 do_comments = has_format_option(FO_Q_COMS);
2421 do_second_indent = has_format_option(FO_Q_SECOND);
2422 do_number_indent = has_format_option(FO_Q_NUMBER);
2423 do_trail_white = has_format_option(FO_WHITE_PAR);
2424
2425 /*
2426 * Get info about the previous and current line.
2427 */
2428 if (curwin->w_cursor.lnum > 1)
2429 is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1
2430 , &leader_len, &leader_flags, do_comments);
2431 else
2432 is_not_par = TRUE;
2433 next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
2434 , &next_leader_len, &next_leader_flags, do_comments);
2435 is_end_par = (is_not_par || next_is_not_par);
2436 if (!is_end_par && do_trail_white)
2437 is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1);
2438
2439 curwin->w_cursor.lnum--;
2440 for (count = line_count; count != 0 && !got_int; --count)
2441 {
2442 /*
2443 * Advance to next paragraph.
2444 */
2445 if (advance)
2446 {
2447 curwin->w_cursor.lnum++;
2448 prev_is_end_par = is_end_par;
2449 is_not_par = next_is_not_par;
2450 leader_len = next_leader_len;
2451 leader_flags = next_leader_flags;
2452 }
2453
2454 /*
2455 * The last line to be formatted.
2456 */
2457 if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
2458 {
2459 next_is_not_par = TRUE;
2460 next_leader_len = 0;
2461 next_leader_flags = NULL;
2462 }
2463 else
2464 {
2465 next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1
2466 , &next_leader_len, &next_leader_flags, do_comments);
2467 if (do_number_indent)
2468 next_is_start_par =
2469 (get_number_indent(curwin->w_cursor.lnum + 1) > 0);
2470 }
2471 advance = TRUE;
2472 is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
2473 if (!is_end_par && do_trail_white)
2474 is_end_par = !ends_in_white(curwin->w_cursor.lnum);
2475
2476 /*
2477 * Skip lines that are not in a paragraph.
2478 */
2479 if (is_not_par)
2480 {
2481 if (line_count < 0)
2482 break;
2483 }
2484 else
2485 {
2486 /*
2487 * For the first line of a paragraph, check indent of second line.
2488 * Don't do this for comments and empty lines.
2489 */
2490 if (first_par_line
2491 && (do_second_indent || do_number_indent)
2492 && prev_is_end_par
2493 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2494 {
2495 if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1))
2496 {
2497 if (leader_len == 0 && next_leader_len == 0)
2498 {
2499 // no comment found
2500 second_indent =
2501 get_indent_lnum(curwin->w_cursor.lnum + 1);
2502 }
2503 else
2504 {
2505 second_indent = next_leader_len;
2506 do_comments_list = 1;
2507 }
2508 }
2509 else if (do_number_indent)
2510 {
2511 if (leader_len == 0 && next_leader_len == 0)
2512 {
2513 // no comment found
2514 second_indent =
2515 get_number_indent(curwin->w_cursor.lnum);
2516 }
2517 else
2518 {
2519 // get_number_indent() is now "comment aware"...
2520 second_indent =
2521 get_number_indent(curwin->w_cursor.lnum);
2522 do_comments_list = 1;
2523 }
2524 }
2525 }
2526
2527 /*
2528 * When the comment leader changes, it's the end of the paragraph.
2529 */
2530 if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count
2531 || !same_leader(curwin->w_cursor.lnum,
2532 leader_len, leader_flags,
2533 next_leader_len, next_leader_flags))
2534 is_end_par = TRUE;
2535
2536 /*
2537 * If we have got to the end of a paragraph, or the line is
2538 * getting long, format it.
2539 */
2540 if (is_end_par || force_format)
2541 {
2542 if (need_set_indent)
2543 // replace indent in first line with minimal number of
2544 // tabs and spaces, according to current options
2545 (void)set_indent(get_indent(), SIN_CHANGED);
2546
2547 // put cursor on last non-space
2548 State = NORMAL; // don't go past end-of-line
2549 coladvance((colnr_T)MAXCOL);
2550 while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
2551 dec_cursor();
2552
2553 // do the formatting, without 'showmode'
2554 State = INSERT; // for open_line()
2555 smd_save = p_smd;
2556 p_smd = FALSE;
2557 insertchar(NUL, INSCHAR_FORMAT
2558 + (do_comments ? INSCHAR_DO_COM : 0)
2559 + (do_comments && do_comments_list
2560 ? INSCHAR_COM_LIST : 0)
2561 + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
2562 State = old_State;
2563 p_smd = smd_save;
2564 second_indent = -1;
2565 // at end of par.: need to set indent of next par.
2566 need_set_indent = is_end_par;
2567 if (is_end_par)
2568 {
2569 // When called with a negative line count, break at the
2570 // end of the paragraph.
2571 if (line_count < 0)
2572 break;
2573 first_par_line = TRUE;
2574 }
2575 force_format = FALSE;
2576 }
2577
2578 /*
2579 * When still in same paragraph, join the lines together. But
2580 * first delete the leader from the second line.
2581 */
2582 if (!is_end_par)
2583 {
2584 advance = FALSE;
2585 curwin->w_cursor.lnum++;
2586 curwin->w_cursor.col = 0;
2587 if (line_count < 0 && u_save_cursor() == FAIL)
2588 break;
2589 if (next_leader_len > 0)
2590 {
2591 (void)del_bytes((long)next_leader_len, FALSE, FALSE);
2592 mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
2593 (long)-next_leader_len, 0);
2594 }
2595 else if (second_indent > 0) // the "leader" for FO_Q_SECOND
2596 {
2597 int indent = getwhitecols_curline();
2598
2599 if (indent > 0)
2600 {
2601 (void)del_bytes(indent, FALSE, FALSE);
2602 mark_col_adjust(curwin->w_cursor.lnum,
2603 (colnr_T)0, 0L, (long)-indent, 0);
2604 }
2605 }
2606 curwin->w_cursor.lnum--;
2607 if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL)
2608 {
2609 beep_flush();
2610 break;
2611 }
2612 first_par_line = FALSE;
2613 // If the line is getting long, format it next time
2614 if (STRLEN(ml_get_curline()) > (size_t)max_len)
2615 force_format = TRUE;
2616 else
2617 force_format = FALSE;
2618 }
2619 }
2620 line_breakcheck();
2621 }
2622 }
2623
2624 /*
2625 * Return TRUE if line "lnum" ends in a white character.
2626 */
2627 static int
2628 ends_in_white(linenr_T lnum)
2629 {
2630 char_u *s = ml_get(lnum);
2631 size_t l;
2632
2633 if (*s == NUL)
2634 return FALSE;
2635 // Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro
2636 // invocation may call function multiple times".
2637 l = STRLEN(s) - 1;
2638 return VIM_ISWHITE(s[l]);
2639 }
2640
2641 /*
2642 * Blank lines, and lines containing only the comment leader, are left
2643 * untouched by the formatting. The function returns TRUE in this
2644 * case. It also returns TRUE when a line starts with the end of a comment
2645 * ('e' in comment flags), so that this line is skipped, and not joined to the
2646 * previous line. A new paragraph starts after a blank line, or when the
2647 * comment leader changes -- webb.
2648 */
2649 static int
2650 fmt_check_par(
2651 linenr_T lnum,
2652 int *leader_len,
2653 char_u **leader_flags,
2654 int do_comments)
2655 {
2656 char_u *flags = NULL; // init for GCC
2657 char_u *ptr;
2658
2659 ptr = ml_get(lnum);
2660 if (do_comments)
2661 *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE);
2662 else
2663 *leader_len = 0;
2664
2665 if (*leader_len > 0)
2666 {
2667 /*
2668 * Search for 'e' flag in comment leader flags.
2669 */
2670 flags = *leader_flags;
2671 while (*flags && *flags != ':' && *flags != COM_END)
2672 ++flags;
2673 }
2674
2675 return (*skipwhite(ptr + *leader_len) == NUL
2676 || (*leader_len > 0 && *flags == COM_END)
2677 || startPS(lnum, NUL, FALSE));
2678 }
2679
2680 /*
2681 * Return TRUE when a paragraph starts in line "lnum". Return FALSE when the
2682 * previous line is in the same paragraph. Used for auto-formatting.
2683 */
2684 int
2685 paragraph_start(linenr_T lnum)
2686 {
2687 char_u *p;
2688 int leader_len = 0; // leader len of current line
2689 char_u *leader_flags = NULL; // flags for leader of current line
2690 int next_leader_len; // leader len of next line
2691 char_u *next_leader_flags; // flags for leader of next line
2692 int do_comments; // format comments
2693
2694 if (lnum <= 1)
2695 return TRUE; // start of the file
2696
2697 p = ml_get(lnum - 1);
2698 if (*p == NUL)
2699 return TRUE; // after empty line
2700
2701 do_comments = has_format_option(FO_Q_COMS);
2702 if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments))
2703 return TRUE; // after non-paragraph line
2704
2705 if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments))
2706 return TRUE; // "lnum" is not a paragraph line
2707
2708 if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1))
2709 return TRUE; // missing trailing space in previous line.
2710
2711 if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0))
2712 return TRUE; // numbered item starts in "lnum".
2713
2714 if (!same_leader(lnum - 1, leader_len, leader_flags,
2715 next_leader_len, next_leader_flags))
2716 return TRUE; // change of comment leader.
2717
2718 return FALSE;
2719 }
2720
2721 /*
2722 * prepare a few things for block mode yank/delete/tilde 2132 * prepare a few things for block mode yank/delete/tilde
2723 * 2133 *
2724 * for delete: 2134 * for delete:
2725 * - textlen includes the first/last char to be (partly) deleted 2135 * - textlen includes the first/last char to be (partly) deleted
2726 * - start/endspaces is the number of columns that are taken by the 2136 * - start/endspaces is the number of columns that are taken by the