diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-10-16 08:06:07 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-10-16 08:34:55 +0800 |
commit | 19eb7054ff7b1fbc78e56e7f9ed6537b085147bc (patch) | |
tree | f10b35a7a415ebd3cbfc3b944aec96e65892becc | |
parent | bc798dfd8cea9a5f93461e05dcb8409b6d96afc0 (diff) | |
download | rneovim-19eb7054ff7b1fbc78e56e7f9ed6537b085147bc.tar.gz rneovim-19eb7054ff7b1fbc78e56e7f9ed6537b085147bc.tar.bz2 rneovim-19eb7054ff7b1fbc78e56e7f9ed6537b085147bc.zip |
vim-patch:9.0.0761: cannot use 'indentexpr' for Lisp indenting
Problem: Cannot use 'indentexpr' for Lisp indenting.
Solution: Add the 'lispoptions' option.
https://github.com/vim/vim/commit/49846fb1a31de99f49d6a7e70efe685197423c84
vim-patch:9.0.0762: build failure
Problem: Build failure.
Solution: Add missing change.
https://github.com/vim/vim/commit/4b082c4bd05f504fda1acaa9d28fca55a2d04857
-rw-r--r-- | runtime/doc/options.txt | 13 | ||||
-rw-r--r-- | src/nvim/buffer.c | 3 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/change.c | 24 | ||||
-rw-r--r-- | src/nvim/edit.c | 28 | ||||
-rw-r--r-- | src/nvim/edit.h | 2 | ||||
-rw-r--r-- | src/nvim/indent.c | 43 | ||||
-rw-r--r-- | src/nvim/indent.h | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 4 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 8 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 5 | ||||
-rw-r--r-- | src/nvim/testdir/test_lispindent.vim | 15 |
13 files changed, 107 insertions, 43 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index a846f49781..3e056ffc28 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -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| diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 29b00bad2a..84ff2fa59b 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -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); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 630e1d14a8..043a31bf16 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -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' diff --git a/src/nvim/change.c b/src/nvim/change.c index c6f9e9f5c2..2424a8a2eb 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -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) { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 0e14567286..e37f967a2c 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -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) diff --git a/src/nvim/edit.h b/src/nvim/edit.h index eda6d8c9db..91c519f015 100644 --- a/src/nvim/edit.h +++ b/src/nvim/edit.h @@ -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 diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 3f5a8afbc1..3f08aa7043 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -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(); + } +} diff --git a/src/nvim/indent.h b/src/nvim/indent.h index f96732bf1c..f807bbb42b 100644 --- a/src/nvim/indent.h +++ b/src/nvim/indent.h @@ -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 diff --git a/src/nvim/option.c b/src/nvim/option.c index 7202156c46..0b819aad43 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -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; diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 196ab865a2..c4333a6f61 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -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, diff --git a/src/nvim/options.lua b/src/nvim/options.lua index f4d6c808fa..8a883a09c3 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1364,6 +1364,14 @@ return { 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"), type='string', list='onecomma', scope={'global', 'buffer'}, diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index be3e137b69..43628d2842 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -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; diff --git a/src/nvim/testdir/test_lispindent.vim b/src/nvim/testdir/test_lispindent.vim index 8987f67a80..2d6060bba3 100644 --- a/src/nvim/testdir/test_lispindent.vim +++ b/src/nvim/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 |