Repository: neovim/neovim
File: src/nvim/ex_cmds.c (C)

Code before:
  for (linenr_T lnum = eap->line1;
       lnum <= line2 && !got_quit && !aborting()
       && (cmdpreview_ns <= 0 || preview_lines.lines_needed <= (linenr_T)p_cwh
           || lnum <= curwin->w_botline);
       lnum++) {
    int nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
                                   0, NULL, NULL);
    if (nmatch) {
      colnr_T copycol;
      colnr_T matchcol;
      colnr_T prev_matchcol = MAXCOL;
      char *new_end;
      char *new_start = NULL;
      int new_start_len = 0;
      char *p1;
      bool did_sub = false;
      int lastone;
      linenr_T nmatch_tl = 0;               // nr of lines matched below lnum
      int do_again;                     // do it again after joining lines
      bool skip_match = false;
      linenr_T sub_firstlnum;           // nr of first sub line

      // Track where substitutions started (set once per line).
      linenr_T lnum_start = 0;

      // Track extmark_splice data for each match in the line.
      typedef struct {
        int start_col;         // Position in new text where replacement goes
        lpos_T start;          // Match start position in original text
        lpos_T end;            // Match end position in original text
        int matchcols;         // Columns deleted from original text
        bcount_t matchbytes;   // Bytes deleted from original text
        int subcols;           // Columns in replacement text
        bcount_t subbytes;     // Bytes in replacement text
        linenr_T lnum_before;  // Line number before this substitution
        linenr_T lnum_after;   // Line number after this substitution
      } MatchExtmarkData;

      kvec_t(MatchExtmarkData) match_extmarks = KV_INITIAL_VALUE;

      // The new text is build up step by step, to avoid too much
      // copying.  There are these pieces:
      // sub_firstline  The old text, unmodified.
      // copycol                Column in the old text where we started
      //                        looking for a match; from here old text still
      //                        needs to be copied to the new text.
      // matchcol               Column number of the old text where to look
      //                        for the next match.  It's just after the
      //                        previous match or one further.
      // prev_matchcol  Column just after the previous match (if any).
      //                        Mostly equal to matchcol, except for the first

Review comment (performance):
```suggestion
      // Track per-line data for each match.
      // Will be sent as a batch to `extmark_splice` after the substitution is done.
```

Code after:
  for (linenr_T lnum = eap->line1;
       lnum <= line2 && !got_quit && !aborting()
       && (cmdpreview_ns <= 0 || preview_lines.lines_needed <= (linenr_T)p_cwh
           || lnum <= curwin->w_botline);
       lnum++) {
    int nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
                                   0, NULL, NULL);
    if (nmatch) {
      colnr_T copycol;
      colnr_T matchcol;
      colnr_T prev_matchcol = MAXCOL;
      char *new_end;
      char *new_start = NULL;
      int new_start_len = 0;
      char *p1;
      bool did_sub = false;
      int lastone;
      linenr_T nmatch_tl = 0;               // nr of lines matched below lnum
      int do_again;                     // do it again after joining lines
      bool skip_match = false;
      linenr_T sub_firstlnum;           // nr of first sub line

      // Track where substitutions started (set once per line).
      linenr_T lnum_start = 0;

      // Track per-line data for each match.
      // Will be sent as a batch to `extmark_splice` after the substitution is done.
      typedef struct {
        int start_col;         // Position in new text where replacement goes
        lpos_T start;          // Match start position in original text
        lpos_T end;            // Match end position in original text
        int matchcols;         // Columns deleted from original text
        bcount_t matchbytes;   // Bytes deleted from original text
        int subcols;           // Columns in replacement text
        bcount_t subbytes;     // Bytes in replacement text
        linenr_T lnum_before;  // Line number before this substitution
        linenr_T lnum_after;   // Line number after this substitution
      } LineData;

      kvec_t(LineData) line_matches = KV_INITIAL_VALUE;

      // The new text is build up step by step, to avoid too much
      // copying.  There are these pieces:
      // sub_firstline  The old text, unmodified.
      // copycol                Column in the old text where we started
      //                        looking for a match; from here old text still
      //                        needs to be copied to the new text.
      // matchcol               Column number of the old text where to look
      //                        for the next match.  It's just after the
      //                        previous match or one further.
      // prev_matchcol  Column just after the previous match (if any).