changeset 30853:40df8a6515f6 v9.0.0761

patch 9.0.0761: cannot use 'indentexpr' for Lisp indenting Commit: https://github.com/vim/vim/commit/49846fb1a31de99f49d6a7e70efe685197423c84 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Oct 15 16:05:33 2022 +0100 patch 9.0.0761: cannot use 'indentexpr' for Lisp indenting Problem: Cannot use 'indentexpr' for Lisp indenting. Solution: Add the 'lispoptions' option.
author Bram Moolenaar <Bram@vim.org>
date Sat, 15 Oct 2022 17:15:04 +0200
parents 46157e3ebe96
children 5a3768b95027
files runtime/doc/options.txt src/buffer.c src/change.c src/indent.c src/option.c src/option.h src/optiondefs.h src/optionstr.c src/proto/indent.pro src/testdir/test_lispindent.vim src/version.c
diffstat 11 files changed, 95 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4621,7 +4621,7 @@ A jump table for the options with a shor
 	in Insert mode as specified with the 'indentkeys' option.
 	When this option is not empty, it overrules the 'cindent' and
 	'smartindent' indenting.  When 'lisp' is set, this option is
-	overridden by the Lisp indentation algorithm.
+	is only used when 'lispoptions' contains "expr:1".
 	When 'paste' is set this option is not used for indenting.
 	The expression is evaluated with |v:lnum| set to the line number for
 	which the indent is to be computed.  The cursor is also in this line
@@ -5063,6 +5063,17 @@ A jump table for the options with a shor
 	calling an external program if 'equalprg' is empty.
 	This option is not used when 'paste' is set.
 
