vim-patch:9.0.0761: cannot use 'indentexpr' for Lisp indenting

Problem:    Cannot use 'indentexpr' for Lisp indenting.
Solution:   Add the 'lispoptions' option.
49846fb1a3

vim-patch:9.0.0762: build failure

Problem:    Build failure.
Solution:   Add missing change.
4b082c4bd0
This commit is contained in:
zeertzjq
2022-10-16 08:06:07 +08:00
parent bc798dfd8c
commit 19eb7054ff
13 changed files with 107 additions and 43 deletions

View File

@@ -3352,7 +3352,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. in Insert mode as specified with the 'indentkeys' option.
When this option is not empty, it overrules the 'cindent' and When this option is not empty, it overrules the 'cindent' and
'smartindent' indenting. When 'lisp' is set, this option is '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. When 'paste' is set this option is not used for indenting.
The expression is evaluated with |v:lnum| set to the line number for 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 which the indent is to be computed. The cursor is also in this line
@@ -3719,6 +3719,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. calling an external program if 'equalprg' is empty.
This option is not used when 'paste' is set. 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'*
'lispwords' 'lw' string (default is very long) 'lispwords' 'lw' string (default is very long)
global or local to buffer |global-local| global or local to buffer |global-local|

View File

@@ -1959,8 +1959,9 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_ft); clear_string_option(&buf->b_p_ft);
clear_string_option(&buf->b_p_cink); clear_string_option(&buf->b_p_cink);
clear_string_option(&buf->b_p_cino); clear_string_option(&buf->b_p_cino);
clear_string_option(&buf->b_p_cinw); clear_string_option(&buf->b_p_lop);
clear_string_option(&buf->b_p_cinsd); clear_string_option(&buf->b_p_cinsd);
clear_string_option(&buf->b_p_cinw);
clear_string_option(&buf->b_p_cpt); clear_string_option(&buf->b_p_cpt);
clear_string_option(&buf->b_p_cfu); clear_string_option(&buf->b_p_cfu);
clear_string_option(&buf->b_p_ofu); clear_string_option(&buf->b_p_ofu);

View File

@@ -699,6 +699,7 @@ struct file_buffer {
uint32_t b_p_fex_flags; ///< flags for 'formatexpr' uint32_t b_p_fex_flags; ///< flags for 'formatexpr'
char *b_p_kp; ///< 'keywordprg' char *b_p_kp; ///< 'keywordprg'
int b_p_lisp; ///< 'lisp' int b_p_lisp; ///< 'lisp'
char *b_p_lop; ///< 'lispoptions'
char *b_p_menc; ///< 'makeencoding' char *b_p_menc; ///< 'makeencoding'
char *b_p_mps; ///< 'matchpairs' char *b_p_mps; ///< 'matchpairs'
int b_p_ml; ///< 'modeline' int b_p_ml; ///< 'modeline'

View File

@@ -1814,17 +1814,19 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
vreplace_mode = 0; vreplace_mode = 0;
} }
if (!p_paste if (!p_paste) {
&& leader == NULL if (leader == NULL
&& curbuf->b_p_lisp && !use_indentexpr_for_lisp()
&& curbuf->b_p_ai) { && curbuf->b_p_lisp
// do lisp indenting && curbuf->b_p_ai) {
fixthisline(get_lisp_indent); // do lisp indenting
ai_col = (colnr_T)getwhitecols_curline(); fixthisline(get_lisp_indent);
} else if (do_cindent) { ai_col = (colnr_T)getwhitecols_curline();
// do 'cindent' or 'indentexpr' indenting } else if (do_cindent || (curbuf->b_p_ai && use_indentexpr_for_lisp())) {
do_c_expr_indent(); // do 'cindent' or 'indentexpr' indenting
ai_col = (colnr_T)getwhitecols_curline(); do_c_expr_indent();
ai_col = (colnr_T)getwhitecols_curline();
}
} }
if (vreplace_mode != 0) { if (vreplace_mode != 0) {

View File

@@ -2993,34 +2993,6 @@ bool cindent_on(void)
return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL); return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL);
} }
// Re-indent the current line, based on the current contents of it and the
// surrounding lines. Fixing the cursor position seems really easy -- I'm very
// confused what all the part that handles Control-T is doing that I'm not.
// "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
void fixthisline(IndentGetter get_the_indent)
{
int amount = get_the_indent();
if (amount >= 0) {
change_indent(INDENT_SET, amount, false, 0, true);
if (linewhite(curwin->w_cursor.lnum)) {
did_ai = true; // delete the indent if the line stays empty
}
}
}
void fix_indent(void)
{
if (p_paste) {
return;
}
if (curbuf->b_p_lisp && curbuf->b_p_ai) {
fixthisline(get_lisp_indent);
} else if (cindent_on()) {
do_c_expr_indent();
}
}
/// Check that "cinkeys" contains the key "keytyped", /// Check that "cinkeys" contains the key "keytyped",
/// when == '*': Only if key is preceded with '*' (indent before insert) /// when == '*': Only if key is preceded with '*' (indent before insert)
/// when == '!': Only if key is preceded with '!' (don't insert) /// when == '!': Only if key is preceded with '!' (don't insert)

