diff --git a/src/buffer.c b/src/buffer.c index 3115271370..c8d071ccd8 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -40,6 +40,7 @@ #include "fold.h" #include "getchar.h" #include "hashtab.h" +#include "indent.h" #include "indent_c.h" #include "main.h" #include "mark.h" diff --git a/src/indent.c b/src/indent.c index 5cf3bd5265..a6db81b672 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1,10 +1,12 @@ #include "indent.h" +#include "eval.h" #include "charset.h" #include "memline.h" #include "misc1.h" #include "misc2.h" #include "option.h" #include "regexp.h" +#include "search.h" #include "undo.h" /* @@ -399,3 +401,258 @@ int get_number_indent(linenr_T lnum) getvcol(curwin, &pos, &col, NULL, NULL); return (int)col; } + +/* + * When extra == 0: Return TRUE if the cursor is before or on the first + * non-blank in the line. + * When extra == 1: Return TRUE if the cursor is before the first non-blank in + * the line. + */ +int inindent(int extra) +{ + char_u *ptr; + colnr_T col; + + for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col) + ++ptr; + if (col >= curwin->w_cursor.col + extra) + return TRUE; + else + return FALSE; +} + +/* + * Get indent level from 'indentexpr'. + */ +int get_expr_indent(void) { + int indent; + pos_T save_pos; + colnr_T save_curswant; + int save_set_curswant; + int save_State; + int use_sandbox = was_set_insecurely((char_u *)"indentexpr", + OPT_LOCAL); + + /* Save and restore cursor position and curswant, in case it was changed + * via :normal commands */ + save_pos = curwin->w_cursor; + save_curswant = curwin->w_curswant; + save_set_curswant = curwin->w_set_curswant; + set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); + if (use_sandbox) + ++sandbox; + ++textlock; + indent = eval_to_number(curbuf->b_p_inde); + if (use_sandbox) + --sandbox; + --textlock; + + /* Restore the cursor position so that 'indentexpr' doesn't need to. + * Pretend to be in Insert mode, allow cursor past end of line for "o" + * command. */ + save_State = State; + State = INSERT; + curwin->w_cursor = save_pos; + curwin->w_curswant = save_curswant; + curwin->w_set_curswant = save_set_curswant; + check_cursor(); + State = save_State; + + /* If there is an error, just keep the current indent. */ + if (indent < 0) + indent = get_indent(); + + return indent; +} + +static int lisp_match(char_u *p); + +static int lisp_match(char_u *p) +{ + char_u buf[LSIZE]; + int len; + char_u *word = p_lispwords; + + while (*word != NUL) { + (void)copy_option_part(&word, buf, LSIZE, ","); + len = (int)STRLEN(buf); + if (STRNCMP(buf, p, len) == 0 && p[len] == ' ') + return TRUE; + } + return FALSE; +} + +/* + * When 'p' is present in 'cpoptions, a Vi compatible method is used. + * The incompatible newer method is quite a bit better at indenting + * code in lisp-like languages than the traditional one; it's still + * mostly heuristics however -- Dirk van Deun, dirk@rave.org + * + * TODO: + * Findmatch() should be adapted for lisp, also to make showmatch + * work correctly: now (v5.3) it seems all C/C++ oriented: + * - it does not recognize the #\( and #\) notations as character literals + * - it doesn't know about comments starting with a semicolon + * - it incorrectly interprets '(' as a character literal + * All this messes up get_lisp_indent in some rare cases. + * Update from Sergey Khorev: + * I tried to fix the first two issues. + */ +int get_lisp_indent(void) { + pos_T *pos, realpos, paren; + int amount; + char_u *that; + colnr_T col; + colnr_T firsttry; + int parencount, quotecount; + int vi_lisp; + + /* Set vi_lisp to use the vi-compatible method */ + vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL); + + realpos = curwin->w_cursor; + curwin->w_cursor.col = 0; + + if ((pos = findmatch(NULL, '(')) == NULL) + pos = findmatch(NULL, '['); + else { + paren = *pos; + pos = findmatch(NULL, '['); + if (pos == NULL || ltp(pos, &paren)) + pos = &paren; + } + if (pos != NULL) { + /* Extra trick: Take the indent of the first previous non-white + * line that is at the same () level. */ + amount = -1; + parencount = 0; + + while (--curwin->w_cursor.lnum >= pos->lnum) { + if (linewhite(curwin->w_cursor.lnum)) + continue; + for (that = ml_get_curline(); *that != NUL; ++that) { + if (*that == ';') { + while (*(that + 1) != NUL) + ++that; + continue; + } + if (*that == '\\') { + if (*(that + 1) != NUL) + ++that; + continue; + } + if (*that == '"' && *(that + 1) != NUL) { + while (*++that && *that != '"') { + /* skipping escaped characters in the string */ + if (*that == '\\') { + if (*++that == NUL) + break; + if (that[1] == NUL) { + ++that; + break; + } + } + } + } + if (*that == '(' || *that == '[') + ++parencount; + else if (*that == ')' || *that == ']') + --parencount; + } + if (parencount == 0) { + amount = get_indent(); + break; + } + } + + if (amount == -1) { + curwin->w_cursor.lnum = pos->lnum; + curwin->w_cursor.col = pos->col; + col = pos->col; + + that = ml_get_curline(); + + if (vi_lisp && get_indent() == 0) + amount = 2; + else { + amount = 0; + while (*that && col) { + amount += lbr_chartabsize_adv(&that, (colnr_T)amount); + col--; + } + + /* + * Some keywords require "body" indenting rules (the + * non-standard-lisp ones are Scheme special forms): + * + * (let ((a 1)) instead (let ((a 1)) + * (...)) of (...)) + */ + + if (!vi_lisp && (*that == '(' || *that == '[') + && lisp_match(that + 1)) + amount += 2; + else { + that++; + amount++; + firsttry = amount; + + while (vim_iswhite(*that)) { + amount += lbr_chartabsize(that, (colnr_T)amount); + ++that; + } + + if (*that && *that != ';') { /* not a comment line */ + /* test *that != '(' to accommodate first let/do + * argument if it is more than one line */ + if (!vi_lisp && *that != '(' && *that != '[') + firsttry++; + + parencount = 0; + quotecount = 0; + + if (vi_lisp + || (*that != '"' + && *that != '\'' + && *that != '#' + && (*that < '0' || *that > '9'))) { + while (*that + && (!vim_iswhite(*that) + || quotecount + || parencount) + && (!((*that == '(' || *that == '[') + && !quotecount + && !parencount + && vi_lisp))) { + if (*that == '"') + quotecount = !quotecount; + if ((*that == '(' || *that == '[') + && !quotecount) + ++parencount; + if ((*that == ')' || *that == ']') + && !quotecount) + --parencount; + if (*that == '\\' && *(that+1) != NUL) + amount += lbr_chartabsize_adv(&that, + (colnr_T)amount); + amount += lbr_chartabsize_adv(&that, + (colnr_T)amount); + } + } + while (vim_iswhite(*that)) { + amount += lbr_chartabsize(that, (colnr_T)amount); + that++; + } + if (!*that || *that == ';') + amount = firsttry; + } + } + } + } + } else + amount = 0; /* no matching '(' or '[' found, use zero indent */ + + curwin->w_cursor = realpos; + + return amount; +} diff --git a/src/indent.h b/src/indent.h index f256a95e31..a148eed94a 100644 --- a/src/indent.h +++ b/src/indent.h @@ -8,4 +8,7 @@ int get_indent_str(char_u *ptr, int ts); int set_indent(int size, int flags); int copy_indent(int size, char_u *src); int get_number_indent(linenr_T lnum); +int inindent(int extra); +int get_expr_indent(void); +int get_lisp_indent(void); #endif diff --git a/src/misc1.c b/src/misc1.c index 2cedc91b68..91e5313c96 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -1832,25 +1832,6 @@ void pchar_cursor(int c) + curwin->w_cursor.col) = c; } -/* - * When extra == 0: Return TRUE if the cursor is before or on the first - * non-blank in the line. - * When extra == 1: Return TRUE if the cursor is before the first non-blank in - * the line. - */ -int inindent(int extra) -{ - char_u *ptr; - colnr_T col; - - for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col) - ++ptr; - if (col >= curwin->w_cursor.col + extra) - return TRUE; - else - return FALSE; -} - /* * Skip to next part of an option argument: Skip space and comma. */ @@ -3787,242 +3768,6 @@ FullName_save ( return new_fname; } -/* - * Get indent level from 'indentexpr'. - */ -int get_expr_indent(void) { - int indent; - pos_T save_pos; - colnr_T save_curswant; - int save_set_curswant; - int save_State; - int use_sandbox = was_set_insecurely((char_u *)"indentexpr", - OPT_LOCAL); - - /* Save and restore cursor position and curswant, in case it was changed - * via :normal commands */ - save_pos = curwin->w_cursor; - save_curswant = curwin->w_curswant; - save_set_curswant = curwin->w_set_curswant; - set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); - if (use_sandbox) - ++sandbox; - ++textlock; - indent = eval_to_number(curbuf->b_p_inde); - if (use_sandbox) - --sandbox; - --textlock; - - /* Restore the cursor position so that 'indentexpr' doesn't need to. - * Pretend to be in Insert mode, allow cursor past end of line for "o" - * command. */ - save_State = State; - State = INSERT; - curwin->w_cursor = save_pos; - curwin->w_curswant = save_curswant; - curwin->w_set_curswant = save_set_curswant; - check_cursor(); - State = save_State; - - /* If there is an error, just keep the current indent. */ - if (indent < 0) - indent = get_indent(); - - return indent; -} - -static int lisp_match(char_u *p); - -static int lisp_match(char_u *p) -{ - char_u buf[LSIZE]; - int len; - char_u *word = p_lispwords; - - while (*word != NUL) { - (void)copy_option_part(&word, buf, LSIZE, ","); - len = (int)STRLEN(buf); - if (STRNCMP(buf, p, len) == 0 && p[len] == ' ') - return TRUE; - } - return FALSE; -} - -/* - * When 'p' is present in 'cpoptions, a Vi compatible method is used. - * The incompatible newer method is quite a bit better at indenting - * code in lisp-like languages than the traditional one; it's still - * mostly heuristics however -- Dirk van Deun, dirk@rave.org - * - * TODO: - * Findmatch() should be adapted for lisp, also to make showmatch - * work correctly: now (v5.3) it seems all C/C++ oriented: - * - it does not recognize the #\( and #\) notations as character literals - * - it doesn't know about comments starting with a semicolon - * - it incorrectly interprets '(' as a character literal - * All this messes up get_lisp_indent in some rare cases. - * Update from Sergey Khorev: - * I tried to fix the first two issues. - */ -int get_lisp_indent(void) { - pos_T *pos, realpos, paren; - int amount; - char_u *that; - colnr_T col; - colnr_T firsttry; - int parencount, quotecount; - int vi_lisp; - - /* Set vi_lisp to use the vi-compatible method */ - vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL); - - realpos = curwin->w_cursor; - curwin->w_cursor.col = 0; - - if ((pos = findmatch(NULL, '(')) == NULL) - pos = findmatch(NULL, '['); - else { - paren = *pos; - pos = findmatch(NULL, '['); - if (pos == NULL || ltp(pos, &paren)) - pos = &paren; - } - if (pos != NULL) { - /* Extra trick: Take the indent of the first previous non-white - * line that is at the same () level. */ - amount = -1; - parencount = 0; - - while (--curwin->w_cursor.lnum >= pos->lnum) { - if (linewhite(curwin->w_cursor.lnum)) - continue; - for (that = ml_get_curline(); *that != NUL; ++that) { - if (*that == ';') { - while (*(that + 1) != NUL) - ++that; - continue; - } - if (*that == '\\') { - if (*(that + 1) != NUL) - ++that; - continue; - } - if (*that == '"' && *(that + 1) != NUL) { - while (*++that && *that != '"') { - /* skipping escaped characters in the string */ - if (*that == '\\') { - if (*++that == NUL) - break; - if (that[1] == NUL) { - ++that; - break; - } - } - } - } - if (*that == '(' || *that == '[') - ++parencount; - else if (*that == ')' || *that == ']') - --parencount; - } - if (parencount == 0) { - amount = get_indent(); - break; - } - } - - if (amount == -1) { - curwin->w_cursor.lnum = pos->lnum; - curwin->w_cursor.col = pos->col; - col = pos->col; - - that = ml_get_curline(); - - if (vi_lisp && get_indent() == 0) - amount = 2; - else { - amount = 0; - while (*that && col) { - amount += lbr_chartabsize_adv(&that, (colnr_T)amount); - col--; - } - - /* - * Some keywords require "body" indenting rules (the - * non-standard-lisp ones are Scheme special forms): - * - * (let ((a 1)) instead (let ((a 1)) - * (...)) of (...)) - */ - - if (!vi_lisp && (*that == '(' || *that == '[') - && lisp_match(that + 1)) - amount += 2; - else { - that++; - amount++; - firsttry = amount; - - while (vim_iswhite(*that)) { - amount += lbr_chartabsize(that, (colnr_T)amount); - ++that; - } - - if (*that && *that != ';') { /* not a comment line */ - /* test *that != '(' to accommodate first let/do - * argument if it is more than one line */ - if (!vi_lisp && *that != '(' && *that != '[') - firsttry++; - - parencount = 0; - quotecount = 0; - - if (vi_lisp - || (*that != '"' - && *that != '\'' - && *that != '#' - && (*that < '0' || *that > '9'))) { - while (*that - && (!vim_iswhite(*that) - || quotecount - || parencount) - && (!((*that == '(' || *that == '[') - && !quotecount - && !parencount - && vi_lisp))) { - if (*that == '"') - quotecount = !quotecount; - if ((*that == '(' || *that == '[') - && !quotecount) - ++parencount; - if ((*that == ')' || *that == ']') - && !quotecount) - --parencount; - if (*that == '\\' && *(that+1) != NUL) - amount += lbr_chartabsize_adv(&that, - (colnr_T)amount); - amount += lbr_chartabsize_adv(&that, - (colnr_T)amount); - } - } - while (vim_iswhite(*that)) { - amount += lbr_chartabsize(that, (colnr_T)amount); - that++; - } - if (!*that || *that == ';') - amount = firsttry; - } - } - } - } - } else - amount = 0; /* no matching '(' or '[' found, use zero indent */ - - curwin->w_cursor = realpos; - - return amount; -} - void prepare_to_exit(void) { #if defined(SIGHUP) && defined(SIG_IGN) /* Ignore SIGHUP, because a dropped connection causes a read error, which diff --git a/src/misc1.h b/src/misc1.h index 236bcfcf81..df7eb4bca8 100644 --- a/src/misc1.h +++ b/src/misc1.h @@ -25,7 +25,6 @@ void del_lines(long nlines, int undo); int gchar_pos(pos_T *pos); int gchar_cursor(void); void pchar_cursor(int c); -int inindent(int extra); char_u *skip_to_option_part(char_u *p); void changed(void); void changed_int(void); @@ -80,8 +79,6 @@ char_u *concat_fnames(char_u *fname1, char_u *fname2, int sep); char_u *concat_str(char_u *str1, char_u *str2); void add_pathsep(char_u *p); char_u *FullName_save(char_u *fname, int force); -int get_expr_indent(void); -int get_lisp_indent(void); void prepare_to_exit(void); void preserve_exit(void); int vim_fexists(char_u *fname); diff --git a/src/normal.c b/src/normal.c index dd2d0a13ff..40b7834079 100644 --- a/src/normal.c +++ b/src/normal.c @@ -27,6 +27,7 @@ #include "fileio.h" #include "fold.h" #include "getchar.h" +#include "indent.h" #include "indent_c.h" #include "main.h" #include "mark.h" diff --git a/src/search.c b/src/search.c index 0bf3e8645e..16b56e2a0d 100644 --- a/src/search.c +++ b/src/search.c @@ -21,6 +21,7 @@ #include "fileio.h" #include "fold.h" #include "getchar.h" +#include "indent.h" #include "main.h" #include "mark.h" #include "mbyte.h"