+						*'lispoptions'* *'lop'*
+'lispoptions' 'lop'	string	(default "")
+			local to buffer
+	Comma-separated list of items that influence the Lisp indenting when
+	enabled with the |'lisp'| option.  Currently only one item is
+	supported:
+		expr:1	use 'indentexpr' for Lisp indenting when it is set
+		expr:0	do not use 'indentexpr' for Lisp indenting (default)
+	Note that when using 'indentexpr' the `=` operator indents all the
+	lines, otherwise the first line is not indented (Vi-compatible).
+
 						*'lispwords'* *'lw'*
 'lispwords' 'lw'	string	(default is very long)
 			global or local to buffer |global-local|
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2390,6 +2390,7 @@ free_buf_options(
     clear_string_option(&buf->b_p_ft);
     clear_string_option(&buf->b_p_cink);
     clear_string_option(&buf->b_p_cino);
+    clear_string_option(&buf->b_p_lop);
     clear_string_option(&buf->b_p_cinsd);
     clear_string_option(&buf->b_p_cinw);
     clear_string_option(&buf->b_p_cpt);
--- a/src/change.c
+++ b/src/change.c
@@ -2269,20 +2269,23 @@ open_line(
     else
 	vreplace_mode = 0;
 
-    if (!p_paste
-	    && leader == NULL
-	    && curbuf->b_p_lisp
-	    && curbuf->b_p_ai)
+    if (!p_paste)
     {
-	// do lisp indenting
-	fixthisline(get_lisp_indent);
-	ai_col = (colnr_T)getwhitecols_curline();
-    }
-    else if (do_cindent)
-    {
-	// do 'cindent' or 'indentexpr' indenting
-	do_c_expr_indent();
-	ai_col = (colnr_T)getwhitecols_curline();
+	if (leader == NULL
+		&& !use_indentexpr_for_lisp()
+		&& curbuf->b_p_lisp
+		&& curbuf->b_p_ai)
+	{
+	    // do lisp indenting
+	    fixthisline(get_lisp_indent);
+	    ai_col = (colnr_T)getwhitecols_curline();
+	}
+	else if (do_cindent || (curbuf->b_p_ai && use_indentexpr_for_lisp()))
+	{
+	    // do 'cindent' or 'indentexpr' indenting
+	    do_c_expr_indent();
+	    ai_col = (colnr_T)getwhitecols_curline();
+	}
     }
 
     if (vreplace_mode != 0)
--- a/src/indent.c
+++ b/src/indent.c
@@ -2197,18 +2197,38 @@ fixthisline(int (*get_the_indent)(void))
 }
 
 /*
+ * Return TRUE if 'indentexpr' should be used for Lisp indenting.
+ * Caller may want to check 'autoindent'.
+ */
+    int
+use_indentexpr_for_lisp(void)
+{
+#ifdef FEAT_EVAL
+    return curbuf->b_p_lisp
+		&& *curbuf->b_p_inde != NUL
+		&& STRCMP(curbuf->b_p_lop, "expr:1") == 0;
+#else
+    return FALSE;
+#endif
+}
+
+/*
  * Fix indent for 'lisp' and 'cindent'.
  */
     void
 fix_indent(void)
 {
     if (p_paste)
-	return;
+	return;  // no auto-indenting when 'paste' is set
     if (curbuf->b_p_lisp && curbuf->b_p_ai)
-	fixthisline(get_lisp_indent);
-    else
-	if (cindent_on())
+    {
+	if (use_indentexpr_for_lisp())
 	    do_c_expr_indent();
+	else
+	    fixthisline(get_lisp_indent);
+    }
+    else if (cindent_on())
+	do_c_expr_indent();
 }
 
 #if defined(FEAT_EVAL) || defined(PROTO)
--- a/src/option.c
+++ b/src/option.c
@@ -5518,6 +5518,7 @@ get_varp(struct vimoption *p)
 	case PV_KEY:	return (char_u *)&(curbuf->b_p_key);
 #endif
 	case PV_LISP:	return (char_u *)&(curbuf->b_p_lisp);
+	case PV_LOP:	return (char_u *)&(curbuf->b_p_lop);
 	case PV_ML:	return (char_u *)&(curbuf->b_p_ml);
 	case PV_MPS:	return (char_u *)&(curbuf->b_p_mps);
 	case PV_MA:	return (char_u *)&(curbuf->b_p_ma);
@@ -6047,6 +6048,8 @@ buf_copy_options(buf_T *buf, int flags)
 	    COPY_OPT_SCTX(buf, BV_CINO);
 	    buf->b_p_cinsd = vim_strsave(p_cinsd);
 	    COPY_OPT_SCTX(buf, BV_CINSD);
+	    buf->b_p_lop = vim_strsave(p_lop);
+	    COPY_OPT_SCTX(buf, BV_LOP);
 
 	    // Don't copy 'filetype', it must be detected
 	    buf->b_p_ft = empty_option;
--- a/src/option.h
+++ b/src/option.h
@@ -709,6 +709,7 @@ EXTERN char_u	*p_lm;		// 'langmenu'
 EXTERN long	p_linespace;	// 'linespace'
 #endif
 EXTERN int	p_lisp;		// 'lisp'
+EXTERN char_u	*p_lop;		// 'lispoptions'
 EXTERN char_u	*p_lispwords;	// 'lispwords'
 EXTERN long	p_ls;		// 'laststatus'
 EXTERN long	p_stal;		// 'showtabline'
@@ -1155,6 +1156,7 @@ enum
 #endif
     , BV_KP
     , BV_LISP
+    , BV_LOP
     , BV_LW
     , BV_MENC
     , BV_MA
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -41,17 +41,17 @@
 #define PV_BOMB		OPT_BUF(BV_BOMB)
 #define PV_CI		OPT_BUF(BV_CI)
 #define PV_CIN		OPT_BUF(BV_CIN)
-#define PV_CINK	OPT_BUF(BV_CINK)
-#define PV_CINO	OPT_BUF(BV_CINO)
+#define PV_CINK		OPT_BUF(BV_CINK)
+#define PV_CINO		OPT_BUF(BV_CINO)
 #define PV_CINSD	OPT_BUF(BV_CINSD)
-#define PV_CINW	OPT_BUF(BV_CINW)
+#define PV_CINW		OPT_BUF(BV_CINW)
 #define PV_CM		OPT_BOTH(OPT_BUF(BV_CM))
 #ifdef FEAT_FOLDING
 # define PV_CMS		OPT_BUF(BV_CMS)
 #endif
 #define PV_COM		OPT_BUF(BV_COM)
 #define PV_CPT		OPT_BUF(BV_CPT)
-#define PV_DICT	OPT_BOTH(OPT_BUF(BV_DICT))
+#define PV_DICT		OPT_BOTH(OPT_BUF(BV_DICT))
 #define PV_TSR		OPT_BOTH(OPT_BUF(BV_TSR))
 #define PV_CSL		OPT_BUF(BV_CSL)
 #ifdef FEAT_COMPL_FUNC
@@ -95,7 +95,8 @@
 # define PV_KMAP	OPT_BUF(BV_KMAP)
 #endif
 #define PV_KP		OPT_BOTH(OPT_BUF(BV_KP))
-#define PV_LISP	OPT_BUF(BV_LISP)
+#define PV_LISP		OPT_BUF(BV_LISP)
+#define PV_LOP		OPT_BUF(BV_LOP)
 #define PV_LW		OPT_BOTH(OPT_BUF(BV_LW))
 #define PV_MENC		OPT_BOTH(OPT_BUF(BV_MENC))
 #define PV_MA		OPT_BUF(BV_MA)
@@ -142,7 +143,7 @@
 #endif
 #define PV_WM		OPT_BUF(BV_WM)
 #ifdef FEAT_VARTABS
-# define PV_VSTS		OPT_BUF(BV_VSTS)
+# define PV_VSTS	OPT_BUF(BV_VSTS)
 # define PV_VTS		OPT_BUF(BV_VTS)
 #endif
 
@@ -1522,6 +1523,9 @@ static struct vimoption options[] =
     {"lisp",	    NULL,   P_BOOL|P_VI_DEF,
 			    (char_u *)&p_lisp, PV_LISP,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+    {"lispoptions", "lop",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+			    (char_u *)&p_lop, PV_LOP,
+			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"lispwords",   "lw",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 			    (char_u *)&p_lispwords, PV_LW,
 			    {(char_u *)LISPWORD_VALUE, (char_u *)0L} SCTX_INIT},
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -259,6 +259,7 @@ check_buf_options(buf_T *buf)
     check_string_option(&buf->b_p_cino);
     check_string_option(&buf->b_p_cinsd);
     parse_cino(buf);
+    check_string_option(&buf->b_p_lop);
     check_string_option(&buf->b_p_ft);
     check_string_option(&buf->b_p_cinw);
     check_string_option(&buf->b_p_cpt);
@@ -2102,6 +2103,14 @@ did_set_string_option(
 	parse_cino(curbuf);
     }
 
+    // 'lispoptions'
+    else if (gvarp == &p_lop)
+    {
+	if (**varp != NUL && STRCMP(*varp, "expr:0") != 0
+					       && STRCMP(*varp, "expr:1") != 0)
+	    errmsg = e_invalid_argument;
+    }
+
 #if defined(FEAT_RENDER_OPTIONS)
     // 'renderoptions'
     else if (varp == &p_rop)
--- a/src/proto/indent.pro
+++ b/src/proto/indent.pro
@@ -31,6 +31,7 @@ void ex_retab(exarg_T *eap);
 int get_expr_indent(void);
 int get_lisp_indent(void);
 void fixthisline(int (*get_the_indent)(void));
+int use_indentexpr_for_lisp(void);
 void fix_indent(void);
 void f_indent(typval_T *argvars, typval_T *rettv);
 void f_lispindent(typval_T *argvars, typval_T *rettv);
--- a/src/testdir/test_lispindent.vim
+++ b/src/testdir/test_lispindent.vim
@@ -97,8 +97,23 @@ func Test_lispindent_with_indentexpr()
   exe "normal a(x\<CR>1\<CR>2)\<Esc>"
   let expected = ['(x', '  1', '  2)']
   call assert_equal(expected, getline(1, 3))
+  " with Lisp indenting the first line is not indented
   normal 1G=G
   call assert_equal(expected, getline(1, 3))
+
+  %del
+  setl lispoptions=expr:1 indentexpr=5
+  exe "normal a(x\<CR>1\<CR>2)\<Esc>"
+  let expected_expr = ['(x', '     1', '     2)']
+  call assert_equal(expected_expr, getline(1, 3))
+  normal 2G2<<=G
+  call assert_equal(expected_expr, getline(1, 3))
+
+  setl lispoptions=expr:0
+  " with Lisp indenting the first line is not indented
+  normal 1G3<<=G
+  call assert_equal(expected, getline(1, 3))
+
   bwipe!
 endfunc
 
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    761,
+/**/
     760,
 /**/
     759,