View File

@@ -4,8 +4,6 @@
#include "nvim/autocmd.h" #include "nvim/autocmd.h"
#include "nvim/vim.h" #include "nvim/vim.h"
typedef int (*IndentGetter)(void);
// Values for in_cinkeys() // Values for in_cinkeys()
#define KEY_OPEN_FORW 0x101 #define KEY_OPEN_FORW 0x101
#define KEY_OPEN_BACK 0x102 #define KEY_OPEN_BACK 0x102

View File

@@ -15,6 +15,7 @@
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/extmark.h" #include "nvim/extmark.h"
#include "nvim/indent.h" #include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/mark.h" #include "nvim/mark.h"
#include "nvim/memline.h" #include "nvim/memline.h"
#include "nvim/memory.h" #include "nvim/memory.h"
@@ -1144,3 +1145,45 @@ static int lisp_match(char_u *p)
} }
return false; return false;
} }
/// Re-indent the current line, based on the current contents of it and the
/// surrounding lines. Fixing the cursor position seems really easy -- I'm very
/// confused what all the part that handles Control-T is doing that I'm not.
/// "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
void fixthisline(IndentGetter get_the_indent)
{
int amount = get_the_indent();
if (amount >= 0) {
change_indent(INDENT_SET, amount, false, 0, true);
if (linewhite(curwin->w_cursor.lnum)) {
did_ai = true; // delete the indent if the line stays empty
}
}
}
/// Return true if 'indentexpr' should be used for Lisp indenting.
/// Caller may want to check 'autoindent'.
bool use_indentexpr_for_lisp(void)
{
return curbuf->b_p_lisp
&& *curbuf->b_p_inde != NUL
&& strcmp(curbuf->b_p_lop, "expr:1") == 0;
}
/// Fix indent for 'lisp' and 'cindent'.
void fix_indent(void)
{
if (p_paste) {
return; // no auto-indenting when 'paste' is set
}
if (curbuf->b_p_lisp && curbuf->b_p_ai) {
if (use_indentexpr_for_lisp()) {
do_c_expr_indent();
} else {
fixthisline(get_lisp_indent);
}
} else if (cindent_on()) {
do_c_expr_indent();
}
}

View File

@@ -3,6 +3,8 @@
#include "nvim/vim.h" #include "nvim/vim.h"
typedef int (*IndentGetter)(void);
// flags for set_indent() // flags for set_indent()
#define SIN_CHANGED 1 // call changed_bytes() when line changed #define SIN_CHANGED 1 // call changed_bytes() when line changed
#define SIN_INSERT 2 // insert indent before existing text #define SIN_INSERT 2 // insert indent before existing text

View File

