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

@@ -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_cink);
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_cinw);
clear_string_option(&buf->b_p_cpt);
clear_string_option(&buf->b_p_cfu);
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'
char *b_p_kp; ///< 'keywordprg'
int b_p_lisp; ///< 'lisp'
char *b_p_lop; ///< 'lispoptions'
char *b_p_menc; ///< 'makeencoding'
char *b_p_mps; ///< 'matchpairs'
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;
}
if (!p_paste
&& leader == NULL
&& 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) {
// do 'cindent' or 'indentexpr' indenting
do_c_expr_indent();
ai_col = (colnr_T)getwhitecols_curline();
if (!p_paste) {
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) {

View File

@@ -2993,34 +2993,6 @@ bool cindent_on(void)
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",
/// when == '*': Only if key is preceded with '*' (indent before insert)
/// when == '!': Only if key is preceded with '!' (don't insert)

View File

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

View File

@@ -15,6 +15,7 @@
#include "nvim/eval.h"
#include "nvim/extmark.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -1144,3 +1145,45 @@ static int lisp_match(char_u *p)
}
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"
typedef int (*IndentGetter)(void);
// flags for set_indent()
#define SIN_CHANGED 1 // call changed_bytes() when line changed
#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);
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:
@@ -4414,6 +4416,8 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_CINO);
buf->b_p_cinsd = xstrdup(p_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
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_linespace; // 'linespace'
EXTERN int p_lisp; ///< 'lisp'
EXTERN char *p_lop; ///< 'lispoptions'
EXTERN char_u *p_lispwords; // 'lispwords'
EXTERN long p_ls; // 'laststatus'
EXTERN long p_stal; // 'showtabline'
@@ -878,6 +879,7 @@ enum {
BV_KMAP,
BV_KP,
BV_LISP,
BV_LOP,
BV_LW,
BV_MENC,
BV_MA,

View File

@@ -1363,6 +1363,14 @@ return {
varname='p_lisp',
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',
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_cino);
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_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'
// TODO(vim): recognize errors
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'
if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
errmsg = e_invarg;

View 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