Patch 8.2.2854
Problem:    Custom statusline cannot contain % items.
Solution:   Add "%{% expr %}". (closes #8190)
Files:      runtime/doc/options.txt, src/buffer.c, src/optionstr.c,
            src/testdir/test_statusline.vim


*** ../vim-8.2.2853/runtime/doc/options.txt     2021-05-06 18:46:31.039085745 
+0200
--- runtime/doc/options.txt     2021-05-15 16:54:06.138186893 +0200
***************
*** 7334,7339 ****
--- 7339,7356 ----
              Note that there is no '%' before the closing '}'.  The
              expression cannot contain a '}' character, call a function to
              work around that.  See |stl-%{| below.
+       {% -  This is almost same as { except the result of the expression is
+             re-evaluated as a statusline format string.  Thus if the
+             return value of expr contains % items they will get expanded.
+             The expression can contain the } character, the end of
+             expression is denoted by %}.
+             The For example: >
+               func! Stl_filename() abort
+                   return "%t"
+               endfunc
+ <             `stl=%{Stl_filename()}`   results in `"%t"`
+               `stl=%{%Stl_filename()%}` results in `"Name of current file"`
+       } -   End of `{%` expression
        ( -   Start of item group.  Can be used for setting the width and
              alignment of a section.  Must be followed by %) somewhere.
        ) -   End of item group.  No width fields allowed.
*** ../vim-8.2.2853/src/buffer.c        2021-03-04 21:55:54.601235264 +0100
--- src/buffer.c        2021-05-15 16:59:14.820874600 +0200
***************
*** 27,32 ****
--- 27,38 ----
  
  #include "vim.h"
  
+ 
+ #ifdef FEAT_EVAL
+ // Determines how deeply nested %{} blocks will be evaluated in statusline.
+ # define MAX_STL_EVAL_DEPTH 100
+ #endif
+ 
  static void   enter_buffer(buf_T *buf);
  static void   buflist_getfpos(void);
  static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
***************
*** 4113,4118 ****
--- 4119,4127 ----
      int               group_end_userhl;
      int               group_start_userhl;
      int               groupdepth;
+ #ifdef FEAT_EVAL
+     int               evaldepth;
+ #endif
      int               minwid;
      int               maxwid;
      int               zeropad;
***************
*** 4187,4192 ****
--- 4196,4204 ----
        byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
  
      groupdepth = 0;
+ #ifdef FEAT_EVAL
+     evaldepth = 0;
+ #endif
      p = out;
      curitem = 0;
      prevchar_isflag = TRUE;
***************
*** 4447,4452 ****
--- 4459,4473 ----
            curitem++;
            continue;
        }
+ #ifdef FEAT_EVAL
+       // Denotes end of expanded %{} block
+       if (*s == '}' && evaldepth > 0)
+       {
+           s++;
+           evaldepth--;
+           continue;
+       }
+ #endif
        if (vim_strchr(STL_ALL, *s) == NULL)
        {
            s++;
***************
*** 4482,4497 ****
            break;
  
        case STL_VIM_EXPR: // '{'
            itemisflag = TRUE;
            t = p;
!           while (*s != '}' && *s != NUL && p + 1 < out + outlen)
                *p++ = *s++;
            if (*s != '}')      // missing '}' or out of space
                break;
            s++;
!           *p = 0;
            p = t;
- 
  #ifdef FEAT_EVAL
            vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
                                                         "%d", curbuf->b_fnum);
--- 4503,4529 ----
            break;
  
        case STL_VIM_EXPR: // '{'
+       {
+ #ifdef FEAT_EVAL
+           char_u *block_start = s - 1;
+ #endif
+           int reevaluate = (*s == '%');
+ 
+           if (reevaluate)
+               s++;
            itemisflag = TRUE;
            t = p;
!           while ((*s != '}' || (reevaluate && s[-1] != '%'))
!                                         && *s != NUL && p + 1 < out + outlen)
                *p++ = *s++;
            if (*s != '}')      // missing '}' or out of space
                break;
            s++;
!           if (reevaluate)
!               p[-1] = 0; // remove the % at the end of %{% expr %}
!           else
!               *p = 0;
            p = t;
  #ifdef FEAT_EVAL
            vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
                                                         "%d", curbuf->b_fnum);