@@ -4008,6 +4008,8 @@ static char_u *get_varp(vimoption_T *p)
return (char_u *)&(curbuf->b_p_fex); return (char_u *)&(curbuf->b_p_fex);
case PV_LISP: case PV_LISP:
return (char_u *)&(curbuf->b_p_lisp); return (char_u *)&(curbuf->b_p_lisp);
case PV_LOP:
return (char_u *)&(curbuf->b_p_lop);
case PV_ML: case PV_ML:
return (char_u *)&(curbuf->b_p_ml); return (char_u *)&(curbuf->b_p_ml);
case PV_MPS: case PV_MPS:
@@ -4414,6 +4416,8 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_CINO); COPY_OPT_SCTX(buf, BV_CINO);
buf->b_p_cinsd = xstrdup(p_cinsd); buf->b_p_cinsd = xstrdup(p_cinsd);
COPY_OPT_SCTX(buf, BV_CINSD); COPY_OPT_SCTX(buf, BV_CINSD);
buf->b_p_lop = xstrdup(p_lop);
COPY_OPT_SCTX(buf, BV_LOP);
// Don't copy 'filetype', it must be detected // Don't copy 'filetype', it must be detected
buf->b_p_ft = empty_option; buf->b_p_ft = empty_option;

View File

@@ -580,6 +580,7 @@ EXTERN char_u *p_lm; // 'langmenu'
EXTERN long p_lines; // 'lines' EXTERN long p_lines; // 'lines'
EXTERN long p_linespace; // 'linespace' EXTERN long p_linespace; // 'linespace'
EXTERN int p_lisp; ///< 'lisp' EXTERN int p_lisp; ///< 'lisp'
EXTERN char *p_lop; ///< 'lispoptions'
EXTERN char_u *p_lispwords; // 'lispwords' EXTERN char_u *p_lispwords; // 'lispwords'
EXTERN long p_ls; // 'laststatus' EXTERN long p_ls; // 'laststatus'
EXTERN long p_stal; // 'showtabline' EXTERN long p_stal; // 'showtabline'
@@ -878,6 +879,7 @@ enum {
BV_KMAP, BV_KMAP,
BV_KP, BV_KP,
BV_LISP, BV_LISP,
BV_LOP,
BV_LW, BV_LW,
BV_MENC, BV_MENC,
BV_MA, BV_MA,

View File

@@ -1363,6 +1363,14 @@ return {
varname='p_lisp', varname='p_lisp',
defaults={if_true=false} defaults={if_true=false}
}, },
{
full_name='lispoptions', abbreviation='lop',
short_desc=N_("options for lisp indenting"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
varname='p_lop', pv_name='p_lop',
defaults={if_true=''}
},
{ {
full_name='lispwords', abbreviation='lw', full_name='lispwords', abbreviation='lw',
short_desc=N_("words that change how lisp indenting works"), short_desc=N_("words that change how lisp indenting works"),

View File

@@ -228,6 +228,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_cink); check_string_option(&buf->b_p_cink);
check_string_option(&buf->b_p_cino); check_string_option(&buf->b_p_cino);
parse_cino(buf); parse_cino(buf);
check_string_option(&buf->b_p_lop);
check_string_option(&buf->b_p_ft); check_string_option(&buf->b_p_ft);
check_string_option(&buf->b_p_cinw); check_string_option(&buf->b_p_cinw);
check_string_option(&buf->b_p_cinsd); check_string_option(&buf->b_p_cinsd);
@@ -1378,6 +1379,10 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
} else if (gvarp == &p_cino) { // 'cinoptions' } else if (gvarp == &p_cino) { // 'cinoptions'
// TODO(vim): recognize errors // TODO(vim): recognize errors
parse_cino(curbuf); parse_cino(curbuf);
} else if (gvarp == &p_lop) { // 'lispoptions'
if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) {
errmsg = e_invarg;
}
} else if (varp == &p_icm) { // 'inccommand' } else if (varp == &p_icm) { // 'inccommand'
if (check_opt_strings(p_icm, p_icm_values, false) != OK) { if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
errmsg = e_invarg; errmsg = e_invarg;

View File

@@ -97,8 +97,23 @@ func Test_lispindent_with_indentexpr()
exe "normal a(x\<CR>1\<CR>2)\<Esc>" exe "normal a(x\<CR>1\<CR>2)\<Esc>"
let expected = ['(x', ' 1', ' 2)'] let expected = ['(x', ' 1', ' 2)']
call assert_equal(expected, getline(1, 3)) call assert_equal(expected, getline(1, 3))
" with Lisp indenting the first line is not indented
normal 1G=G normal 1G=G
call assert_equal(expected, getline(1, 3)) 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! bwipe!
endfunc endfunc