diff options
| author | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-12 02:25:17 +0200 |
|---|---|---|
| committer | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-15 20:46:01 +0200 |
| commit | da51dc9cf202772f60bd2da975dbef257bd9237c (patch) | |
| tree | 5c16b93238a153f55634e9323077f30c8133970c /src/fold.c | |
| parent | ffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff) | |
| download | rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2 rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip | |
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/fold.c')
| -rw-r--r-- | src/fold.c | 3033 |
1 files changed, 0 insertions, 3033 deletions
diff --git a/src/fold.c b/src/fold.c deleted file mode 100644 index 143b35ea10..0000000000 --- a/src/fold.c +++ /dev/null @@ -1,3033 +0,0 @@ -/* vim: set fdm=marker fdl=1 fdc=3 - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * fold.c: code for folding - */ - -#include <string.h> - -#include "vim.h" -#include "fold.h" -#include "charset.h" -#include "diff.h" -#include "eval.h" -#include "ex_docmd.h" -#include "indent.h" -#include "mark.h" -#include "memline.h" -#include "memory.h" -#include "message.h" -#include "misc1.h" -#include "misc2.h" -#include "garray.h" -#include "move.h" -#include "option.h" -#include "screen.h" -#include "syntax.h" -#include "undo.h" - -/* local declarations. {{{1 */ -/* typedef fold_T {{{2 */ -/* - * The toplevel folds for each window are stored in the w_folds growarray. - * Each toplevel fold can contain an array of second level folds in the - * fd_nested growarray. - * The info stored in both growarrays is the same: An array of fold_T. - */ -typedef struct { - linenr_T fd_top; /* first line of fold; for nested fold - * relative to parent */ - linenr_T fd_len; /* number of lines in the fold */ - garray_T fd_nested; /* array of nested folds */ - char fd_flags; /* see below */ - char fd_small; /* TRUE, FALSE or MAYBE: fold smaller than - 'foldminlines'; MAYBE applies to nested - folds too */ -} fold_T; - -#define FD_OPEN 0 /* fold is open (nested ones can be closed) */ -#define FD_CLOSED 1 /* fold is closed */ -#define FD_LEVEL 2 /* depends on 'foldlevel' (nested folds too) */ - -#define MAX_LEVEL 20 /* maximum fold depth */ - -/* static functions {{{2 */ -static void newFoldLevelWin(win_T *wp); -static int checkCloseRec(garray_T *gap, linenr_T lnum, int level); -static int foldFind(garray_T *gap, linenr_T lnum, fold_T **fpp); -static int foldLevelWin(win_T *wp, linenr_T lnum); -static void checkupdate(win_T *wp); -static void setFoldRepeat(linenr_T lnum, long count, int do_open); -static linenr_T setManualFold(linenr_T lnum, int opening, int recurse, - int *donep); -static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, - int recurse, - int *donep); -static void foldOpenNested(fold_T *fpr); -static void deleteFoldEntry(garray_T *gap, int idx, int recursive); -static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, - linenr_T line2, long amount, - long amount_after); -static int getDeepestNestingRecurse(garray_T *gap); -static int check_closed(win_T *win, fold_T *fp, int *use_levelp, - int level, int *maybe_smallp, - linenr_T lnum_off); -static void checkSmall(win_T *wp, fold_T *fp, linenr_T lnum_off); -static void setSmallMaybe(garray_T *gap); -static void foldCreateMarkers(linenr_T start, linenr_T end); -static void foldAddMarker(linenr_T lnum, char_u *marker, int markerlen); -static void deleteFoldMarkers(fold_T *fp, int recursive, - linenr_T lnum_off); -static void foldDelMarker(linenr_T lnum, char_u *marker, int markerlen); -static void foldUpdateIEMS(win_T *wp, linenr_T top, linenr_T bot); -static void parseMarker(win_T *wp); - -static 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; - -/* - * 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 - * stored yet. To get around this chicken-egg problem the level of the - * previous line is stored here when available. prev_lnum is zero when the - * level is not available. - */ -static linenr_T prev_lnum = 0; -static int prev_lnum_lvl = -1; - -/* Flags used for "done" argument of setManualFold. */ -#define DONE_NOTHING 0 -#define DONE_ACTION 1 /* did close or open a fold */ -#define DONE_FOLD 2 /* did find a fold */ - -static int foldstartmarkerlen; -static char_u *foldendmarker; -static int foldendmarkerlen; - -/* Exported folding functions. {{{1 */ -/* copyFoldingState() {{{2 */ -/* - * Copy that folding state from window "wp_from" to window "wp_to". - */ -void copyFoldingState(win_T *wp_from, win_T *wp_to) -{ - wp_to->w_fold_manual = wp_from->w_fold_manual; - wp_to->w_foldinvalid = wp_from->w_foldinvalid; - cloneFoldGrowArray(&wp_from->w_folds, &wp_to->w_folds); -} - -/* hasAnyFolding() {{{2 */ -/* - * Return TRUE if there may be folded lines in the current window. - */ -int hasAnyFolding(win_T *win) -{ - /* very simple now, but can become more complex later */ - return win->w_p_fen - && (!foldmethodIsManual(win) || win->w_folds.ga_len > 0); -} - -/* hasFolding() {{{2 */ -/* - * Return TRUE if line "lnum" in the current window is part of a closed - * fold. - * When returning TRUE, *firstp and *lastp are set to the first and last - * lnum of the sequence of folded lines (skipped when NULL). - */ -int hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp) -{ - return hasFoldingWin(curwin, lnum, firstp, lastp, TRUE, NULL); -} - -/* hasFoldingWin() {{{2 */ -int -hasFoldingWin ( - win_T *win, - linenr_T lnum, - linenr_T *firstp, - linenr_T *lastp, - int cache, /* when TRUE: use cached values of window */ - foldinfo_T *infop /* where to store fold info */ -) -{ - int had_folded = FALSE; - linenr_T first = 0; - linenr_T last = 0; - linenr_T lnum_rel = lnum; - int x; - fold_T *fp; - int level = 0; - int use_level = FALSE; - int maybe_small = FALSE; - garray_T *gap; - int low_level = 0;; - - checkupdate(win); - /* - * Return quickly when there is no folding at all in this window. - */ - if (!hasAnyFolding(win)) { - if (infop != NULL) - infop->fi_level = 0; - return FALSE; - } - - if (cache) { - /* - * First look in cached info for displayed lines. This is probably - * the fastest, but it can only be used if the entry is still valid. - */ - x = find_wl_entry(win, lnum); - if (x >= 0) { - first = win->w_lines[x].wl_lnum; - last = win->w_lines[x].wl_lastlnum; - had_folded = win->w_lines[x].wl_folded; - } - } - - if (first == 0) { - /* - * Recursively search for a fold that contains "lnum". - */ - gap = &win->w_folds; - for (;; ) { - if (!foldFind(gap, lnum_rel, &fp)) - break; - - /* Remember lowest level of fold that starts in "lnum". */ - if (lnum_rel == fp->fd_top && low_level == 0) - low_level = level + 1; - - first += fp->fd_top; - last += fp->fd_top; - - /* is this fold closed? */ - had_folded = check_closed(win, fp, &use_level, level, - &maybe_small, lnum - lnum_rel); - if (had_folded) { - /* Fold closed: Set last and quit loop. */ - last += fp->fd_len - 1; - break; - } - - /* Fold found, but it's open: Check nested folds. Line number is - * relative to containing fold. */ - gap = &fp->fd_nested; - lnum_rel -= fp->fd_top; - ++level; - } - } - - if (!had_folded) { - if (infop != NULL) { - infop->fi_level = level; - infop->fi_lnum = lnum - lnum_rel; - infop->fi_low_level = low_level == 0 ? level : low_level; - } - return FALSE; - } - - if (lastp != NULL) - *lastp = last; - if (firstp != NULL) - *firstp = first; - if (infop != NULL) { - infop->fi_level = level + 1; - infop->fi_lnum = first; - infop->fi_low_level = low_level == 0 ? level + 1 : low_level; - } - return TRUE; -} - -/* foldLevel() {{{2 */ -/* - * Return fold level at line number "lnum" in the current window. - */ -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) - checkupdate(curwin); - else if (lnum == prev_lnum && prev_lnum_lvl >= 0) - return prev_lnum_lvl; - else if (lnum >= invalid_top && lnum <= invalid_bot) - return -1; - - /* Return quickly when there is no folding at all in this window. */ - if (!hasAnyFolding(curwin)) - return 0; - - return foldLevelWin(curwin, lnum); -} - -/* lineFolded() {{{2 */ -/* - * Low level function to check if a line is folded. Doesn't use any caching. - * Return TRUE if line is folded. - * Return FALSE if line is not folded. - * Return MAYBE if the line is folded when next to a folded line. - */ -int lineFolded(win_T *win, linenr_T lnum) -{ - return foldedCount(win, lnum, NULL) != 0; -} - -/* foldedCount() {{{2 */ -/* - * Count the number of lines that are folded at line number "lnum". - * Normally "lnum" is the first line of a possible fold, and the returned - * number is the number of lines in the fold. - * Doesn't use caching from the displayed window. - * Returns number of folded lines from "lnum", or 0 if line is not folded. - * When "infop" is not NULL, fills *infop with the fold level info. - */ -long foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop) -{ - linenr_T last; - - if (hasFoldingWin(win, lnum, NULL, &last, FALSE, infop)) - return (long)(last - lnum + 1); - return 0; -} - -/* foldmethodIsManual() {{{2 */ -/* - * Return TRUE if 'foldmethod' is "manual" - */ -int foldmethodIsManual(win_T *wp) -{ - return wp->w_p_fdm[3] == 'u'; -} - -/* foldmethodIsIndent() {{{2 */ -/* - * Return TRUE if 'foldmethod' is "indent" - */ -int foldmethodIsIndent(win_T *wp) -{ - return wp->w_p_fdm[0] == 'i'; -} - -/* foldmethodIsExpr() {{{2 */ -/* - * Return TRUE if 'foldmethod' is "expr" - */ -int foldmethodIsExpr(win_T *wp) -{ - return wp->w_p_fdm[1] == 'x'; -} - -/* foldmethodIsMarker() {{{2 */ -/* - * Return TRUE if 'foldmethod' is "marker" - */ -int foldmethodIsMarker(win_T *wp) -{ - return wp->w_p_fdm[2] == 'r'; -} - -/* foldmethodIsSyntax() {{{2 */ -/* - * Return TRUE if 'foldmethod' is "syntax" - */ -int foldmethodIsSyntax(win_T *wp) -{ - return wp->w_p_fdm[0] == 's'; -} - -/* foldmethodIsDiff() {{{2 */ -/* - * Return TRUE if 'foldmethod' is "diff" - */ -int foldmethodIsDiff(win_T *wp) -{ - return wp->w_p_fdm[0] == 'd'; -} - -/* closeFold() {{{2 */ -/* - * Close fold for current window at line "lnum". - * Repeat "count" times. - */ -void closeFold(linenr_T lnum, long count) -{ - setFoldRepeat(lnum, count, FALSE); -} - -/* closeFoldRecurse() {{{2 */ -/* - * Close fold for current window at line "lnum" recursively. - */ -void closeFoldRecurse(linenr_T lnum) -{ - (void)setManualFold(lnum, FALSE, TRUE, NULL); -} - -/* opFoldRange() {{{2 */ -/* - * Open or Close folds for current window in lines "first" to "last". - * Used for "zo", "zO", "zc" and "zC" in Visual mode. - */ -void -opFoldRange ( - linenr_T first, - linenr_T last, - int opening, /* TRUE to open, FALSE to close */ - int recurse, /* TRUE to do it recursively */ - int had_visual /* TRUE when Visual selection used */ -) -{ - int done = DONE_NOTHING; /* avoid error messages */ - linenr_T lnum; - linenr_T lnum_next; - - for (lnum = first; lnum <= last; lnum = lnum_next + 1) { - lnum_next = lnum; - /* Opening one level only: next fold to open is after the one going to - * be opened. */ - if (opening && !recurse) - (void)hasFolding(lnum, NULL, &lnum_next); - (void)setManualFold(lnum, opening, recurse, &done); - /* Closing one level only: next line to close a fold is after just - * closed fold. */ - if (!opening && !recurse) - (void)hasFolding(lnum, NULL, &lnum_next); - } - if (done == DONE_NOTHING) - EMSG(_(e_nofold)); - /* Force a redraw to remove the Visual highlighting. */ - if (had_visual) - redraw_curbuf_later(INVERTED); -} - -/* openFold() {{{2 */ -/* - * Open fold for current window at line "lnum". - * Repeat "count" times. - */ -void openFold(linenr_T lnum, long count) -{ - setFoldRepeat(lnum, count, TRUE); -} - -/* openFoldRecurse() {{{2 */ -/* - * Open fold for current window at line "lnum" recursively. - */ -void openFoldRecurse(linenr_T lnum) -{ - (void)setManualFold(lnum, TRUE, TRUE, NULL); -} - -/* foldOpenCursor() {{{2 */ -/* - * Open folds until the cursor line is not in a closed fold. - */ -void foldOpenCursor(void) -{ - int done; - - checkupdate(curwin); - if (hasAnyFolding(curwin)) - for (;; ) { - done = DONE_NOTHING; - (void)setManualFold(curwin->w_cursor.lnum, TRUE, FALSE, &done); - if (!(done & DONE_ACTION)) - break; - } -} - -/* newFoldLevel() {{{2 */ -/* - * Set new foldlevel for current window. - */ -void newFoldLevel(void) -{ - newFoldLevelWin(curwin); - - if (foldmethodIsDiff(curwin) && curwin->w_p_scb) { - win_T *wp; - - /* - * Set the same foldlevel in other windows in diff mode. - */ - FOR_ALL_WINDOWS(wp) - { - if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) { - wp->w_p_fdl = curwin->w_p_fdl; - newFoldLevelWin(wp); - } - } - } -} - -static void newFoldLevelWin(win_T *wp) -{ - fold_T *fp; - int i; - - checkupdate(wp); - if (wp->w_fold_manual) { - /* Set all flags for the first level of folds to FD_LEVEL. Following - * manual open/close will then change the flags to FD_OPEN or - * FD_CLOSED for those folds that don't use 'foldlevel'. */ - fp = (fold_T *)wp->w_folds.ga_data; - for (i = 0; i < wp->w_folds.ga_len; ++i) - fp[i].fd_flags = FD_LEVEL; - wp->w_fold_manual = FALSE; - } - changed_window_setting_win(wp); -} - -/* foldCheckClose() {{{2 */ -/* - * Apply 'foldlevel' to all folds that don't contain the cursor. - */ -void foldCheckClose(void) -{ - if (*p_fcl != NUL) { /* can only be "all" right now */ - checkupdate(curwin); - if (checkCloseRec(&curwin->w_folds, curwin->w_cursor.lnum, - (int)curwin->w_p_fdl)) - changed_window_setting(); - } -} - -/* checkCloseRec() {{{2 */ -static int checkCloseRec(garray_T *gap, linenr_T lnum, int level) -{ - fold_T *fp; - int retval = FALSE; - int i; - - fp = (fold_T *)gap->ga_data; - for (i = 0; i < gap->ga_len; ++i) { - /* Only manually opened folds may need to be closed. */ - if (fp[i].fd_flags == FD_OPEN) { - if (level <= 0 && (lnum < fp[i].fd_top - || lnum >= fp[i].fd_top + fp[i].fd_len)) { - fp[i].fd_flags = FD_LEVEL; - retval = TRUE; - } else - retval |= checkCloseRec(&fp[i].fd_nested, lnum - fp[i].fd_top, - level - 1); - } - } - return retval; -} - -/* foldCreateAllowed() {{{2 */ -/* - * Return TRUE if it's allowed to manually create or delete a fold. - * Give an error message and return FALSE if not. - */ -int foldManualAllowed(int create) -{ - if (foldmethodIsManual(curwin) || foldmethodIsMarker(curwin)) - return TRUE; - if (create) - EMSG(_("E350: Cannot create fold with current 'foldmethod'")); - else - EMSG(_("E351: Cannot delete fold with current 'foldmethod'")); - return FALSE; -} - -/* foldCreate() {{{2 */ -/* - * Create a fold from line "start" to line "end" (inclusive) in the current - * window. - */ -void foldCreate(linenr_T start, linenr_T end) -{ - fold_T *fp; - garray_T *gap; - garray_T fold_ga; - int i, j; - int cont; - int use_level = FALSE; - int closed = FALSE; - int level = 0; - linenr_T start_rel = start; - linenr_T end_rel = end; - - if (start > end) { - /* reverse the range */ - end = start_rel; - start = end_rel; - start_rel = start; - end_rel = end; - } - - /* When 'foldmethod' is "marker" add markers, which creates the folds. */ - if (foldmethodIsMarker(curwin)) { - foldCreateMarkers(start, end); - return; - } - - checkupdate(curwin); - - /* Find the place to insert the new fold. */ - gap = &curwin->w_folds; - for (;; ) { - if (!foldFind(gap, start_rel, &fp)) - break; - if (fp->fd_top + fp->fd_len > end_rel) { - /* New fold is completely inside this fold: Go one level deeper. */ - gap = &fp->fd_nested; - start_rel -= fp->fd_top; - end_rel -= fp->fd_top; - if (use_level || fp->fd_flags == FD_LEVEL) { - use_level = TRUE; - if (level >= curwin->w_p_fdl) - closed = TRUE; - } else if (fp->fd_flags == FD_CLOSED) - closed = TRUE; - ++level; - } else { - /* This fold and new fold overlap: Insert here and move some folds - * inside the new fold. */ - break; - } - } - - i = (int)(fp - (fold_T *)gap->ga_data); - ga_grow(gap, 1); - { - fp = (fold_T *)gap->ga_data + i; - ga_init(&fold_ga, (int)sizeof(fold_T), 10); - - /* Count number of folds that will be contained in the new fold. */ - for (cont = 0; i + cont < gap->ga_len; ++cont) - if (fp[cont].fd_top > end_rel) - break; - if (cont > 0) { - ga_grow(&fold_ga, cont); - /* If the first fold starts before the new fold, let the new fold - * start there. Otherwise the existing fold would change. */ - if (start_rel > fp->fd_top) - start_rel = fp->fd_top; - - /* When last contained fold isn't completely contained, adjust end - * of new fold. */ - if (end_rel < fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1) - end_rel = fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1; - /* Move contained folds to inside new fold. */ - memmove(fold_ga.ga_data, fp, sizeof(fold_T) * cont); - fold_ga.ga_len += cont; - i += cont; - - /* Adjust line numbers in contained folds to be relative to the - * new fold. */ - for (j = 0; j < cont; ++j) - ((fold_T *)fold_ga.ga_data)[j].fd_top -= start_rel; - } - /* Move remaining entries to after the new fold. */ - if (i < gap->ga_len) - memmove(fp + 1, (fold_T *)gap->ga_data + i, - sizeof(fold_T) * (gap->ga_len - i)); - gap->ga_len = gap->ga_len + 1 - cont; - - /* insert new fold */ - fp->fd_nested = fold_ga; - fp->fd_top = start_rel; - fp->fd_len = end_rel - start_rel + 1; - - /* 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 < curwin->w_p_fdl) - closeFold(start, 1L); - if (!use_level) - curwin->w_fold_manual = TRUE; - fp->fd_flags = FD_CLOSED; - fp->fd_small = MAYBE; - - /* redraw */ - changed_window_setting(); - } -} - - -/* deleteFold() {{{2 */ -/* - * Delete a fold at line "start" in the current window. - * When "end" is not 0, delete all folds from "start" to "end". - * When "recursive" is TRUE delete recursively. - */ -void -deleteFold ( - linenr_T start, - linenr_T end, - int recursive, - int had_visual /* TRUE when Visual selection used */ -) -{ - garray_T *gap; - fold_T *fp; - garray_T *found_ga; - fold_T *found_fp = NULL; - linenr_T found_off = 0; - int use_level; - int maybe_small = FALSE; - int level = 0; - linenr_T lnum = start; - linenr_T lnum_off; - int did_one = FALSE; - linenr_T first_lnum = MAXLNUM; - linenr_T last_lnum = 0; - - checkupdate(curwin); - - while (lnum <= end) { - /* Find the deepest fold for "start". */ - gap = &curwin->w_folds; - found_ga = NULL; - lnum_off = 0; - use_level = FALSE; - for (;; ) { - if (!foldFind(gap, lnum - lnum_off, &fp)) - break; - /* lnum is inside this fold, remember info */ - found_ga = gap; - found_fp = fp; - found_off = lnum_off; - - /* if "lnum" is folded, don't check nesting */ - if (check_closed(curwin, fp, &use_level, level, - &maybe_small, lnum_off)) - break; - - /* check nested folds */ - gap = &fp->fd_nested; - lnum_off += fp->fd_top; - ++level; - } - if (found_ga == NULL) { - ++lnum; - } else { - lnum = found_fp->fd_top + found_fp->fd_len + found_off; - - if (foldmethodIsManual(curwin)) - deleteFoldEntry(found_ga, - (int)(found_fp - (fold_T *)found_ga->ga_data), recursive); - else { - if (first_lnum > found_fp->fd_top + found_off) - first_lnum = found_fp->fd_top + found_off; - if (last_lnum < lnum) - last_lnum = lnum; - if (!did_one) - parseMarker(curwin); - deleteFoldMarkers(found_fp, recursive, found_off); - } - did_one = TRUE; - - /* redraw window */ - changed_window_setting(); - } - } - if (!did_one) { - EMSG(_(e_nofold)); - /* Force a redraw to remove the Visual highlighting. */ - if (had_visual) - redraw_curbuf_later(INVERTED); - } else - /* Deleting markers may make cursor column invalid. */ - check_cursor_col(); - - if (last_lnum > 0) - changed_lines(first_lnum, (colnr_T)0, last_lnum, 0L); -} - -/* clearFolding() {{{2 */ -/* - * Remove all folding for window "win". - */ -void clearFolding(win_T *win) -{ - deleteFoldRecurse(&win->w_folds); - win->w_foldinvalid = FALSE; -} - -/* foldUpdate() {{{2 */ -/* - * Update folds for changes in the buffer of a window. - * Note that inserted/deleted lines must have already been taken care of by - * calling foldMarkAdjust(). - * The changes in lines from top to bot (inclusive). - */ -void foldUpdate(win_T *wp, linenr_T top, linenr_T bot) -{ - fold_T *fp; - - /* Mark all folds from top to bot as maybe-small. */ - (void)foldFind(&curwin->w_folds, top, &fp); - while (fp < (fold_T *)curwin->w_folds.ga_data + curwin->w_folds.ga_len - && fp->fd_top < bot) { - fp->fd_small = MAYBE; - ++fp; - } - - if (foldmethodIsIndent(wp) - || foldmethodIsExpr(wp) - || foldmethodIsMarker(wp) - || foldmethodIsDiff(wp) - || foldmethodIsSyntax(wp)) { - int save_got_int = got_int; - - /* reset got_int here, otherwise it won't work */ - got_int = FALSE; - foldUpdateIEMS(wp, top, bot); - got_int |= save_got_int; - } -} - -/* foldUpdateAll() {{{2 */ -/* - * Update all lines in a window for folding. - * Used when a fold setting changes or after reloading the buffer. - * The actual updating is postponed until fold info is used, to avoid doing - * every time a setting is changed or a syntax item is added. - */ -void foldUpdateAll(win_T *win) -{ - win->w_foldinvalid = TRUE; - redraw_win_later(win, NOT_VALID); -} - -/* foldMoveTo() {{{2 */ -/* - * If "updown" is FALSE: Move to the start or end of the fold. - * If "updown" is TRUE: move to fold at the same level. - * If not moved return FAIL. - */ -int -foldMoveTo ( - int updown, - int dir, /* FORWARD or BACKWARD */ - long count -) -{ - long n; - int retval = FAIL; - linenr_T lnum_off; - linenr_T lnum_found; - linenr_T lnum; - int use_level; - int maybe_small; - garray_T *gap; - fold_T *fp; - int level; - int last; - - checkupdate(curwin); - - /* Repeat "count" times. */ - for (n = 0; n < count; ++n) { - /* Find nested folds. Stop when a fold is closed. The deepest fold - * that moves the cursor is used. */ - lnum_off = 0; - gap = &curwin->w_folds; - use_level = FALSE; - maybe_small = FALSE; - lnum_found = curwin->w_cursor.lnum; - level = 0; - last = FALSE; - for (;; ) { - if (!foldFind(gap, curwin->w_cursor.lnum - lnum_off, &fp)) { - if (!updown) - break; - - /* When moving up, consider a fold above the cursor; when - * moving down consider a fold below the cursor. */ - if (dir == FORWARD) { - if (fp - (fold_T *)gap->ga_data >= gap->ga_len) - break; - --fp; - } else { - if (fp == (fold_T *)gap->ga_data) - break; - } - /* don't look for contained folds, they will always move - * the cursor too far. */ - last = TRUE; - } - - if (!last) { - /* Check if this fold is closed. */ - if (check_closed(curwin, fp, &use_level, level, - &maybe_small, lnum_off)) - last = TRUE; - - /* "[z" and "]z" stop at closed fold */ - if (last && !updown) - break; - } - - if (updown) { - if (dir == FORWARD) { - /* to start of next fold if there is one */ - if (fp + 1 - (fold_T *)gap->ga_data < gap->ga_len) { - lnum = fp[1].fd_top + lnum_off; - if (lnum > curwin->w_cursor.lnum) - lnum_found = lnum; - } - } else { - /* to end of previous fold if there is one */ - if (fp > (fold_T *)gap->ga_data) { - lnum = fp[-1].fd_top + lnum_off + fp[-1].fd_len - 1; - if (lnum < curwin->w_cursor.lnum) - lnum_found = lnum; - } - } - } else { - /* Open fold found, set cursor to its start/end and then check - * nested folds. */ - if (dir == FORWARD) { - lnum = fp->fd_top + lnum_off + fp->fd_len - 1; - if (lnum > curwin->w_cursor.lnum) - lnum_found = lnum; - } else { - lnum = fp->fd_top + lnum_off; - if (lnum < curwin->w_cursor.lnum) - lnum_found = lnum; - } - } - - if (last) - break; - - /* Check nested folds (if any). */ - gap = &fp->fd_nested; - lnum_off += fp->fd_top; - ++level; - } - if (lnum_found != curwin->w_cursor.lnum) { - if (retval == FAIL) - setpcmark(); - curwin->w_cursor.lnum = lnum_found; - curwin->w_cursor.col = 0; - retval = OK; - } else - break; - } - - return retval; -} - -/* foldInitWin() {{{2 */ -/* - * Init the fold info in a new window. - */ -void foldInitWin(win_T *new_win) -{ - ga_init(&new_win->w_folds, (int)sizeof(fold_T), 10); -} - -/* find_wl_entry() {{{2 */ -/* - * Find an entry in the win->w_lines[] array for buffer line "lnum". - * Only valid entries are considered (for entries where wl_valid is FALSE the - * line number can be wrong). - * Returns index of entry or -1 if not found. - */ -int find_wl_entry(win_T *win, linenr_T lnum) -{ - int i; - - for (i = 0; i < win->w_lines_valid; ++i) - if (win->w_lines[i].wl_valid) { - if (lnum < win->w_lines[i].wl_lnum) - return -1; - if (lnum <= win->w_lines[i].wl_lastlnum) - return i; - } - return -1; -} - -/* foldAdjustVisual() {{{2 */ -/* - * Adjust the Visual area to include any fold at the start or end completely. - */ -void foldAdjustVisual(void) -{ - pos_T *start, *end; - char_u *ptr; - - if (!VIsual_active || !hasAnyFolding(curwin)) - return; - - if (ltoreq(VIsual, curwin->w_cursor)) { - start = &VIsual; - end = &curwin->w_cursor; - } else { - start = &curwin->w_cursor; - end = &VIsual; - } - if (hasFolding(start->lnum, &start->lnum, NULL)) - start->col = 0; - if (hasFolding(end->lnum, NULL, &end->lnum)) { - ptr = ml_get(end->lnum); - end->col = (colnr_T)STRLEN(ptr); - if (end->col > 0 && *p_sel == 'o') - --end->col; - /* prevent cursor from moving on the trail byte */ - if (has_mbyte) - mb_adjust_cursor(); - } -} - -/* cursor_foldstart() {{{2 */ -/* - * Move the cursor to the first line of a closed fold. - */ -void foldAdjustCursor(void) -{ - (void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); -} - -/* Internal functions for "fold_T" {{{1 */ -/* cloneFoldGrowArray() {{{2 */ -/* - * Will "clone" (i.e deep copy) a garray_T of folds. - */ -void cloneFoldGrowArray(garray_T *from, garray_T *to) -{ - int i; - fold_T *from_p; - fold_T *to_p; - - ga_init(to, from->ga_itemsize, from->ga_growsize); - - if (from->ga_len == 0) - return; - - ga_grow(to, from->ga_len); - - from_p = (fold_T *)from->ga_data; - to_p = (fold_T *)to->ga_data; - - for (i = 0; i < from->ga_len; i++) { - to_p->fd_top = from_p->fd_top; - to_p->fd_len = from_p->fd_len; - to_p->fd_flags = from_p->fd_flags; - to_p->fd_small = from_p->fd_small; - cloneFoldGrowArray(&from_p->fd_nested, &to_p->fd_nested); - ++to->ga_len; - ++from_p; - ++to_p; - } -} - -/* foldFind() {{{2 */ -/* - * Search for line "lnum" in folds of growarray "gap". - * Set *fpp to the fold struct for the fold that contains "lnum" or - * the first fold below it (careful: it can be beyond the end of the array!). - * Returns FALSE when there is no fold that contains "lnum". - */ -static int foldFind(garray_T *gap, linenr_T lnum, fold_T **fpp) -{ - linenr_T low, high; - fold_T *fp; - int i; - - /* - * Perform a binary search. - * "low" is lowest index of possible match. - * "high" is highest index of possible match. - */ - fp = (fold_T *)gap->ga_data; - low = 0; - high = gap->ga_len - 1; - while (low <= high) { - i = (low + high) / 2; - if (fp[i].fd_top > lnum) - /* fold below lnum, adjust high */ - high = i - 1; - else if (fp[i].fd_top + fp[i].fd_len <= lnum) - /* fold above lnum, adjust low */ - low = i + 1; - else { - /* lnum is inside this fold */ - *fpp = fp + i; - return TRUE; - } - } - *fpp = fp + low; - return FALSE; -} - -/* foldLevelWin() {{{2 */ -/* - * Return fold level at line number "lnum" in window "wp". - */ -static int foldLevelWin(win_T *wp, linenr_T lnum) -{ - fold_T *fp; - linenr_T lnum_rel = lnum; - int level = 0; - garray_T *gap; - - /* Recursively search for a fold that contains "lnum". */ - gap = &wp->w_folds; - for (;; ) { - if (!foldFind(gap, lnum_rel, &fp)) - break; - /* Check nested folds. Line number is relative to containing fold. */ - gap = &fp->fd_nested; - lnum_rel -= fp->fd_top; - ++level; - } - - return level; -} - -/* checkupdate() {{{2 */ -/* - * Check if the folds in window "wp" are invalid and update them if needed. - */ -static void checkupdate(win_T *wp) -{ - if (wp->w_foldinvalid) { - foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); /* will update all */ - wp->w_foldinvalid = FALSE; - } -} - -/* setFoldRepeat() {{{2 */ -/* - * Open or close fold for current window at line "lnum". - * Repeat "count" times. - */ -static void setFoldRepeat(linenr_T lnum, long count, int do_open) -{ - int done; - long n; - - for (n = 0; n < count; ++n) { - done = DONE_NOTHING; - (void)setManualFold(lnum, do_open, FALSE, &done); - if (!(done & DONE_ACTION)) { - /* Only give an error message when no fold could be opened. */ - if (n == 0 && !(done & DONE_FOLD)) - EMSG(_(e_nofold)); - break; - } - } -} - -/* setManualFold() {{{2 */ -/* - * Open or close the fold in the current window which contains "lnum". - * Also does this for other windows in diff mode when needed. - */ -static linenr_T -setManualFold ( - linenr_T lnum, - int opening, |