***************
*** 4525,4533 ****
                    itemisflag = FALSE;
                }
            }
  #endif
            break;
! 
        case STL_LINE:
            num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
                  ? 0L : (long)(wp->w_cursor.lnum);
--- 4557,4598 ----
                    itemisflag = FALSE;
                }
            }
+ 
+           // If the output of the expression needs to be evaluated
+           // replace the %{} block with the result of evaluation
+           if (reevaluate && str != NULL && *str != 0
+                   && strchr((const char *)str, '%') != NULL
+                   && evaldepth < MAX_STL_EVAL_DEPTH)
+           {
+               size_t parsed_usefmt = (size_t)(block_start - usefmt);
+               size_t str_length = strlen((const char *)str);
+               size_t fmt_length = strlen((const char *)s);
+               size_t new_fmt_len = parsed_usefmt
+                                                + str_length + fmt_length + 3;
+               char_u *new_fmt = (char_u *)alloc(new_fmt_len * sizeof(char_u));
+               char_u *new_fmt_p = new_fmt;
+ 
+               new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, parsed_usefmt)
+                                                              + parsed_usefmt;
+               new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length)
+                                                                 + str_length;
+               new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2;
+               new_fmt_p = (char_u *)memcpy(new_fmt_p , s, fmt_length)
+                                                                 + fmt_length;
+               *new_fmt_p = 0;
+               new_fmt_p = NULL;
+ 
+               if (usefmt != fmt)
+                   vim_free(usefmt);
+               VIM_CLEAR(str);
+               usefmt = new_fmt;
+               s = usefmt + parsed_usefmt;
+               evaldepth++;
+               continue;
+           }
  #endif
            break;
!       }
        case STL_LINE:
            num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
                  ? 0L : (long)(wp->w_cursor.lnum);
*** ../vim-8.2.2853/src/optionstr.c     2021-05-03 20:40:35.263818664 +0200
--- src/optionstr.c     2021-05-15 17:00:55.640446428 +0200
***************
*** 618,625 ****
        }
        if (*s == '{')
        {
            s++;
!           while (*s != '}' && *s)
                s++;
            if (*s != '}')
                return N_("E540: Unclosed expression sequence");
--- 618,627 ----
        }
        if (*s == '{')
        {
+           int reevaluate = (*s == '%');
+ 
            s++;
!           while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s)
                s++;
            if (*s != '}')
                return N_("E540: Unclosed expression sequence");
*** ../vim-8.2.2853/src/testdir/test_statusline.vim     2021-04-08 
18:27:49.525472168 +0200
--- src/testdir/test_statusline.vim     2021-05-15 17:20:46.167510458 +0200
***************
*** 251,256 ****
--- 251,276 ----
    call assert_match('^vimLineComment\s*$', s:get_statusline())
    syntax off
  
+   "%{%expr%}: evaluates enxpressions present in result of expr
+   func! Inner_eval()
+     return '%n some other text'
+   endfunc
+   func! Outer_eval()
+     return 'some text %{%Inner_eval()%}'
+   endfunc
+   set statusline=%{%Outer_eval()%}
+   call assert_match('^some text ' . bufnr() . ' some other text\s*$', 
s:get_statusline())
+   delfunc Inner_eval
+   delfunc Outer_eval
+ 
+   "%{%expr%}: Doesn't get stuck in recursion
+   func! Recurse_eval()
+     return '%{%Recurse_eval()%}'
+   endfunc
+   set statusline=%{%Recurse_eval()%}
+   call assert_match('^%{%Recurse_eval()%}\s*$', s:get_statusline())
+   delfunc Recurse_eval
+ 
    "%(: Start of item group.
    set statusline=ab%(cd%q%)de
    call assert_match('^abde\s*$', s:get_statusline())
*** ../vim-8.2.2853/src/version.c       2021-05-15 15:09:02.144699051 +0200
--- src/version.c       2021-05-15 17:21:18.095377858 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2854,
  /**/

-- 
This is an airconditioned room, do not open Windows.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202105151524.14FFOA3t3347989%40masaka.moolenaar.net.

Raspunde prin e-mail lui