Merge pull request #20677 from zeertzjq/vim-9.0.0761

vim-patch:9.0.{0761,0762,0764}: 'lispoptions'
This commit is contained in:
zeertzjq 2022-10-16 08:56:26 +08:00 committed by GitHub
commit 0b71960ab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 112 additions and 44 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.
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
@ -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.
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|

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

@ -6206,7 +6206,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
// If 'equalprg' is empty, do the indenting internally.
if (oap->op_type == OP_INDENT && *get_equalprg() == NUL) {
if (curbuf->b_p_lisp) {
op_reindent(oap, get_lisp_indent);
if (use_indentexpr_for_lisp()) {
op_reindent(oap, get_expr_indent);
} else {
op_reindent(oap, get_lisp_indent);
}
break;
}
op_reindent(oap,

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