patch 9.0.0761: cannot use 'indentexpr' for Lisp indenting v9.0.0761
authorBram Moolenaar <Bram@vim.org>
Sat, 15 Oct 2022 15:05:33 +0000 (16:05 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 15 Oct 2022 15:05:33 +0000 (16:05 +0100)
Problem:    Cannot use 'indentexpr' for Lisp indenting.
Solution:   Add the 'lispoptions' option.

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

index 6f479bdc95341e45649ad026efd8ecdc9e89741c..9ecb64e59aef69024bcf92325d67756e8422eff1 100644 (file)
@@ -4621,7 +4621,7 @@ A jump table for the options with a short description can be found at |Q_op|.
        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 short description can be found at |Q_op|.
        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|
index 5f8512ae92f4860c810326f540d43c52c94e3406..0849b70997ad28d5b30240d0dacf4dfd9d6ef99e 100644 (file)
@@ -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);
index c409acdadd5e2a68cc480e18019e8725132916a8..f036a3767ce501d5c04085cf364efc85325ef110 100644 (file)
@@ -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)
index c6e3aaf33d437af0bf4de85ecbced496f1364732..aaf3caafc4d63a1ea23e11350d61bd9b851199a6 100644 (file)
@@ -2196,6 +2196,22 @@ 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'.
  */
@@ -2203,12 +2219,16 @@ fixthisline(int (*get_the_indent)(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)
index 85a55f987c22cc18e7b2d1aab0f8af04b09f251a..329781008015d2dee930fa27b174536860330da9 100644 (file)
@@ -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;
index 6d05f0e29914b3d9ebb6b542c7e42c9c455d0c09..e266d387ea6d2948dfd18d1d5bdb747bb2dd6fde 100644 (file)
@@ -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
index db85a39891ec1587e9cad1031c75204d1eda72b3..9ea86029058806ca7caf93425a01e82b25746ea7 100644 (file)
 #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)
 #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},
index 32663a03e7832e17e1456d710fb324a625c277a6..9e9d18f0e3548c27f8b150409e725a6b16f3103a 100644 (file)
@@ -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)
index 2702f40ab7ab03373c47ec4fe9e51e3d708fd79e..5ab338dce22ebfd443550fe7a58bfa85d03d4255 100644 (file)
@@ -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);
index 3c8660e0ab1c5bfce89f845897fa6408ea70eea9..770c50115e8a3cc473310508827dbc0f3b1f7981 100644 (file)
@@ -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
 
index 0ccdf46360e7ffc71c324dc9f99d2bf83cc98f24..6e602bea3ad2e2f3e8b7e586ccebeb38eed52b4f 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    761,
 /**/
     760,
 /**/