diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/fold.c | |
parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.gz rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.bz2 rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.zip |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/fold.c')
-rw-r--r-- | src/nvim/fold.c | 169 |
1 files changed, 103 insertions, 66 deletions
diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 7306131574..c905b2d3ed 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // vim: set fdm=marker fdl=1 fdc=3 // fold.c: code for folding @@ -12,21 +9,27 @@ #include <stdlib.h> #include <string.h> -#include "nvim/ascii.h" +#include "klib/kvec.h" +#include "nvim/api/extmark.h" +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/buffer_updates.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/ex_session.h" #include "nvim/extmark.h" #include "nvim/fold.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/indent.h" @@ -37,15 +40,17 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/ops.h" -#include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/os/input.h" #include "nvim/plines.h" +#include "nvim/pos_defs.h" #include "nvim/search.h" +#include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/syntax.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/undo.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" // local declarations. {{{1 // typedef fold_T {{{2 @@ -101,12 +106,12 @@ typedef void (*LevelGetter)(fline_T *); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "fold.c.generated.h" #endif -static char *e_nofold = N_("E490: No fold found"); +static const char *e_nofold = N_("E490: No fold found"); // While updating the folds lines between invalid_top and invalid_bot have an // undefined fold level. Only used for the window currently being updated. -static linenr_T invalid_top = (linenr_T)0; -static linenr_T invalid_bot = (linenr_T)0; +static linenr_T invalid_top = 0; +static linenr_T invalid_bot = 0; // When using 'foldexpr' we sometimes get the level of the next line, which // calls foldlevel() to get the level of the current line, which hasn't been @@ -201,7 +206,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp if (first == 0) { // Recursively search for a fold that contains "lnum". garray_T *gap = &win->w_folds; - for (;;) { + while (true) { if (!foldFind(gap, lnum_rel, &fp)) { break; } @@ -263,7 +268,7 @@ static int foldLevel(linenr_T lnum) { // While updating the folds lines between invalid_top and invalid_bot have // an undefined fold level. Otherwise update the folds first. - if (invalid_top == (linenr_T)0) { + if (invalid_top == 0) { checkupdate(curwin); } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { return prev_lnum_lvl; @@ -358,7 +363,7 @@ int foldmethodIsDiff(win_T *wp) // closeFold() {{{2 /// Close fold for current window at position "pos". /// Repeat "count" times. -void closeFold(pos_T pos, long count) +void closeFold(pos_T pos, int count) { setFoldRepeat(pos, count, false); } @@ -412,7 +417,7 @@ void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, int ha // openFold() {{{2 /// Open fold for current window at position "pos". /// Repeat "count" times. -void openFold(pos_T pos, long count) +void openFold(pos_T pos, int count) { setFoldRepeat(pos, count, true); } @@ -430,7 +435,7 @@ void foldOpenCursor(void) { checkupdate(curwin); if (hasAnyFolding(curwin)) { - for (;;) { + while (true) { int done = DONE_NOTHING; (void)setManualFold(curwin->w_cursor, true, false, &done); if (!(done & DONE_ACTION)) { @@ -562,7 +567,7 @@ void foldCreate(win_T *wp, pos_T start, pos_T end) i = 0; } else { fold_T *fp; - for (;;) { + while (true) { if (!foldFind(gap, start_rel.lnum, &fp)) { break; } @@ -645,7 +650,7 @@ void foldCreate(win_T *wp, pos_T start, pos_T end) // We want the new fold to be closed. If it would remain open because // of using 'foldlevel', need to adjust fd_flags of containing folds. if (use_level && !closed && level < wp->w_p_fdl) { - closeFold(start, 1L); + closeFold(start, 1); } if (!use_level) { wp->w_fold_manual = true; @@ -683,7 +688,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const garray_T *found_ga = NULL; linenr_T lnum_off = 0; bool use_level = false; - for (;;) { + while (true) { fold_T *fp; if (!foldFind(gap, lnum - lnum_off, &fp)) { break; @@ -743,8 +748,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const } if (last_lnum > 0) { - // TODO(teto): pass the buffer - changed_lines(first_lnum, (colnr_T)0, last_lnum, 0L, false); + changed_lines(wp->w_buffer, first_lnum, 0, last_lnum, 0, false); // send one nvim_buf_lines_event at the end // last_lnum is the line *after* the last line of the outermost fold @@ -771,7 +775,7 @@ void clearFolding(win_T *win) /// The changes in lines from top to bot (inclusive). void foldUpdate(win_T *wp, linenr_T top, linenr_T bot) { - if (disable_fold_update || State & MODE_INSERT) { + if (disable_fold_update || (State & MODE_INSERT && !foldmethodIsIndent(wp))) { return; } @@ -843,7 +847,7 @@ void foldUpdateAll(win_T *win) /// @return FAIL if not moved. /// /// @param dir FORWARD or BACKWARD -int foldMoveTo(const bool updown, const int dir, const long count) +int foldMoveTo(const bool updown, const int dir, const int count) { int retval = FAIL; linenr_T lnum; @@ -852,7 +856,7 @@ int foldMoveTo(const bool updown, const int dir, const long count) checkupdate(curwin); // Repeat "count" times. - for (long n = 0; n < count; n++) { + for (int n = 0; n < count; n++) { // Find nested folds. Stop when a fold is closed. The deepest fold // that moves the cursor is used. linenr_T lnum_off = 0; @@ -865,7 +869,7 @@ int foldMoveTo(const bool updown, const int dir, const long count) linenr_T lnum_found = curwin->w_cursor.lnum; int level = 0; bool last = false; - for (;;) { + while (true) { if (!foldFind(gap, curwin->w_cursor.lnum - lnum_off, &fp)) { if (!updown || gap->ga_len == 0) { break; @@ -1104,7 +1108,7 @@ static int foldLevelWin(win_T *wp, linenr_T lnum) // Recursively search for a fold that contains "lnum". garray_T *gap = &wp->w_folds; - for (;;) { + while (true) { if (!foldFind(gap, lnum_rel, &fp)) { break; } @@ -1125,14 +1129,14 @@ static void checkupdate(win_T *wp) return; } - foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); // will update all + foldUpdate(wp, 1, (linenr_T)MAXLNUM); // will update all wp->w_foldinvalid = false; } // setFoldRepeat() {{{2 /// Open or close fold for current window at position `pos`. /// Repeat "count" times. -static void setFoldRepeat(pos_T pos, long count, int do_open) +static void setFoldRepeat(pos_T pos, int count, int do_open) { for (int n = 0; n < count; n++) { int done = DONE_NOTHING; @@ -1201,7 +1205,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, int recu // Find the fold, open or close it. garray_T *gap = &wp->w_folds; - for (;;) { + while (true) { if (!foldFind(gap, lnum, &fp)) { // If there is a following fold, continue there next time. if (fp != NULL && fp < (fold_T *)gap->ga_data + gap->ga_len) { @@ -1360,7 +1364,7 @@ void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount, } // If appending a line in Insert mode, it should be included in the fold // just above the line. - if ((State & MODE_INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) { + if ((State & MODE_INSERT) && amount == 1 && line2 == MAXLNUM) { line1--; } foldMarkAdjustRecurse(wp, &wp->w_folds, line1, line2, amount, amount_after); @@ -1378,7 +1382,7 @@ static void foldMarkAdjustRecurse(win_T *wp, garray_T *gap, linenr_T line1, line // In Insert mode an inserted line at the top of a fold is considered part // of the fold, otherwise it isn't. - if ((State & MODE_INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) { + if ((State & MODE_INSERT) && amount == 1 && line2 == MAXLNUM) { top = line1 + 1; } else { top = line1; @@ -1580,8 +1584,7 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end) // Update both changes here, to avoid all folds after the start are // changed when the start marker is inserted and the end isn't. - // TODO(teto): pass the buffer - changed_lines(start.lnum, (colnr_T)0, end.lnum, 0L, false); + changed_lines(buf, start.lnum, 0, end.lnum, 0, false); // Note: foldAddMarker() may not actually change start and/or end if // u_save() is unable to save the buffer line, but we send the @@ -1601,7 +1604,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark linenr_T lnum = pos.lnum; // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end - char *line = ml_get_buf(buf, lnum, false); + char *line = ml_get_buf(buf, lnum); size_t line_len = strlen(line); size_t added = 0; @@ -1661,7 +1664,7 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char *marker, size_t marker } char *cms = buf->b_p_cms; - char *line = ml_get_buf(buf, lnum, false); + char *line = ml_get_buf(buf, lnum); for (char *p = line; *p != NUL; p++) { if (strncmp(p, marker, markerlen) != 0) { continue; @@ -1704,8 +1707,9 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char *marker, size_t marker /// @return the text for a closed fold /// /// Otherwise the result is in allocated memory. -char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo, char *buf) - FUNC_ATTR_NONNULL_ARG(1) +char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo, char *buf, + VirtText *vt) + FUNC_ATTR_NONNULL_ALL { char *text = NULL; // an error occurred when evaluating 'fdt' setting @@ -1742,15 +1746,33 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo set_vim_var_string(VV_FOLDDASHES, dashes, -1); set_vim_var_nr(VV_FOLDLEVEL, (varnumber_T)level); - // skip evaluating foldtext on errors + // skip evaluating 'foldtext' on errors if (!got_fdt_error) { - win_T *save_curwin = curwin; + win_T *const save_curwin = curwin; + const sctx_T saved_sctx = current_sctx; + curwin = wp; curbuf = wp->w_buffer; + current_sctx = wp->w_p_script_ctx[WV_FDT].script_ctx; + + emsg_off++; // handle exceptions, but don't display errors + + Object obj = eval_foldtext(wp); + if (obj.type == kObjectTypeArray) { + Error err = ERROR_INIT; + *vt = parse_virt_text(obj.data.array, &err, NULL); + if (!ERROR_SET(&err)) { + *buf = NUL; + text = buf; + } + api_clear_error(&err); + } else if (obj.type == kObjectTypeString) { + text = obj.data.string.data; + obj = NIL; + } + api_free_object(obj); - emsg_silent++; // handle exceptions, but don't display errors - text = eval_to_string_safe(wp->w_p_fdt, NULL, was_set_insecurely(wp, "foldtext", OPT_LOCAL)); - emsg_silent--; + emsg_off--; if (text == NULL || did_emsg) { got_fdt_error = true; @@ -1758,9 +1780,10 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo curwin = save_curwin; curbuf = curwin->w_buffer; + current_sctx = saved_sctx; } last_lnum = lnum; - last_wp = wp; + last_wp = wp; set_vim_var_string(VV_FOLDDASHES, NULL, -1); if (!did_emsg && save_did_emsg) { @@ -1786,18 +1809,18 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo } } if (*p != NUL) { - p = transstr((const char *)text, true); + p = transstr(text, true); xfree(text); text = p; } } } if (text == NULL) { - long count = lnume - lnum + 1; + int count = lnume - lnum + 1; vim_snprintf(buf, FOLD_TEXT_LEN, - NGETTEXT("+--%3ld line folded", - "+--%3ld lines folded ", count), + NGETTEXT("+--%3d line folded", + "+--%3d lines folded ", count), count); text = buf; } @@ -1888,7 +1911,7 @@ static void foldtext_cleanup(char *str) static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) { // Avoid problems when being called recursively. - if (invalid_top != (linenr_T)0) { + if (invalid_top != 0) { return; } @@ -2109,7 +2132,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) } } - invalid_top = (linenr_T)0; + invalid_top = 0; } // foldUpdateIEMSRecurse() {{{2 @@ -2271,12 +2294,12 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, // We will move the start of this fold up, hence we move all // nested folds (with relative line numbers) down. foldMarkAdjustRecurse(flp->wp, &fp->fd_nested, - (linenr_T)0, (linenr_T)MAXLNUM, - (fp->fd_top - firstlnum), 0L); + 0, (linenr_T)MAXLNUM, + (fp->fd_top - firstlnum), 0); } else { // Will move fold down, move nested folds relatively up. foldMarkAdjustRecurse(flp->wp, &fp->fd_nested, - (linenr_T)0, + 0, (firstlnum - fp->fd_top - 1), (linenr_T)MAXLNUM, (fp->fd_top - firstlnum)); @@ -2344,7 +2367,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, fp->fd_len = startlnum - fp->fd_top; foldMarkAdjustRecurse(flp->wp, &fp->fd_nested, fp->fd_len, (linenr_T)MAXLNUM, - (linenr_T)MAXLNUM, 0L); + (linenr_T)MAXLNUM, 0); fold_changed = true; } } else { @@ -2504,7 +2527,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, } // delete following folds that end before the current line - for (;;) { + while (true) { fp2 = fp + 1; if (fp2 >= (fold_T *)gap->ga_data + gap->ga_len || fp2->fd_top > flp->lnum) { @@ -2514,7 +2537,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, if (fp2->fd_top < flp->lnum) { // Make fold that includes lnum start at lnum. foldMarkAdjustRecurse(flp->wp, &fp2->fd_nested, - (linenr_T)0, (flp->lnum - fp2->fd_top - 1), + 0, (flp->lnum - fp2->fd_top - 1), (linenr_T)MAXLNUM, (fp2->fd_top - flp->lnum)); fp2->fd_len -= flp->lnum - fp2->fd_top; fp2->fd_top = flp->lnum; @@ -2652,7 +2675,7 @@ static void foldRemove(win_T *const wp, garray_T *gap, linenr_T top, linenr_T bo if (fp->fd_top + fp->fd_len - 1 > bot) { // 5: Make fold that includes bot start below bot. foldMarkAdjustRecurse(wp, &fp->fd_nested, - (linenr_T)0, (bot - fp->fd_top), + 0, (bot - fp->fd_top), (linenr_T)MAXLNUM, (fp->fd_top - bot - 1)); fp->fd_len -= bot - fp->fd_top + 1; fp->fd_top = bot + 1; @@ -2718,7 +2741,6 @@ static void truncate_fold(win_T *const wp, fold_T *fp, linenr_T end) } #define FOLD_END(fp) ((fp)->fd_top + (fp)->fd_len - 1) -// -V:VALID_FOLD:V560 #define VALID_FOLD(fp, gap) \ ((gap)->ga_len > 0 && (fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len)) #define FOLD_INDEX(fp, gap) ((size_t)((fp) - ((fold_T *)(gap)->ga_data))) @@ -2838,7 +2860,7 @@ static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2) // If the last nested fold in fp1 touches the first nested fold in fp2, // merge them recursively. - if (foldFind(gap1, fp1->fd_len - 1, &fp3) && foldFind(gap2, 0L, &fp4)) { + if (foldFind(gap1, fp1->fd_len - 1, &fp3) && foldFind(gap2, 0, &fp4)) { foldMerge(wp, fp3, gap2, fp4); } @@ -2869,7 +2891,7 @@ static void foldlevelIndent(fline_T *flp) linenr_T lnum = flp->lnum + flp->off; buf_T *buf = flp->wp->w_buffer; - char *s = skipwhite(ml_get_buf(buf, lnum, false)); + char *s = skipwhite(ml_get_buf(buf, lnum)); // empty line or lines starting with a character in 'foldignore': level // depends on surrounding lines @@ -2926,7 +2948,7 @@ static void foldlevelExpr(fline_T *flp) const bool save_keytyped = KeyTyped; int c; - const int n = eval_foldexpr(flp->wp->w_p_fde, &c); + const int n = eval_foldexpr(flp->wp, &c); KeyTyped = save_keytyped; switch (c) { @@ -3031,7 +3053,7 @@ static void foldlevelMarker(fline_T *flp) flp->start = 0; flp->lvl_next = flp->lvl; - char *s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, false); + char *s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off); while (*s) { if (*s == cstart && strncmp(s + 1, startmarker, foldstartmarkerlen - 1) == 0) { @@ -3109,7 +3131,7 @@ int put_folds(FILE *fd, win_T *wp) { if (foldmethodIsManual(wp)) { if (put_line(fd, "silent! normal! zE") == FAIL - || put_folds_recurse(fd, &wp->w_folds, (linenr_T)0) == FAIL + || put_folds_recurse(fd, &wp->w_folds, 0) == FAIL || put_line(fd, "let &fdl = &fdl") == FAIL) { return FAIL; } @@ -3117,7 +3139,7 @@ int put_folds(FILE *fd, win_T *wp) // If some folds are manually opened/closed, need to restore that. if (wp->w_fold_manual) { - return put_foldopen_recurse(fd, wp, &wp->w_folds, (linenr_T)0); + return put_foldopen_recurse(fd, wp, &wp->w_folds, 0); } return OK; @@ -3281,8 +3303,8 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } } - long count = foldend - foldstart + 1; - char *txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count); + int count = foldend - foldstart + 1; + char *txt = NGETTEXT("+-%s%3d line: ", "+-%s%3d lines: ", count); size_t len = strlen(txt) + strlen(dashes) // for %s + 20 // for %3ld @@ -3317,10 +3339,25 @@ void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) foldinfo_T info = fold_info(curwin, lnum); if (info.fi_lines > 0) { - char *text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf); + VirtText vt = VIRTTEXT_EMPTY; + char *text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf, &vt); if (text == buf) { text = xstrdup(text); } + if (kv_size(vt) > 0) { + assert(*text == NUL); + for (size_t i = 0; i < kv_size(vt);) { + int attr = 0; + char *new_text = next_virt_text_chunk(vt, &i, &attr); + if (new_text == NULL) { + break; + } + new_text = concat_str(text, new_text); + xfree(text); + text = new_text; + } + } + clear_virttext(&vt); rettv->vval.v_string = text; } |