mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	vim-patch:8.2.2854: custom statusline cannot contain % items (#14558)
Problem:    Custom statusline cannot contain % items.
Solution:   Add "%{% expr %}". (closes vim/vim#8190)
30e3de21fc
			
			
This commit is contained in:
		@@ -5923,6 +5923,18 @@ A jump table for the options with a short description can be found at |Q_op|.
 | 
			
		||||
	      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.
 | 
			
		||||
 
 | 
			
		||||
@@ -85,6 +85,9 @@
 | 
			
		||||
# include "buffer.c.generated.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Determines how deeply nested %{} blocks will be evaluated in statusline.
 | 
			
		||||
#define MAX_STL_EVAL_DEPTH 100
 | 
			
		||||
 | 
			
		||||
static char *msg_loclist = N_("[Location List]");
 | 
			
		||||
static char *msg_qflist = N_("[Quickfix List]");
 | 
			
		||||
static char *e_auabort = N_("E855: Autocommands caused command to abort");
 | 
			
		||||
@@ -3572,6 +3575,7 @@ int build_stl_str_hl(
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int groupdepth = 0;
 | 
			
		||||
  int evaldepth  = 0;
 | 
			
		||||
 | 
			
		||||
  int curitem = 0;
 | 
			
		||||
  bool prevchar_isflag = true;
 | 
			
		||||
@@ -3909,6 +3913,13 @@ int build_stl_str_hl(
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Denotes end of expanded %{} block
 | 
			
		||||
    if (*fmt_p == '}' && evaldepth > 0) {
 | 
			
		||||
        fmt_p++;
 | 
			
		||||
        evaldepth--;
 | 
			
		||||
        continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // An invalid item was specified.
 | 
			
		||||
    // Continue processing on the next character of the format string.
 | 
			
		||||
    if (vim_strchr(STL_ALL, *fmt_p) == NULL) {
 | 
			
		||||
@@ -3950,18 +3961,30 @@ int build_stl_str_hl(
 | 
			
		||||
    }
 | 
			
		||||
    case STL_VIM_EXPR:     // '{'
 | 
			
		||||
    {
 | 
			
		||||
      char_u *block_start = fmt_p - 1;
 | 
			
		||||
      int reevaluate = (*fmt_p == '%');
 | 
			
		||||
      itemisflag = true;
 | 
			
		||||
 | 
			
		||||
      if (reevaluate) {
 | 
			
		||||
        fmt_p++;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Attempt to copy the expression to evaluate into
 | 
			
		||||
      // the output buffer as a null-terminated string.
 | 
			
		||||
      char_u *t = out_p;
 | 
			
		||||
      while (*fmt_p != '}' && *fmt_p != NUL && out_p < out_end_p)
 | 
			
		||||
      while ((*fmt_p != '}' || (reevaluate && fmt_p[-1] != '%'))
 | 
			
		||||
             && *fmt_p != NUL && out_p < out_end_p) {
 | 
			
		||||
        *out_p++ = *fmt_p++;
 | 
			
		||||
      }
 | 
			
		||||
      if (*fmt_p != '}') {          // missing '}' or out of space
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      fmt_p++;
 | 
			
		||||
      if (reevaluate) {
 | 
			
		||||
        out_p[-1] = 0;  // remove the % at the end of %{% expr %}
 | 
			
		||||
      } else {
 | 
			
		||||
        *out_p = 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Move our position in the output buffer
 | 
			
		||||
      // to the beginning of the expression
 | 
			
		||||
@@ -4007,6 +4030,40 @@ int build_stl_str_hl(
 | 
			
		||||
          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 *)fmt_p);
 | 
			
		||||
        size_t new_fmt_len = parsed_usefmt
 | 
			
		||||
          + str_length + fmt_length + 3;
 | 
			
		||||
        char_u *new_fmt = (char_u *)xmalloc(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 , fmt_p, fmt_length)
 | 
			
		||||
          + fmt_length;
 | 
			
		||||
        *new_fmt_p = 0;
 | 
			
		||||
        new_fmt_p = NULL;
 | 
			
		||||
 | 
			
		||||
        if (usefmt != fmt) {
 | 
			
		||||
          xfree(usefmt);
 | 
			
		||||
        }
 | 
			
		||||
        XFREE_CLEAR(str);
 | 
			
		||||
        usefmt = new_fmt;
 | 
			
		||||
        fmt_p = usefmt + parsed_usefmt;
 | 
			
		||||
        evaldepth++;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3641,9 +3641,11 @@ char_u *check_stl_option(char_u *s)
 | 
			
		||||
      return illegal_char(errbuf, sizeof(errbuf), *s);
 | 
			
		||||
    }
 | 
			
		||||
    if (*s == '{') {
 | 
			
		||||
      int reevaluate = (*s == '%');
 | 
			
		||||
      s++;
 | 
			
		||||
      while (*s != '}' && *s)
 | 
			
		||||
      while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s) {
 | 
			
		||||
        s++;
 | 
			
		||||
      }
 | 
			
		||||
      if (*s != '}') {
 | 
			
		||||
        return (char_u *)N_("E540: Unclosed expression sequence");
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -241,6 +241,26 @@ func Test_statusline()
 | 
			
		||||
  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())
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user