@@ -64,6 +64,7 @@ static void deleteFoldMarkers(fold_T *fp, int recursive, linenr_T lnum_off);
6464static void foldDelMarker (linenr_T lnum , char_u * marker , int markerlen );
6565static void foldUpdateIEMS (win_T * wp , linenr_T top , linenr_T bot );
6666static void parseMarker (win_T * wp );
67+ static void foldMoveRange_int (garray_T * gap , linenr_T line1 , linenr_T line2 , linenr_T dest );
6768
6869static char * e_nofold = N_ ("E490: No fold found" );
6970
@@ -1075,6 +1076,12 @@ foldAdjustCursor(void)
10751076 (void )hasFolding (curwin -> w_cursor .lnum , & curwin -> w_cursor .lnum , NULL );
10761077}
10771078
1079+ /* foldMoveRange() {{{2 */
1080+ void
1081+ foldMoveRange (garray_T * gap , linenr_T line1 , linenr_T line2 , linenr_T dest )
1082+ {
1083+ foldMoveRange_int (gap , line1 , line2 , dest );
1084+ }
10781085/* Internal functions for "fold_T" {{{1 */
10791086/* cloneFoldGrowArray() {{{2 */
10801087/*
@@ -2968,6 +2975,182 @@ foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
29682975 }
29692976}
29702977
2978+ /* foldReverseOrder() {{{2 */
2979+ static void
2980+ foldReverseOrder (garray_T * gap , linenr_T start , linenr_T end )
2981+ {
2982+ fold_T * left , * right ;
2983+ fold_T tmp ;
2984+
2985+ for (; start < end ; start ++ , end -- )
2986+ {
2987+ left = (fold_T * )gap -> ga_data + start ;
2988+ right = (fold_T * )gap -> ga_data + end ;
2989+ tmp = * left ;
2990+ * left = * right ;
2991+ * right = tmp ;
2992+ }
2993+ }
2994+
2995+ /* foldMoveRange_int() {{{2 */
2996+ /*
2997+ * Move folds within the inclusive range "line1" to "line2" to after "dest"
2998+ * requires "line1" <= "line2" <= "dest"
2999+ *
3000+ * There are the following situations for the first fold at or below line1 - 1.
3001+ * 1 2 3 4
3002+ * 1 2 3 4
3003+ * line1 2 3 4
3004+ * 2 3 4 5 6 7
3005+ * line2 3 4 5 6 7
3006+ * 3 4 6 7 8 9
3007+ * dest 4 7 8 9
3008+ * 4 7 8 10
3009+ * 4 7 8 10
3010+ *
3011+ * In the following descriptions, "moved" means moving in the buffer, *and* in
3012+ * the fold array.
3013+ * Meanwhile, "shifted" just means moving in the buffer.
3014+ * 1. not changed
3015+ * 2. truncated above line1
3016+ * 3. length reduced by line2 - line1, folds starting between the end of 3 and
3017+ * dest are truncated and shifted up
3018+ * 4. internal folds moved (from [line1, line2] to dest)
3019+ * 5. moved to dest.
3020+ * 6. truncated below line2 and moved.
3021+ * 7. length reduced by line2 - dest, folds starting between line2 and dest are
3022+ * removed, top is moved down by move_len.
3023+ * 8. truncated below dest and shifted up.
3024+ * 9. shifted up
3025+ * 10. not changed
3026+ */
3027+
3028+ static void
3029+ truncate_fold (fold_T * fp , linenr_T end )
3030+ {
3031+ foldRemove (& fp -> fd_nested , end - fp -> fd_top , MAXLNUM );
3032+ fp -> fd_len = end - fp -> fd_top + 1 ;
3033+ }
3034+
3035+ #define fold_end (fp ) ((fp)->fd_top + (fp)->fd_len - 1)
3036+ #define valid_fold (fp , gap ) ((fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
3037+ #define fold_index (fp , gap ) ((size_t)(fp - ((fold_T *)(gap)->ga_data)))
3038+
3039+ static void
3040+ foldMoveRange_int (garray_T * gap , linenr_T line1 , linenr_T line2 , linenr_T dest )
3041+ {
3042+ fold_T * fp ;
3043+ linenr_T range_len = line2 - line1 + 1 ;
3044+ linenr_T move_len = dest - line2 ;
3045+ int at_start = foldFind (gap , line1 - 1 , & fp );
3046+ size_t move_start = 0 , move_end = 0 , dest_index = 0 ;
3047+
3048+ if (at_start )
3049+ {
3050+ if (fold_end (fp ) > dest )
3051+ {
3052+ /* Case 4
3053+ * don't have to change this fold, but have to move nested folds.
3054+ */
3055+ foldMoveRange (& fp -> fd_nested , line1 - fp -> fd_top , line2 -
3056+ fp -> fd_top , dest - fp -> fd_top );
3057+ return ;
3058+ }
3059+ else if (fold_end (fp ) > line2 )
3060+ {
3061+ /* Case 3
3062+ * Remove nested folds between line1 and line2 & reduce the
3063+ * length of fold by "range_len".
3064+ * Folds after this one must be dealt with.
3065+ */
3066+ foldMarkAdjustRecurse (& fp -> fd_nested , line1 - fp -> fd_top , line2 -
3067+ fp -> fd_top , MAXLNUM , - range_len );
3068+ fp -> fd_len -= range_len ;
3069+ }
3070+ else
3071+ /* Case 2 truncate fold, folds after this one must be dealt with. */
3072+ truncate_fold (fp , line1 );
3073+
3074+ /* Look at the next fold, and treat that one as if it were the first
3075+ * after "line1" (because now it is). */
3076+ fp = fp + 1 ;
3077+ }
3078+
3079+ if (!valid_fold (fp , gap ) || fp -> fd_top > dest )
3080+ {
3081+ /* Case 10
3082+ * No folds after "line1" and before "dest"
3083+ */
3084+ return ;
3085+ }
3086+ else if (fp -> fd_top > line2 )
3087+ {
3088+ for (; valid_fold (fp , gap ) && fold_end (fp ) < dest ; fp ++ )
3089+ /* Case 9. (for all case 9's) -- shift up. */
3090+ fp -> fd_top -= range_len ;
3091+
3092+ if (valid_fold (fp , gap ) && fp -> fd_top < dest )
3093+ {
3094+ /* Case 8. -- ensure truncated at dest, shift up */
3095+ truncate_fold (fp , dest );
3096+ fp -> fd_top -= range_len ;
3097+ }
3098+ return ;
3099+ }
3100+ else if (fold_end (fp ) > dest )
3101+ {
3102+ /* Case 7 -- remove nested folds and shrink */
3103+ foldMarkAdjustRecurse (& fp -> fd_nested , line2 + 1 - fp -> fd_top , dest -
3104+ fp -> fd_top , MAXLNUM , - move_len );
3105+ fp -> fd_len -= move_len ;
3106+ fp -> fd_top += move_len ;
3107+ return ;
3108+ }
3109+
3110+ /* Case 5 or 6
3111+ * changes rely on whether there are folds between the end of
3112+ * this fold and "dest".
3113+ */
3114+ move_start = fold_index (fp , gap );
3115+
3116+ for (; valid_fold (fp , gap ) && fp -> fd_top <= dest ; fp ++ )
3117+ {
3118+ if (fp -> fd_top <= line2 )
3119+ {
3120+ /* 1. 2. or 3. */
3121+ if (fold_end (fp ) > line2 )
3122+ /* 2. or 3., truncate before moving */
3123+ truncate_fold (fp , line2 );
3124+
3125+ fp -> fd_top += move_len ;
3126+ continue ;
3127+ }
3128+
3129+ /* Record index of the first fold after the moved range. */
3130+ if (move_end == 0 )
3131+ move_end = fold_index (fp , gap );
3132+
3133+ if (fold_end (fp ) > dest )
3134+ truncate_fold (fp , dest );
3135+
3136+ fp -> fd_top -= range_len ;
3137+ }
3138+
3139+ dest_index = fold_index (fp , gap );
3140+
3141+ /*
3142+ * All folds are now correct, but they are not necessarily in the correct
3143+ * order. We have to swap folds in the range [move_end, dest_index) with
3144+ * those in the range [move_start, move_end).
3145+ */
3146+ foldReverseOrder (gap , move_start , dest_index - 1 );
3147+ foldReverseOrder (gap , move_start , move_start + dest_index - move_end - 1 );
3148+ foldReverseOrder (gap , move_start + dest_index - move_end , dest_index - 1 );
3149+ }
3150+ #undef fold_end
3151+ #undef valid_fold
3152+ #undef fold_index
3153+
29713154/* foldMerge() {{{2 */
29723155/*
29733156 * Merge two adjacent folds (and the nested ones in them).
0 commit comments