aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/fold.c')
-rw-r--r--src/nvim/fold.c161
1 files changed, 139 insertions, 22 deletions
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 8f26e03a94..b4ddb3ec08 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -14,6 +14,7 @@
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
+#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_session.h"
@@ -31,7 +32,7 @@
#include "nvim/option.h"
#include "nvim/os/input.h"
#include "nvim/plines.h"
-#include "nvim/screen.h"
+#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/undo.h"
@@ -247,7 +248,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp
// foldLevel() {{{2
/// @return fold level at line number "lnum" in the current window.
-int foldLevel(linenr_T lnum)
+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.
@@ -393,7 +394,7 @@ void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, int ha
}
// Force a redraw to remove the Visual highlighting.
if (had_visual) {
- redraw_curbuf_later(INVERTED);
+ redraw_curbuf_later(UPD_INVERTED);
}
}
@@ -720,7 +721,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const
emsg(_(e_nofold));
// Force a redraw to remove the Visual highlighting.
if (had_visual) {
- redraw_buf_later(wp->w_buffer, INVERTED);
+ redraw_buf_later(wp->w_buffer, UPD_INVERTED);
}
} else {
// Deleting markers may make cursor column invalid
@@ -756,7 +757,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 || compl_busy || State & MODE_INSERT) {
+ if (disable_fold_update || State & MODE_INSERT) {
return;
}
@@ -818,7 +819,7 @@ void foldUpdateAfterInsert(void)
void foldUpdateAll(win_T *win)
{
win->w_foldinvalid = true;
- redraw_later(win, NOT_VALID);
+ redraw_later(win, UPD_NOT_VALID);
}
// foldMoveTo() {{{2
@@ -862,7 +863,7 @@ int foldMoveTo(const bool updown, const int dir, const long count)
if (fp - (fold_T *)gap->ga_data >= gap->ga_len) {
break;
}
- --fp;
+ fp--;
} else {
if (fp == (fold_T *)gap->ga_data) {
break;
@@ -1555,7 +1556,7 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
}
parseMarker(wp);
- foldAddMarker(buf, start, wp->w_p_fmr, foldstartmarkerlen);
+ foldAddMarker(buf, start, (char_u *)wp->w_p_fmr, foldstartmarkerlen);
foldAddMarker(buf, end, foldendmarker, foldendmarkerlen);
// Update both changes here, to avoid all folds after the start are
@@ -1574,9 +1575,9 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
/// Add "marker[markerlen]" in 'commentstring' to position `pos`.
static void foldAddMarker(buf_T *buf, pos_T pos, const char_u *marker, size_t markerlen)
{
- char_u *cms = buf->b_p_cms;
+ char_u *cms = (char_u *)buf->b_p_cms;
char_u *newline;
- char_u *p = (char_u *)strstr((char *)buf->b_p_cms, "%s");
+ char_u *p = (char_u *)strstr(buf->b_p_cms, "%s");
bool line_is_comment = false;
linenr_T lnum = pos.lnum;
@@ -1620,7 +1621,7 @@ static void deleteFoldMarkers(win_T *wp, fold_T *fp, int recursive, linenr_T lnu
lnum_off + fp->fd_top);
}
}
- foldDelMarker(wp->w_buffer, fp->fd_top + lnum_off, wp->w_p_fmr,
+ foldDelMarker(wp->w_buffer, fp->fd_top + lnum_off, (char_u *)wp->w_p_fmr,
foldstartmarkerlen);
foldDelMarker(wp->w_buffer, fp->fd_top + lnum_off + fp->fd_len - 1,
foldendmarker, foldendmarkerlen);
@@ -1638,7 +1639,7 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char_u *marker, size_t mark
return;
}
- char_u *cms = buf->b_p_cms;
+ char_u *cms = (char_u *)buf->b_p_cms;
char_u *line = ml_get_buf(buf, lnum, false);
for (char_u *p = line; *p != NUL; p++) {
if (STRNCMP(p, marker, markerlen) != 0) {
@@ -1728,7 +1729,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin
emsg_silent++; // handle exceptions, but don't display errors
text =
- (char_u *)eval_to_string_safe((char *)wp->w_p_fdt, NULL,
+ (char_u *)eval_to_string_safe(wp->w_p_fdt, NULL,
was_set_insecurely(wp, "foldtext", OPT_LOCAL));
emsg_silent--;
@@ -1786,13 +1787,13 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin
// foldtext_cleanup() {{{2
/// Remove 'foldmarker' and 'commentstring' from "str" (in-place).
-void foldtext_cleanup(char_u *str)
+static void foldtext_cleanup(char_u *str)
{
// Ignore leading and trailing white space in 'commentstring'.
- char_u *cms_start = (char_u *)skipwhite((char *)curbuf->b_p_cms);
+ char_u *cms_start = (char_u *)skipwhite(curbuf->b_p_cms);
size_t cms_slen = STRLEN(cms_start);
while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1])) {
- --cms_slen;
+ cms_slen--;
}
// locate "%s" in 'commentstring', use the part before and after it.
@@ -1804,7 +1805,7 @@ void foldtext_cleanup(char_u *str)
// exclude white space before "%s"
while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1])) {
- --cms_slen;
+ cms_slen--;
}
// skip "%s" and white space after it
@@ -2853,7 +2854,7 @@ static void foldlevelIndent(fline_T *flp)
// empty line or lines starting with a character in 'foldignore': level
// depends on surrounding lines
- if (*s == NUL || vim_strchr((char *)flp->wp->w_p_fdi, *s) != NULL) {
+ if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, *s) != NULL) {
// first and last line can't be undefined, use level 0
if (lnum == 1 || lnum == buf->b_ml.ml_line_count) {
flp->lvl = 0;
@@ -2906,7 +2907,7 @@ static void foldlevelExpr(fline_T *flp)
const bool save_keytyped = KeyTyped;
int c;
- const int n = eval_foldexpr((char *)flp->wp->w_p_fde, &c);
+ const int n = eval_foldexpr(flp->wp->w_p_fde, &c);
KeyTyped = save_keytyped;
switch (c) {
@@ -2984,8 +2985,8 @@ static void foldlevelExpr(fline_T *flp)
/// Relies on the option value to have been checked for correctness already.
static void parseMarker(win_T *wp)
{
- foldendmarker = (char_u *)vim_strchr((char *)wp->w_p_fmr, ',');
- foldstartmarkerlen = (size_t)(foldendmarker++ - wp->w_p_fmr);
+ foldendmarker = (char_u *)vim_strchr(wp->w_p_fmr, ',');
+ foldstartmarkerlen = (size_t)(foldendmarker++ - (char_u *)wp->w_p_fmr);
foldendmarkerlen = STRLEN(foldendmarker);
}
@@ -3002,7 +3003,7 @@ static void foldlevelMarker(fline_T *flp)
int start_lvl = flp->lvl;
// cache a few values for speed
- char_u *startmarker = flp->wp->w_p_fmr;
+ char_u *startmarker = (char_u *)flp->wp->w_p_fmr;
int cstart = *startmarker;
startmarker++;
int cend = *foldendmarker;
@@ -3190,3 +3191,119 @@ static int put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off)
}
// }}}1
+
+/// "foldclosed()" and "foldclosedend()" functions
+static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end)
+{
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
+ linenr_T first;
+ linenr_T last;
+ if (hasFoldingWin(curwin, lnum, &first, &last, false, NULL)) {
+ if (end) {
+ rettv->vval.v_number = (varnumber_T)last;
+ } else {
+ rettv->vval.v_number = (varnumber_T)first;
+ }
+ return;
+ }
+ }
+ rettv->vval.v_number = -1;
+}
+
+/// "foldclosed()" function
+void f_foldclosed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ foldclosed_both(argvars, rettv, false);
+}
+
+/// "foldclosedend()" function
+void f_foldclosedend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ foldclosed_both(argvars, rettv, true);
+}
+
+/// "foldlevel()" function
+void f_foldlevel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
+ rettv->vval.v_number = foldLevel(lnum);
+ }
+}
+
+/// "foldtext()" function
+void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ linenr_T foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
+ linenr_T foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
+ char_u *dashes = (char_u *)get_vim_var_str(VV_FOLDDASHES);
+ if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count) {
+ // Find first non-empty line in the fold.
+ linenr_T lnum;
+ for (lnum = foldstart; lnum < foldend; lnum++) {
+ if (!linewhite(lnum)) {
+ break;
+ }
+ }
+
+ // Find interesting text in this line.
+ char_u *s = (char_u *)skipwhite((char *)ml_get(lnum));
+ // skip C comment-start
+ if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) {
+ s = (char_u *)skipwhite((char *)s + 2);
+ if (*skipwhite((char *)s) == NUL && lnum + 1 < foldend) {
+ s = (char_u *)skipwhite((char *)ml_get(lnum + 1));
+ if (*s == '*') {
+ s = (char_u *)skipwhite((char *)s + 1);
+ }
+ }
+ }
+ int count = foldend - foldstart + 1;
+ char *txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
+ size_t len = STRLEN(txt)
+ + STRLEN(dashes) // for %s
+ + 20 // for %3ld
+ + STRLEN(s); // concatenated
+ char_u *r = xmalloc(len);
+ snprintf((char *)r, len, txt, dashes, count);
+ len = STRLEN(r);
+ STRCAT(r, s);
+ // remove 'foldmarker' and 'commentstring'
+ foldtext_cleanup(r + len);
+ rettv->vval.v_string = (char *)r;
+ }
+}
+
+/// "foldtextresult(lnum)" function
+void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ char_u buf[FOLD_TEXT_LEN];
+ static bool entered = false;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (entered) {
+ return; // reject recursive use
+ }
+ entered = true;
+ linenr_T lnum = tv_get_lnum(argvars);
+ // Treat illegal types and illegal string values for {lnum} the same.
+ if (lnum < 0) {
+ lnum = 0;
+ }
+
+ foldinfo_T info = fold_info(curwin, lnum);
+ if (info.fi_lines > 0) {
+ char_u *text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf);
+ if (text == buf) {
+ text = vim_strsave(text);
+ }
+ rettv->vval.v_string = (char *)text;
+ }
+
+ entered = false;
+}