Patch 8.2.0660

15 views
Skip to first unread message

Bram Moolenaar

unread,
Apr 29, 2020, 3:05:00 PM4/29/20
to vim...@googlegroups.com

Patch 8.2.0660
Problem: The search.c file is a bit big.
Solution: Split off the text object code to a separate file. (Yegappan
Lakshmanan, closes #6007)
Files: Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
src/proto.h, src/proto/search.pro, src/proto/textobject.pro,
src/search.c, src/textobject.c


*** ../vim-8.2.0659/Filelist 2020-04-27 22:51:30.133472305 +0200
--- Filelist 2020-04-29 20:39:26.465343559 +0200
***************
*** 128,133 ****
--- 128,134 ----
src/term.h \
src/termlib.c \
src/testing.c \
+ src/textobject.c \
src/textprop.c \
src/time.c \
src/ui.c \
***************
*** 279,284 ****
--- 280,286 ----
src/proto/terminal.pro \
src/proto/termlib.pro \
src/proto/testing.pro \
+ src/proto/textobject.pro \
src/proto/textprop.pro \
src/proto/time.pro \
src/proto/ui.pro \
*** ../vim-8.2.0659/src/Make_cyg_ming.mak 2020-04-18 18:24:13.106776132 +0200
--- src/Make_cyg_ming.mak 2020-04-29 20:39:26.465343559 +0200
***************
*** 787,792 ****
--- 787,793 ----
$(OUTDIR)/tag.o \
$(OUTDIR)/term.o \
$(OUTDIR)/testing.o \
+ $(OUTDIR)/textobject.o \
$(OUTDIR)/textprop.o \
$(OUTDIR)/time.o \
$(OUTDIR)/ui.o \
*** ../vim-8.2.0659/src/Make_morph.mak 2020-04-05 20:20:40.100596581 +0200
--- src/Make_morph.mak 2020-04-29 20:39:26.465343559 +0200
***************
*** 103,108 ****
--- 103,109 ----
tag.c \
term.c \
testing.c \
+ textobject.c \
textprop.c \
time.c \
ui.c \
*** ../vim-8.2.0659/src/Make_mvc.mak 2020-04-18 18:24:13.106776132 +0200
--- src/Make_mvc.mak 2020-04-29 20:39:26.469343540 +0200
***************
*** 806,811 ****
--- 806,812 ----
$(OUTDIR)\tag.obj \
$(OUTDIR)\term.obj \
$(OUTDIR)\testing.obj \
+ $(OUTDIR)\textobject.obj \
$(OUTDIR)\textprop.obj \
$(OUTDIR)\time.obj \
$(OUTDIR)\ui.obj \
***************
*** 1744,1749 ****
--- 1745,1752 ----

$(OUTDIR)/term.obj: $(OUTDIR) testing.c $(INCL)

+ $(OUTDIR)/textobject.obj: $(OUTDIR) textobject.c $(INCL)
+
$(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL)

$(OUTDIR)/time.obj: $(OUTDIR) time.c $(INCL)
***************
*** 1942,1947 ****
--- 1945,1951 ----
proto/tag.pro \
proto/term.pro \
proto/testing.pro \
+ proto/textobject.pro \
proto/textprop.pro \
proto/time.pro \
proto/ui.pro \
*** ../vim-8.2.0659/src/Make_vms.mms 2020-04-05 20:20:40.100596581 +0200
--- src/Make_vms.mms 2020-04-29 20:39:26.469343540 +0200
***************
*** 382,387 ****
--- 382,388 ----
term.c \
termlib.c \
testing.c \
+ textobject.c \
textprop.c \
time.c \
ui.c \
***************
*** 491,496 ****
--- 492,498 ----
term.obj \
termlib.obj \
testing.obj \
+ textobject.obj \
textprop.obj \
time.obj \
ui.obj \
***************
*** 989,994 ****
--- 991,999 ----
testing.obj : testing.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
+ textobject.obj : textobject.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
*** ../vim-8.2.0659/src/Makefile 2020-04-23 15:41:21.867364624 +0200
--- src/Makefile 2020-04-29 20:39:26.469343540 +0200
***************
*** 404,410 ****
# Use --with-luajit if you want to use LuaJIT instead of Lua.
# Set PATH environment variable to find lua or luajit executable.
# This requires at least "normal" features, "tiny" and "small" don't work.
! #CONF_OPT_LUA = --enable-luainterp
#CONF_OPT_LUA = --enable-luainterp=dynamic
#CONF_OPT_LUA = --enable-luainterp --with-luajit
#CONF_OPT_LUA = --enable-luainterp=dynamic --with-luajit
--- 404,410 ----
# Use --with-luajit if you want to use LuaJIT instead of Lua.
# Set PATH environment variable to find lua or luajit executable.
# This requires at least "normal" features, "tiny" and "small" don't work.
! CONF_OPT_LUA = --enable-luainterp
#CONF_OPT_LUA = --enable-luainterp=dynamic
#CONF_OPT_LUA = --enable-luainterp --with-luajit
#CONF_OPT_LUA = --enable-luainterp=dynamic --with-luajit
***************
*** 433,439 ****
# When you get an error for a missing "perl.exp" file, try creating an empty
# one: "touch perl.exp".
# This requires at least "normal" features, "tiny" and "small" don't work.
! #CONF_OPT_PERL = --enable-perlinterp
#CONF_OPT_PERL = --enable-perlinterp=dynamic

# PYTHON
--- 433,439 ----
# When you get an error for a missing "perl.exp" file, try creating an empty
# one: "touch perl.exp".
# This requires at least "normal" features, "tiny" and "small" don't work.
! CONF_OPT_PERL = --enable-perlinterp
#CONF_OPT_PERL = --enable-perlinterp=dynamic

# PYTHON
***************
*** 447,456 ****
# dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available
# However, this may still cause problems, such as "import termios" failing.
# Build two separate versions of Vim in that case.
! #CONF_OPT_PYTHON = --enable-pythoninterp
#CONF_OPT_PYTHON = --enable-pythoninterp --with-python-command=python2.7
#CONF_OPT_PYTHON = --enable-pythoninterp=dynamic
! #CONF_OPT_PYTHON3 = --enable-python3interp
#CONF_OPT_PYTHON3 = --enable-python3interp --with-python3-command=python3.6
#CONF_OPT_PYTHON3 = --enable-python3interp=dynamic

--- 447,456 ----
# dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available
# However, this may still cause problems, such as "import termios" failing.
# Build two separate versions of Vim in that case.
! CONF_OPT_PYTHON = --enable-pythoninterp
#CONF_OPT_PYTHON = --enable-pythoninterp --with-python-command=python2.7
#CONF_OPT_PYTHON = --enable-pythoninterp=dynamic
! CONF_OPT_PYTHON3 = --enable-python3interp
#CONF_OPT_PYTHON3 = --enable-python3interp --with-python3-command=python3.6
#CONF_OPT_PYTHON3 = --enable-python3interp=dynamic

***************
*** 460,478 ****
# Note: you need the development package (e.g., ruby1.9.1-dev on Ubuntu).
# This requires at least "normal" features, "tiny" and "small" don't work.
#CONF_OPT_RUBY = --enable-rubyinterp
! #CONF_OPT_RUBY = --enable-rubyinterp=dynamic
#CONF_OPT_RUBY = --enable-rubyinterp --with-ruby-command=ruby1.9.1

# TCL
# Uncomment this when you want to include the Tcl interface.
# First one is for static linking, second one for dynamic loading.
#CONF_OPT_TCL = --enable-tclinterp
! #CONF_OPT_TCL = --enable-tclinterp=dynamic
#CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4

# CSCOPE
# Uncomment this when you want to include the Cscope interface.
! #CONF_OPT_CSCOPE = --enable-cscope

# NETBEANS - NetBeans interface. Only works with Motif, GTK, and gnome.
# Motif version must have XPM libraries (see |netbeans-xpm|).
--- 460,478 ----
# Note: you need the development package (e.g., ruby1.9.1-dev on Ubuntu).
# This requires at least "normal" features, "tiny" and "small" don't work.
#CONF_OPT_RUBY = --enable-rubyinterp
! CONF_OPT_RUBY = --enable-rubyinterp=dynamic
#CONF_OPT_RUBY = --enable-rubyinterp --with-ruby-command=ruby1.9.1

# TCL
# Uncomment this when you want to include the Tcl interface.
# First one is for static linking, second one for dynamic loading.
#CONF_OPT_TCL = --enable-tclinterp
! CONF_OPT_TCL = --enable-tclinterp=dynamic
#CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4

# CSCOPE
# Uncomment this when you want to include the Cscope interface.
! CONF_OPT_CSCOPE = --enable-cscope

# NETBEANS - NetBeans interface. Only works with Motif, GTK, and gnome.
# Motif version must have XPM libraries (see |netbeans-xpm|).
***************
*** 540,546 ****
#CONF_OPT_FEAT = --with-features=small
#CONF_OPT_FEAT = --with-features=normal
#CONF_OPT_FEAT = --with-features=big
! #CONF_OPT_FEAT = --with-features=huge

# COMPILED BY - For including a specific e-mail address for ":version".
#CONF_OPT_COMPBY = "--with-compiledby=John Doe <Joh...@yahoo.com>"
--- 540,546 ----
#CONF_OPT_FEAT = --with-features=small
#CONF_OPT_FEAT = --with-features=normal
#CONF_OPT_FEAT = --with-features=big
! CONF_OPT_FEAT = --with-features=huge

# COMPILED BY - For including a specific e-mail address for ":version".
#CONF_OPT_COMPBY = "--with-compiledby=John Doe <Joh...@yahoo.com>"
***************
*** 614,624 ****
# Use this with GCC to check for mistakes, unused arguments, etc.
# Note: If you use -Wextra and get warnings in GTK code about function
# parameters, you can add -Wno-cast-function-type
! #CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
# Add -Wpedantic to find // comments and other C99 constructs.
# Better disable Perl and Python to avoid a lot of warnings.
#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
! #CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
#PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers
#MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter

--- 614,624 ----
# Use this with GCC to check for mistakes, unused arguments, etc.
# Note: If you use -Wextra and get warnings in GTK code about function
# parameters, you can add -Wno-cast-function-type
! CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
# Add -Wpedantic to find // comments and other C99 constructs.
# Better disable Perl and Python to avoid a lot of warnings.
#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
! #CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wno-cast-function-type -Wunused-result -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
#PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers
#MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter

***************
*** 707,718 ****
# Configuration is in the .ccmalloc or ~/.ccmalloc file.
# Doesn't work very well, since memory linked to from global variables
# (in libraries) is also marked as leaked memory.
! #LEAK_CFLAGS = -DEXITFREE
#LEAK_LIBS = -lccmalloc

# Uncomment this line to have Vim call abort() when an internal error is
# detected. Useful when using a tool to find errors.
! #ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR

#####################################################
### Specific systems, check if yours is listed! ### {{{
--- 707,718 ----
# Configuration is in the .ccmalloc or ~/.ccmalloc file.
# Doesn't work very well, since memory linked to from global variables
# (in libraries) is also marked as leaked memory.
! LEAK_CFLAGS = -DEXITFREE
#LEAK_LIBS = -lccmalloc

# Uncomment this line to have Vim call abort() when an internal error is
# detected. Useful when using a tool to find errors.
! ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR

#####################################################
### Specific systems, check if yours is listed! ### {{{
***************
*** 1680,1685 ****
--- 1680,1686 ----
term.c \
terminal.c \
testing.c \
+ textobject.c \
textprop.c \
time.c \
ui.c \
***************
*** 1822,1827 ****
--- 1823,1829 ----
objects/term.o \
objects/terminal.o \
objects/testing.o \
+ objects/textobject.o \
objects/textprop.o \
objects/time.o \
objects/ui.o \
***************
*** 1996,2001 ****
--- 1998,2004 ----
terminal.pro \
termlib.pro \
testing.pro \
+ textobject.pro \
textprop.pro \
time.pro \
ui.pro \
***************
*** 3469,3474 ****
--- 3472,3480 ----
objects/testing.o: testing.c
$(CCC) -o $@ testing.c

+ objects/textobject.o: textobject.c
+ $(CCC) -o $@ textobject.c
+
objects/textprop.o: textprop.c
$(CCC) -o $@ textprop.c

***************
*** 4060,4065 ****
--- 4066,4075 ----
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h globals.h
+ objects/textobject.o: textobject.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h
objects/textprop.o: textprop.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
*** ../vim-8.2.0659/src/README.md 2020-04-05 20:20:40.100596581 +0200
--- src/README.md 2020-04-29 20:39:26.469343540 +0200
***************
*** 80,85 ****
--- 80,86 ----
tag.c | tags
term.c | terminal handling, termcap codes
testing.c | testing: assert and test functions
+ textobject.c | text objects
textprop.c | text properties
time.c | time and timer functions
undo.c | undo and redo
*** ../vim-8.2.0659/src/proto.h 2020-04-05 20:20:40.104596563 +0200
--- src/proto.h 2020-04-29 20:39:26.469343540 +0200
***************
*** 223,228 ****
--- 223,229 ----
# include "textprop.pro"
# endif
# include "testing.pro"
+ # include "textobject.pro"
# include "time.pro"
# include "ui.pro"
# include "undo.pro"
*** ../vim-8.2.0659/src/proto/search.pro 2020-02-21 21:30:33.867979726 +0100
--- src/proto/search.pro 2020-04-29 20:39:26.473343525 +0200
***************
*** 30,48 ****
pos_T *findmatch(oparg_T *oap, int initc);
pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int maxtravel);
void showmatch(int c);
- int findsent(int dir, long count);
- int findpar(int *pincl, int dir, long count, int what, int both);
- int startPS(linenr_T lnum, int para, int both);
- int fwd_word(long count, int bigword, int eol);
- int bck_word(long count, int bigword, int stop);
- int end_word(long count, int bigword, int stop, int empty);
- int bckend_word(long count, int bigword, int eol);
- int current_word(oparg_T *oap, long count, int include, int bigword);
- int current_sent(oparg_T *oap, long count, int include);
- int current_block(oparg_T *oap, long count, int include, int what, int other);
- int current_tagblock(oparg_T *oap, long count_arg, int include);
- int current_par(oparg_T *oap, long count, int include, int type);
- int current_quote(oparg_T *oap, long count, int include, int quotechar);
int current_search(long count, int forward);
int linewhite(linenr_T lnum);
void find_pattern_in_path(char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum);
--- 30,35 ----
*** ../vim-8.2.0659/src/proto/textobject.pro 2020-04-29 21:03:25.327279003 +0200
--- src/proto/textobject.pro 2020-04-29 20:39:26.473343525 +0200
***************
*** 0 ****
--- 1,16 ----
+ /* textobject.c */
+ int findsent(int dir, long count);
+ int findpar(int *pincl, int dir, long count, int what, int both);
+ int startPS(linenr_T lnum, int para, int both);
+ int fwd_word(long count, int bigword, int eol);
+ int bck_word(long count, int bigword, int stop);
+ int end_word(long count, int bigword, int stop, int empty);
+ int bckend_word(long count, int bigword, int eol);
+ int current_word(oparg_T *oap, long count, int include, int bigword);
+ int current_sent(oparg_T *oap, long count, int include);
+ int current_block(oparg_T *oap, long count, int include, int what, int other);
+ int current_tagblock(oparg_T *oap, long count_arg, int include);
+ int current_par(oparg_T *oap, long count, int include, int type);
+ int current_quote(oparg_T *oap, long count, int include, int quotechar);
+ /* vim: set ft=c : */
+
*** ../vim-8.2.0659/src/search.c 2020-04-12 19:37:13.522297249 +0200
--- src/search.c 2020-04-29 20:39:26.477343508 +0200
***************
*** 17,24 ****
static int first_submatch(regmmatch_T *rp);
#endif
static int check_linecomment(char_u *line);
- static int cls(void);
- static int skip_chars(int, int);
#ifdef FEAT_FIND_ID
static void show_pat_in_path(char_u *, int,
int, int, FILE *, linenr_T *, long);
--- 17,22 ----
***************
*** 2838,4792 ****
}

/*
- * Find the start of the next sentence, searching in the direction specified
- * by the "dir" argument. The cursor is positioned on the start of the next
- * sentence when found. If the next sentence is found, return OK. Return FAIL
- * otherwise. See ":h sentence" for the precise definition of a "sentence"
- * text object.
- */
- int
- findsent(int dir, long count)
- {
- pos_T pos, tpos;
- int c;
- int (*func)(pos_T *);
- int startlnum;
- int noskip = FALSE; // do not skip blanks
- int cpo_J;
- int found_dot;
-
- pos = curwin->w_cursor;
- if (dir == FORWARD)
- func = incl;
- else
- func = decl;
-
- while (count--)
- {
- /*
- * if on an empty line, skip up to a non-empty line
- */
- if (gchar_pos(&pos) == NUL)
- {
- do
- if ((*func)(&pos) == -1)
- break;
- while (gchar_pos(&pos) == NUL);
- if (dir == FORWARD)
- goto found;
- }
- /*
- * if on the start of a paragraph or a section and searching forward,
- * go to the next line
- */
- else if (dir == FORWARD && pos.col == 0 &&
- startPS(pos.lnum, NUL, FALSE))
- {
- if (pos.lnum == curbuf->b_ml.ml_line_count)
- return FAIL;
- ++pos.lnum;
- goto found;
- }
- else if (dir == BACKWARD)
- decl(&pos);
-
- // go back to the previous non-white non-punctuation character
- found_dot = FALSE;
- while (c = gchar_pos(&pos), VIM_ISWHITE(c)
- || vim_strchr((char_u *)".!?)]\"'", c) != NULL)
- {
- tpos = pos;
- if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD))
- break;
-
- if (found_dot)
- break;
- if (vim_strchr((char_u *) ".!?", c) != NULL)
- found_dot = TRUE;
-
- if (vim_strchr((char_u *) ")]\"'", c) != NULL
- && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL)
- break;
-
- decl(&pos);
- }
-
- // remember the line where the search started
- startlnum = pos.lnum;
- cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
-
- for (;;) // find end of sentence
- {
- c = gchar_pos(&pos);
- if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
- {
- if (dir == BACKWARD && pos.lnum != startlnum)
- ++pos.lnum;
- break;
- }
- if (c == '.' || c == '!' || c == '?')
- {
- tpos = pos;
- do
- if ((c = inc(&tpos)) == -1)
- break;
- while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos))
- != NULL);
- if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL
- || (cpo_J && (c == ' ' && inc(&tpos) >= 0
- && gchar_pos(&tpos) == ' ')))
- {
- pos = tpos;
- if (gchar_pos(&pos) == NUL) // skip NUL at EOL
- inc(&pos);
- break;
- }
- }
- if ((*func)(&pos) == -1)
- {
- if (count)
- return FAIL;
- noskip = TRUE;
- break;
- }
- }
- found:
- // skip white space
- while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
- if (incl(&pos) == -1)
- break;
- }
-
- setpcmark();
- curwin->w_cursor = pos;
- return OK;
- }
-
- /*
- * Find the next paragraph or section in direction 'dir'.
- * Paragraphs are currently supposed to be separated by empty lines.
- * If 'what' is NUL we go to the next paragraph.
- * If 'what' is '{' or '}' we go to the next section.
- * If 'both' is TRUE also stop at '}'.
- * Return TRUE if the next paragraph or section was found.
- */
- int
- findpar(
- int *pincl, // Return: TRUE if last char is to be included
- int dir,
- long count,
- int what,
- int both)
- {
- linenr_T curr;
- int did_skip; // TRUE after separating lines have been skipped
- int first; // TRUE on first line
- int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL);
- #ifdef FEAT_FOLDING
- linenr_T fold_first; // first line of a closed fold
- linenr_T fold_last; // last line of a closed fold
- int fold_skipped; // TRUE if a closed fold was skipped this
- // iteration
- #endif
-
- curr = curwin->w_cursor.lnum;
-
- while (count--)
- {
- did_skip = FALSE;
- for (first = TRUE; ; first = FALSE)
- {
- if (*ml_get(curr) != NUL)
- did_skip = TRUE;
-
- #ifdef FEAT_FOLDING
- // skip folded lines
- fold_skipped = FALSE;
- if (first && hasFolding(curr, &fold_first, &fold_last))
- {
- curr = ((dir > 0) ? fold_last : fold_first) + dir;
- fold_skipped = TRUE;
- }
- #endif
-
- // POSIX has its own ideas of what a paragraph boundary is and it
- // doesn't match historical Vi: It also stops at a "{" in the
- // first column and at an empty line.
- if (!first && did_skip && (startPS(curr, what, both)
- || (posix && what == NUL && *ml_get(curr) == '{')))
- break;
-
- #ifdef FEAT_FOLDING
- if (fold_skipped)
- curr -= dir;
- #endif
- if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
- {
- if (count)
- return FALSE;
- curr -= dir;
- break;
- }
- }
- }
- setpcmark();
- if (both && *ml_get(curr) == '}') // include line with '}'
- ++curr;
- curwin->w_cursor.lnum = curr;
- if (curr == curbuf->b_ml.ml_line_count && what != '}')
- {
- char_u *line = ml_get(curr);
-
- // Put the cursor on the last character in the last line and make the
- // motion inclusive.
- if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0)
- {
- --curwin->w_cursor.col;
- curwin->w_cursor.col -=
- (*mb_head_off)(line, line + curwin->w_cursor.col);
- *pincl = TRUE;
- }
- }
- else
- curwin->w_cursor.col = 0;
- return TRUE;
- }
-
- /*
- * check if the string 's' is a nroff macro that is in option 'opt'
- */
- static int
- inmacro(char_u *opt, char_u *s)
- {
- char_u *macro;
-
- for (macro = opt; macro[0]; ++macro)
- {
- // Accept two characters in the option being equal to two characters
- // in the line. A space in the option matches with a space in the
- // line or the line having ended.
- if ( (macro[0] == s[0]
- || (macro[0] == ' '
- && (s[0] == NUL || s[0] == ' ')))
- && (macro[1] == s[1]
- || ((macro[1] == NUL || macro[1] == ' ')
- && (s[0] == NUL || s[1] == NUL || s[1] == ' '))))
- break;
- ++macro;
- if (macro[0] == NUL)
- break;
- }
- return (macro[0] != NUL);
- }
-
- /*
- * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
- * If 'para' is '{' or '}' only check for sections.
- * If 'both' is TRUE also stop at '}'
- */
- int
- startPS(linenr_T lnum, int para, int both)
- {
- char_u *s;
-
- s = ml_get(lnum);
- if (*s == para || *s == '\f' || (both && *s == '}'))
- return TRUE;
- if (*s == '.' && (inmacro(p_sections, s + 1) ||
- (!para && inmacro(p_para, s + 1))))
- return TRUE;
- return FALSE;
- }
-
- /*
- * The following routines do the word searches performed by the 'w', 'W',
- * 'b', 'B', 'e', and 'E' commands.
- */
-
- /*
- * To perform these searches, characters are placed into one of three
- * classes, and transitions between classes determine word boundaries.
- *
- * The classes are:
- *
- * 0 - white space
- * 1 - punctuation
- * 2 or higher - keyword characters (letters, digits and underscore)
- */
-
- static int cls_bigword; // TRUE for "W", "B" or "E"
-
- /*
- * cls() - returns the class of character at curwin->w_cursor
- *
- * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars
- * from class 2 and higher are reported as class 1 since only white space
- * boundaries are of interest.
- */
- static int
- cls(void)
- {
- int c;
-
- c = gchar_cursor();
- if (c == ' ' || c == '\t' || c == NUL)
- return 0;
- if (enc_dbcs != 0 && c > 0xFF)
- {
- // If cls_bigword, report multi-byte chars as class 1.
- if (enc_dbcs == DBCS_KOR && cls_bigword)
- return 1;
-
- // process code leading/trailing bytes
- return dbcs_class(((unsigned)c >> 8), (c & 0xFF));
- }
- if (enc_utf8)
- {
- c = utf_class(c);
- if (c != 0 && cls_bigword)
- return 1;
- return c;
- }
-
- // If cls_bigword is TRUE, report all non-blanks as class 1.
- if (cls_bigword)
- return 1;
-
- if (vim_iswordc(c))
- return 2;
- return 1;
- }
-
-
- /*
- * fwd_word(count, type, eol) - move forward one word
- *
- * Returns FAIL if the cursor was already at the end of the file.
- * If eol is TRUE, last word stops at end of line (for operators).
- */
- int
- fwd_word(
- long count,
- int bigword, // "W", "E" or "B"
- int eol)
- {
- int sclass; // starting class
- int i;
- int last_line;
-
- curwin->w_cursor.coladd = 0;
- cls_bigword = bigword;
- while (--count >= 0)
- {
- #ifdef FEAT_FOLDING
- // When inside a range of folded lines, move to the last char of the
- // last line.
- if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
- coladvance((colnr_T)MAXCOL);
- #endif
- sclass = cls();
-
- /*
- * We always move at least one character, unless on the last
- * character in the buffer.
- */
- last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
- i = inc_cursor();
- if (i == -1 || (i >= 1 && last_line)) // started at last char in file
- return FAIL;
- if (i >= 1 && eol && count == 0) // started at last char in line
- return OK;
-
- /*
- * Go one char past end of current word (if any)
- */
- if (sclass != 0)
- while (cls() == sclass)
- {
- i = inc_cursor();
- if (i == -1 || (i >= 1 && eol && count == 0))
- return OK;
- }
-
- /*
- * go to next non-white
- */
- while (cls() == 0)
- {
- /*
- * We'll stop if we land on a blank line
- */
- if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
- break;
-
- i = inc_cursor();
- if (i == -1 || (i >= 1 && eol && count == 0))
- return OK;
- }
- }
- return OK;
- }
-
- /*
- * bck_word() - move backward 'count' words
- *
- * If stop is TRUE and we are already on the start of a word, move one less.
- *
- * Returns FAIL if top of the file was reached.
- */
- int
- bck_word(long count, int bigword, int stop)
- {
- int sclass; // starting class
-
- curwin->w_cursor.coladd = 0;
- cls_bigword = bigword;
- while (--count >= 0)
- {
- #ifdef FEAT_FOLDING
- // When inside a range of folded lines, move to the first char of the
- // first line.
- if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL))
- curwin->w_cursor.col = 0;
- #endif
- sclass = cls();
- if (dec_cursor() == -1) // started at start of file
- return FAIL;
-
- if (!stop || sclass == cls() || sclass == 0)
- {
- /*
- * Skip white space before the word.
- * Stop on an empty line.
- */
- while (cls() == 0)
- {
- if (curwin->w_cursor.col == 0
- && LINEEMPTY(curwin->w_cursor.lnum))
- goto finished;
- if (dec_cursor() == -1) // hit start of file, stop here
- return OK;
- }
-
- /*
- * Move backward to start of this word.
- */
- if (skip_chars(cls(), BACKWARD))
- return OK;
- }
-
- inc_cursor(); // overshot - forward one
- finished:
- stop = FALSE;
- }
- return OK;
- }
-
- /*
- * end_word() - move to the end of the word
- *
- * There is an apparent bug in the 'e' motion of the real vi. At least on the
- * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
- * motion crosses blank lines. When the real vi crosses a blank line in an
- * 'e' motion, the cursor is placed on the FIRST character of the next
- * non-blank line. The 'E' command, however, works correctly. Since this
- * appears to be a bug, I have not duplicated it here.
- *
- * Returns FAIL if end of the file was reached.
- *
- * If stop is TRUE and we are already on the end of a word, move one less.
- * If empty is TRUE stop on an empty line.
- */
- int
- end_word(
- long count,
- int bigword,
- int stop,
- int empty)
- {
- int sclass; // starting class
-
- curwin->w_cursor.coladd = 0;
- cls_bigword = bigword;
- while (--count >= 0)
- {
- #ifdef FEAT_FOLDING
- // When inside a range of folded lines, move to the last char of the
- // last line.
- if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
- coladvance((colnr_T)MAXCOL);
- #endif
- sclass = cls();
- if (inc_cursor() == -1)
- return FAIL;
-
- /*
- * If we're in the middle of a word, we just have to move to the end
- * of it.
- */
- if (cls() == sclass && sclass != 0)
- {
- /*
- * Move forward to end of the current word
- */
- if (skip_chars(sclass, FORWARD))
- return FAIL;
- }
- else if (!stop || sclass == 0)
- {
- /*
- * We were at the end of a word. Go to the end of the next word.
- * First skip white space, if 'empty' is TRUE, stop at empty line.
- */
- while (cls() == 0)
- {
- if (empty && curwin->w_cursor.col == 0
- && LINEEMPTY(curwin->w_cursor.lnum))
- goto finished;
- if (inc_cursor() == -1) // hit end of file, stop here
- return FAIL;
- }
-
- /*
- * Move forward to the end of this word.
- */
- if (skip_chars(cls(), FORWARD))
- return FAIL;
- }
- dec_cursor(); // overshot - one char backward
- finished:
- stop = FALSE; // we move only one word less
- }
- return OK;
- }
-
- /*
- * Move back to the end of the word.
- *
- * Returns FAIL if start of the file was reached.
- */
- int
- bckend_word(
- long count,
- int bigword, // TRUE for "B"
- int eol) // TRUE: stop at end of line.
- {
- int sclass; // starting class
- int i;
-
- curwin->w_cursor.coladd = 0;
- cls_bigword = bigword;
- while (--count >= 0)
- {
- sclass = cls();
- if ((i = dec_cursor()) == -1)
- return FAIL;
- if (eol && i == 1)
- return OK;
-
- /*
- * Move backward to before the start of this word.
- */
- if (sclass != 0)
- {
- while (cls() == sclass)
- if ((i = dec_cursor()) == -1 || (eol && i == 1))
- return OK;
- }
-
- /*
- * Move backward to end of the previous word
- */
- while (cls() == 0)
- {
- if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum))
- break;
- if ((i = dec_cursor()) == -1 || (eol && i == 1))
- return OK;
- }
- }
- return OK;
- }
-
- /*
- * Skip a row of characters of the same class.
- * Return TRUE when end-of-file reached, FALSE otherwise.
- */
- static int
- skip_chars(int cclass, int dir)
- {
- while (cls() == cclass)
- if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
- return TRUE;
- return FALSE;
- }
-
- #ifdef FEAT_TEXTOBJ
- /*
- * Go back to the start of the word or the start of white space
- */
- static void
- back_in_line(void)
- {
- int sclass; // starting class
-
- sclass = cls();
- for (;;)
- {
- if (curwin->w_cursor.col == 0) // stop at start of line
- break;
- dec_cursor();
- if (cls() != sclass) // stop at start of word
- {
- inc_cursor();
- break;
- }
- }
- }
-
- static void
- find_first_blank(pos_T *posp)
- {
- int c;
-
- while (decl(posp) != -1)
- {
- c = gchar_pos(posp);
- if (!VIM_ISWHITE(c))
- {
- incl(posp);
- break;
- }
- }
- }
-
- /*
- * Skip count/2 sentences and count/2 separating white spaces.
- */
- static void
- findsent_forward(
- long count,
- int at_start_sent) // cursor is at start of sentence
- {
- while (count--)
- {
- findsent(FORWARD, 1L);
- if (at_start_sent)
- find_first_blank(&curwin->w_cursor);
- if (count == 0 || at_start_sent)
- decl(&curwin->w_cursor);
- at_start_sent = !at_start_sent;
- }
- }
-
- /*
- * Find word under cursor, cursor at end.
- * Used while an operator is pending, and in Visual mode.
- */
- int
- current_word(
- oparg_T *oap,
- long count,
- int include, // TRUE: include word and white space
- int bigword) // FALSE == word, TRUE == WORD
- {
- pos_T start_pos;
- pos_T pos;
- int inclusive = TRUE;
- int include_white = FALSE;
-
- cls_bigword = bigword;
- CLEAR_POS(&start_pos);
-
- // Correct cursor when 'selection' is exclusive
- if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
- dec_cursor();
-
- /*
- * When Visual mode is not active, or when the VIsual area is only one
- * character, select the word and/or white space under the cursor.
- */
- if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual))
- {
- /*
- * Go to start of current word or white space.
- */
- back_in_line();
- start_pos = curwin->w_cursor;
-
- /*
- * If the start is on white space, and white space should be included
- * (" word"), or start is not on white space, and white space should
- * not be included ("word"), find end of word.
- */
- if ((cls() == 0) == include)
- {
- if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
- return FAIL;
- }
- else
- {
- /*
- * If the start is not on white space, and white space should be
- * included ("word "), or start is on white space and white
- * space should not be included (" "), find start of word.
- * If we end up in the first column of the next line (single char
- * word) back up to end of the line.
- */
- fwd_word(1L, bigword, TRUE);
- if (curwin->w_cursor.col == 0)
- decl(&curwin->w_cursor);
- else
- oneleft();
-
- if (include)
- include_white = TRUE;
- }
-
- if (VIsual_active)
- {
- // should do something when inclusive == FALSE !
- VIsual = start_pos;
- redraw_curbuf_later(INVERTED); // update the inversion
- }
- else
- {
- oap->start = start_pos;
- oap->motion_type = MCHAR;
- }
- --count;
- }
-
- /*
- * When count is still > 0, extend with more objects.
- */
- while (count > 0)
- {
- inclusive = TRUE;
- if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
- {
- /*
- * In Visual mode, with cursor at start: move cursor back.
- */
- if (decl(&curwin->w_cursor) == -1)
- return FAIL;
- if (include != (cls() != 0))
- {
- if (bck_word(1L, bigword, TRUE) == FAIL)
- return FAIL;
- }
- else
- {
- if (bckend_word(1L, bigword, TRUE) == FAIL)
- return FAIL;
- (void)incl(&curwin->w_cursor);
- }
- }
- else
- {
- /*
- * Move cursor forward one word and/or white area.
- */
- if (incl(&curwin->w_cursor) == -1)
- return FAIL;
- if (include != (cls() == 0))
- {
- if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
- return FAIL;
- /*
- * If end is just past a new-line, we don't want to include
- * the first character on the line.
- * Put cursor on last char of white.
- */
- if (oneleft() == FAIL)
- inclusive = FALSE;
- }
- else
- {
- if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
- return FAIL;
- }
- }
- --count;
- }
-
- if (include_white && (cls() != 0
- || (curwin->w_cursor.col == 0 && !inclusive)))
- {
- /*
- * If we don't include white space at the end, move the start
- * to include some white space there. This makes "daw" work
- * better on the last word in a sentence (and "2daw" on last-but-one
- * word). Also when "2daw" deletes "word." at the end of the line
- * (cursor is at start of next line).
- * But don't delete white space at start of line (indent).
- */
- pos = curwin->w_cursor; // save cursor position
- curwin->w_cursor = start_pos;
- if (oneleft() == OK)
- {
- back_in_line();
- if (cls() == 0 && curwin->w_cursor.col > 0)
- {
- if (VIsual_active)
- VIsual = curwin->w_cursor;
- else
- oap->start = curwin->w_cursor;
- }
- }
- curwin->w_cursor = pos; // put cursor back at end
- }
-
- if (VIsual_active)
- {
- if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor))
- inc_cursor();
- if (VIsual_mode == 'V')
- {
- VIsual_mode = 'v';
- redraw_cmdline = TRUE; // show mode later
- }
- }
- else
- oap->inclusive = inclusive;
-
- return OK;
- }
-
- /*
- * Find sentence(s) under the cursor, cursor at end.
- * When Visual active, extend it by one or more sentences.
- */
- int
- current_sent(oparg_T *oap, long count, int include)
- {
- pos_T start_pos;
- pos_T pos;
- int start_blank;
- int c;
- int at_start_sent;
- long ncount;
-
- start_pos = curwin->w_cursor;
- pos = start_pos;
- findsent(FORWARD, 1L); // Find start of next sentence.
-
- /*
- * When the Visual area is bigger than one character: Extend it.
- */
- if (VIsual_active && !EQUAL_POS(start_pos, VIsual))
- {
- extend:
- if (LT_POS(start_pos, VIsual))
- {
- /*
- * Cursor at start of Visual area.
- * Find out where we are:
- * - in the white space before a sentence
- * - in a sentence or just after it
- * - at the start of a sentence
- */
- at_start_sent = TRUE;
- decl(&pos);
- while (LT_POS(pos, curwin->w_cursor))
- {
- c = gchar_pos(&pos);
- if (!VIM_ISWHITE(c))
- {
- at_start_sent = FALSE;
- break;
- }
- incl(&pos);
- }
- if (!at_start_sent)
- {
- findsent(BACKWARD, 1L);
- if (EQUAL_POS(curwin->w_cursor, start_pos))
- at_start_sent = TRUE; // exactly at start of sentence
- else
- // inside a sentence, go to its end (start of next)
- findsent(FORWARD, 1L);
- }
- if (include) // "as" gets twice as much as "is"
- count *= 2;
- while (count--)
- {
- if (at_start_sent)
- find_first_blank(&curwin->w_cursor);
- c = gchar_cursor();
- if (!at_start_sent || (!include && !VIM_ISWHITE(c)))
- findsent(BACKWARD, 1L);
- at_start_sent = !at_start_sent;
- }
- }
- else
- {
- /*
- * Cursor at end of Visual area.
- * Find out where we are:
- * - just before a sentence
- * - just before or in the white space before a sentence
- * - in a sentence
- */
- incl(&pos);
- at_start_sent = TRUE;
- // not just before a sentence
- if (!EQUAL_POS(pos, curwin->w_cursor))
- {
- at_start_sent = FALSE;
- while (LT_POS(pos, curwin->w_cursor))
- {
- c = gchar_pos(&pos);
- if (!VIM_ISWHITE(c))
- {
- at_start_sent = TRUE;
- break;
- }
- incl(&pos);
- }
- if (at_start_sent) // in the sentence
- findsent(BACKWARD, 1L);
- else // in/before white before a sentence
- curwin->w_cursor = start_pos;
- }
-
- if (include) // "as" gets twice as much as "is"
- count *= 2;
- findsent_forward(count, at_start_sent);
- if (*p_sel == 'e')
- ++curwin->w_cursor.col;
- }
- return OK;
- }
-
- /*
- * If the cursor started on a blank, check if it is just before the start
- * of the next sentence.
- */
- while (c = gchar_pos(&pos), VIM_ISWHITE(c)) // VIM_ISWHITE() is a macro
- incl(&pos);
- if (EQUAL_POS(pos, curwin->w_cursor))
- {
- start_blank = TRUE;
- find_first_blank(&start_pos); // go back to first blank
- }
- else
- {
- start_blank = FALSE;
- findsent(BACKWARD, 1L);
- start_pos = curwin->w_cursor;
- }
- if (include)
- ncount = count * 2;
- else
- {
- ncount = count;
- if (start_blank)
- --ncount;
- }
- if (ncount > 0)
- findsent_forward(ncount, TRUE);
- else
- decl(&curwin->w_cursor);
-
- if (include)
- {
- /*
- * If the blank in front of the sentence is included, exclude the
- * blanks at the end of the sentence, go back to the first blank.
- * If there are no trailing blanks, try to include leading blanks.
- */
- if (start_blank)
- {
- find_first_blank(&curwin->w_cursor);
- c = gchar_pos(&curwin->w_cursor); // VIM_ISWHITE() is a macro
- if (VIM_ISWHITE(c))
- decl(&curwin->w_cursor);
- }
- else if (c = gchar_cursor(), !VIM_ISWHITE(c))
- find_first_blank(&start_pos);
- }
-
- if (VIsual_active)
- {
- // Avoid getting stuck with "is" on a single space before a sentence.
- if (EQUAL_POS(start_pos, curwin->w_cursor))
- goto extend;
- if (*p_sel == 'e')
- ++curwin->w_cursor.col;
- VIsual = start_pos;
- VIsual_mode = 'v';
- redraw_cmdline = TRUE; // show mode later
- redraw_curbuf_later(INVERTED); // update the inversion
- }
- else
- {
- // include a newline after the sentence, if there is one
- if (incl(&curwin->w_cursor) == -1)
- oap->inclusive = TRUE;
- else
- oap->inclusive = FALSE;
- oap->start = start_pos;
- oap->motion_type = MCHAR;
- }
- return OK;
- }
-
- /*
- * Find block under the cursor, cursor at end.
- * "what" and "other" are two matching parenthesis/brace/etc.
- */
- int
- current_block(
- oparg_T *oap,
- long count,
- int include, // TRUE == include white space
- int what, // '(', '{', etc.
- int other) // ')', '}', etc.
- {
- pos_T old_pos;
- pos_T *pos = NULL;
- pos_T start_pos;
- pos_T *end_pos;
- pos_T old_start, old_end;
- char_u *save_cpo;
- int sol = FALSE; // '{' at start of line
-
- old_pos = curwin->w_cursor;
- old_end = curwin->w_cursor; // remember where we started
- old_start = old_end;
-
- /*
- * If we start on '(', '{', ')', '}', etc., use the whole block inclusive.
- */
- if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
- {
- setpcmark();
- if (what == '{') // ignore indent
- while (inindent(1))
- if (inc_cursor() != 0)
- break;
- if (gchar_cursor() == what)
- // cursor on '(' or '{', move cursor just after it
- ++curwin->w_cursor.col;
- }
- else if (LT_POS(VIsual, curwin->w_cursor))
- {
- old_start = VIsual;
- curwin->w_cursor = VIsual; // cursor at low end of Visual
- }
- else
- old_end = VIsual;
-
- /*
- * Search backwards for unclosed '(', '{', etc..
- * Put this position in start_pos.
- * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the
- * user wants.
- */
- save_cpo = p_cpo;
- p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%");
- while (count-- > 0)
- {
- if ((pos = findmatch(NULL, what)) == NULL)
- break;
- curwin->w_cursor = *pos;
- start_pos = *pos; // the findmatch for end_pos will overwrite *pos
- }
- p_cpo = save_cpo;
-
- /*
- * Search for matching ')', '}', etc.
- * Put this position in curwin->w_cursor.
- */
- if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
- {
- curwin->w_cursor = old_pos;
- return FAIL;
- }
- curwin->w_cursor = *end_pos;
-
- /*
- * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE.
- * If the ending '}', ')' or ']' is only preceded by indent, skip that
- * indent. But only if the resulting area is not smaller than what we
- * started with.
- */
- while (!include)
- {
- incl(&start_pos);
- sol = (curwin->w_cursor.col == 0);
- decl(&curwin->w_cursor);
- while (inindent(1))
- {
- sol = TRUE;
- if (decl(&curwin->w_cursor) != 0)
- break;
- }
-
- /*
- * In Visual mode, when the resulting area is not bigger than what we
- * started with, extend it to the next block, and then exclude again.
- */
- if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor)
- && VIsual_active)
- {
- curwin->w_cursor = old_start;
- decl(&curwin->w_cursor);
- if ((pos = findmatch(NULL, what)) == NULL)
- {
- curwin->w_cursor = old_pos;
- return FAIL;
- }
- start_pos = *pos;
- curwin->w_cursor = *pos;
- if ((end_pos = findmatch(NULL, other)) == NULL)
- {
- curwin->w_cursor = old_pos;
- return FAIL;
- }
- curwin->w_cursor = *end_pos;
- }
- else
- break;
- }
-
- if (VIsual_active)
- {
- if (*p_sel == 'e')
- inc(&curwin->w_cursor);
- if (sol && gchar_cursor() != NUL)
- inc(&curwin->w_cursor); // include the line break
- VIsual = start_pos;
- VIsual_mode = 'v';
- redraw_curbuf_later(INVERTED); // update the inversion
- showmode();
- }
- else
- {
- oap->start = start_pos;
- oap->motion_type = MCHAR;
- oap->inclusive = FALSE;
- if (sol)
- incl(&curwin->w_cursor);
- else if (LTOREQ_POS(start_pos, curwin->w_cursor))
- // Include the character under the cursor.
- oap->inclusive = TRUE;
- else
- // End is before the start (no text in between <>, [], etc.): don't
- // operate on any text.
- curwin->w_cursor = start_pos;
- }
-
- return OK;
- }
-
- /*
- * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>".
- * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>".
- */
- static int
- in_html_tag(
- int end_tag)
- {
- char_u *line = ml_get_curline();
- char_u *p;
- int c;
- int lc = NUL;
- pos_T pos;
-
- if (enc_dbcs)
- {
- char_u *lp = NULL;
-
- // We search forward until the cursor, because searching backwards is
- // very slow for DBCS encodings.
- for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p))
- if (*p == '>' || *p == '<')
- {
- lc = *p;
- lp = p;
- }
- if (*p != '<') // check for '<' under cursor
- {
- if (lc != '<')
- return FALSE;
- p = lp;
- }
- }
- else
- {
- for (p = line + curwin->w_cursor.col; p > line; )
- {
- if (*p == '<') // find '<' under/before cursor
- break;
- MB_PTR_BACK(line, p);
- if (*p == '>') // find '>' before cursor
- break;
- }
- if (*p != '<')
- return FALSE;
- }
-
- pos.lnum = curwin->w_cursor.lnum;
- pos.col = (colnr_T)(p - line);
-
- MB_PTR_ADV(p);
- if (end_tag)
- // check that there is a '/' after the '<'
- return *p == '/';
-
- // check that there is no '/' after the '<'
- if (*p == '/')
- return FALSE;
-
- // check that the matching '>' is not preceded by '/'
- for (;;)
- {
- if (inc(&pos) < 0)
- return FALSE;
- c = *ml_get_pos(&pos);
- if (c == '>')
- break;
- lc = c;
- }
- return lc != '/';
- }
-
- /*
- * Find tag block under the cursor, cursor at end.
- */
- int
- current_tagblock(
- oparg_T *oap,
- long count_arg,
- int include) // TRUE == include white space
- {
- long count = count_arg;
- long n;
- pos_T old_pos;
- pos_T start_pos;
- pos_T end_pos;
- pos_T old_start, old_end;
- char_u *spat, *epat;
- char_u *p;
- char_u *cp;
- int len;
- int r;
- int do_include = include;
- int save_p_ws = p_ws;
- int retval = FAIL;
- int is_inclusive = TRUE;
-
- p_ws = FALSE;
-
- old_pos = curwin->w_cursor;
- old_end = curwin->w_cursor; // remember where we started
- old_start = old_end;
- if (!VIsual_active || *p_sel == 'e')
- decl(&old_end); // old_end is inclusive
-
- /*
- * If we start on "<aaa>" select that block.
- */
- if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
- {
- setpcmark();
-
- // ignore indent
- while (inindent(1))
- if (inc_cursor() != 0)
- break;
-
- if (in_html_tag(FALSE))
- {
- // cursor on start tag, move to its '>'
- while (*ml_get_cursor() != '>')
- if (inc_cursor() < 0)
- break;
- }
- else if (in_html_tag(TRUE))
- {
- // cursor on end tag, move to just before it
- while (*ml_get_cursor() != '<')
- if (dec_cursor() < 0)
- break;
- dec_cursor();
- old_end = curwin->w_cursor;
- }
- }
- else if (LT_POS(VIsual, curwin->w_cursor))
- {
- old_start = VIsual;
- curwin->w_cursor = VIsual; // cursor at low end of Visual
- }
- else
- old_end = VIsual;
-
- again:
- /*
- * Search backwards for unclosed "<aaa>".
- * Put this position in start_pos.
- */
- for (n = 0; n < count; ++n)
- {
- if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
- (char_u *)"",
- (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
- NULL, (linenr_T)0, 0L) <= 0)
- {
- curwin->w_cursor = old_pos;
- goto theend;
- }
- }
- start_pos = curwin->w_cursor;
-
- /*
- * Search for matching "</aaa>". First isolate the "aaa".
- */
- inc_cursor();
- p = ml_get_cursor();
- for (cp = p; *cp != NUL && *cp != '>' && !VIM_ISWHITE(*cp); MB_PTR_ADV(cp))
- ;
- len = (int)(cp - p);
- if (len == 0)
- {
- curwin->w_cursor = old_pos;
- goto theend;
- }
- spat = alloc(len + 31);
- epat = alloc(len + 9);
- if (spat == NULL || epat == NULL)
- {
- vim_free(spat);
- vim_free(epat);
- curwin->w_cursor = old_pos;
- goto theend;
- }
- sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
- sprintf((char *)epat, "</%.*s>\\c", len, p);
-
- r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
- 0, NULL, (linenr_T)0, 0L);
-
- vim_free(spat);
- vim_free(epat);
-
- if (r < 1 || LT_POS(curwin->w_cursor, old_end))
- {
- // Can't find other end or it's before the previous end. Could be a
- // HTML tag that doesn't have a matching end. Search backwards for
- // another starting tag.
- count = 1;
- curwin->w_cursor = start_pos;
- goto again;
- }
-
- if (do_include)
- {
- // Include up to the '>'.
- while (*ml_get_cursor() != '>')
- if (inc_cursor() < 0)
- break;
- }
- else
- {
- char_u *c = ml_get_cursor();
-
- // Exclude the '<' of the end tag.
- // If the closing tag is on new line, do not decrement cursor, but
- // make operation exclusive, so that the linefeed will be selected
- if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0)
- // do not decrement cursor
- is_inclusive = FALSE;
- else if (*c == '<')
- dec_cursor();
- }
- end_pos = curwin->w_cursor;
-
- if (!do_include)
- {
- // Exclude the start tag.
- curwin->w_cursor = start_pos;
- while (inc_cursor() >= 0)
- if (*ml_get_cursor() == '>')
- {
- inc_cursor();
- start_pos = curwin->w_cursor;
- break;
- }
- curwin->w_cursor = end_pos;
-
- // If we are in Visual mode and now have the same text as before set
- // "do_include" and try again.
- if (VIsual_active && EQUAL_POS(start_pos, old_start)
- && EQUAL_POS(end_pos, old_end))
- {
- do_include = TRUE;
- curwin->w_cursor = old_start;
- count = count_arg;
- goto again;
- }
- }
-
- if (VIsual_active)
- {
- // If the end is before the start there is no text between tags, select
- // the char under the cursor.
- if (LT_POS(end_pos, start_pos))
- curwin->w_cursor = start_pos;
- else if (*p_sel == 'e')
- inc_cursor();
- VIsual = start_pos;
- VIsual_mode = 'v';
- redraw_curbuf_later(INVERTED); // update the inversion
- showmode();
- }
- else
- {
- oap->start = start_pos;
- oap->motion_type = MCHAR;
- if (LT_POS(end_pos, start_pos))
- {
- // End is before the start: there is no text between tags; operate
- // on an empty area.
- curwin->w_cursor = start_pos;
- oap->inclusive = FALSE;
- }
- else
- oap->inclusive = is_inclusive;
- }
- retval = OK;
-
- theend:
- p_ws = save_p_ws;
- return retval;
- }
-
- int
- current_par(
- oparg_T *oap,
- long count,
- int include, // TRUE == include white space
- int type) // 'p' for paragraph, 'S' for section
- {
- linenr_T start_lnum;
- linenr_T end_lnum;
- int white_in_front;
- int dir;
- int start_is_white;
- int prev_start_is_white;
- int retval = OK;
- int do_white = FALSE;
- int t;
- int i;
-
- if (type == 'S') // not implemented yet
- return FAIL;
-
- start_lnum = curwin->w_cursor.lnum;
-
- /*
- * When visual area is more than one line: extend it.
- */
- if (VIsual_active && start_lnum != VIsual.lnum)
- {
- extend:
- if (start_lnum < VIsual.lnum)
- dir = BACKWARD;
- else
- dir = FORWARD;
- for (i = count; --i >= 0; )
- {
- if (start_lnum ==
- (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
- {
- retval = FAIL;
- break;
- }
-
- prev_start_is_white = -1;
- for (t = 0; t < 2; ++t)
- {
- start_lnum += dir;
- start_is_white = linewhite(start_lnum);
- if (prev_start_is_white == start_is_white)
- {
- start_lnum -= dir;
- break;
- }
- for (;;)
- {
- if (start_lnum == (dir == BACKWARD
- ? 1 : curbuf->b_ml.ml_line_count))
- break;
- if (start_is_white != linewhite(start_lnum + dir)
- || (!start_is_white
- && startPS(start_lnum + (dir > 0
- ? 1 : 0), 0, 0)))
- break;
- start_lnum += dir;
- }
- if (!include)
- break;
- if (start_lnum == (dir == BACKWARD
- ? 1 : curbuf->b_ml.ml_line_count))
- break;
- prev_start_is_white = start_is_white;
- }
- }
- curwin->w_cursor.lnum = start_lnum;
- curwin->w_cursor.col = 0;
- return retval;
- }
-
- /*
- * First move back to the start_lnum of the paragraph or white lines
- */
- white_in_front = linewhite(start_lnum);
- while (start_lnum > 1)
- {
- if (white_in_front) // stop at first white line
- {
- if (!linewhite(start_lnum - 1))
- break;
- }
- else // stop at first non-white line of start of paragraph
- {
- if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0))
- break;
- }
- --start_lnum;
- }
-
- /*
- * Move past the end of any white lines.
- */
- end_lnum = start_lnum;
- while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum))
- ++end_lnum;
-
- --end_lnum;
- i = count;
- if (!include && white_in_front)
- --i;
- while (i--)
- {
- if (end_lnum == curbuf->b_ml.ml_line_count)
- return FAIL;
-
- if (!include)
- do_white = linewhite(end_lnum + 1);
-
- if (include || !do_white)
- {
- ++end_lnum;
- /*
- * skip to end of paragraph
- */
- while (end_lnum < curbuf->b_ml.ml_line_count
- && !linewhite(end_lnum + 1)
- && !startPS(end_lnum + 1, 0, 0))
- ++end_lnum;
- }
-
- if (i == 0 && white_in_front && include)
- break;
-
- /*
- * skip to end of white lines after paragraph
- */
- if (include || do_white)
- while (end_lnum < curbuf->b_ml.ml_line_count
- && linewhite(end_lnum + 1))
- ++end_lnum;
- }
-
- /*
- * If there are no empty lines at the end, try to find some empty lines at
- * the start (unless that has been done already).
- */
- if (!white_in_front && !linewhite(end_lnum) && include)
- while (start_lnum > 1 && linewhite(start_lnum - 1))
- --start_lnum;
-
- if (VIsual_active)
- {
- // Problem: when doing "Vipipip" nothing happens in a single white
- // line, we get stuck there. Trap this here.
- if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
- goto extend;
- if (VIsual.lnum != start_lnum)
- {
- VIsual.lnum = start_lnum;
- VIsual.col = 0;
- }
- VIsual_mode = 'V';
- redraw_curbuf_later(INVERTED); // update the inversion
- showmode();
- }
- else
- {
- oap->start.lnum = start_lnum;
- oap->start.col = 0;
- oap->motion_type = MLINE;
- }
- curwin->w_cursor.lnum = end_lnum;
- curwin->w_cursor.col = 0;
-
- return OK;
- }
-
- /*
- * Search quote char from string line[col].
- * Quote character escaped by one of the characters in "escape" is not counted
- * as a quote.
- * Returns column number of "quotechar" or -1 when not found.
- */
- static int
- find_next_quote(
- char_u *line,
- int col,
- int quotechar,
- char_u *escape) // escape characters, can be NULL
- {
- int c;
-
- for (;;)
- {
- c = line[col];
- if (c == NUL)
- return -1;
- else if (escape != NULL && vim_strchr(escape, c))
- ++col;
- else if (c == quotechar)
- break;
- if (has_mbyte)
- col += (*mb_ptr2len)(line + col);
- else
- ++col;
- }
- return col;
- }
-
- /*
- * Search backwards in "line" from column "col_start" to find "quotechar".
- * Quote character escaped by one of the characters in "escape" is not counted
- * as a quote.
- * Return the found column or zero.
- */
- static int
- find_prev_quote(
- char_u *line,
- int col_start,
- int quotechar,
- char_u *escape) // escape characters, can be NULL
- {
- int n;
-
- while (col_start > 0)
- {
- --col_start;
- col_start -= (*mb_head_off)(line, line + col_start);
- n = 0;
- if (escape != NULL)
- while (col_start - n > 0 && vim_strchr(escape,
- line[col_start - n - 1]) != NULL)
- ++n;
- if (n & 1)
- col_start -= n; // uneven number of escape chars, skip it
- else if (line[col_start] == quotechar)
- break;
- }
- return col_start;
- }
-
- /*
- * Find quote under the cursor, cursor at end.
- * Returns TRUE if found, else FALSE.
- */
- int
- current_quote(
- oparg_T *oap,
- long count,
- int include, // TRUE == include quote char
- int quotechar) // Quote character
- {
- char_u *line = ml_get_curline();
- int col_end;
- int col_start = curwin->w_cursor.col;
- int inclusive = FALSE;
- int vis_empty = TRUE; // Visual selection <= 1 char
- int vis_bef_curs = FALSE; // Visual starts before cursor
- int did_exclusive_adj = FALSE; // adjusted pos for 'selection'
- int inside_quotes = FALSE; // Looks like "i'" done before
- int selected_quote = FALSE; // Has quote inside selection
- int i;
- int restore_vis_bef = FALSE; // restore VIsual on abort
-
- // When 'selection' is "exclusive" move the cursor to where it would be
- // with 'selection' "inclusive", so that the logic is the same for both.
- // The cursor then is moved forward after adjusting the area.
- if (VIsual_active)
- {
- // this only works within one line
- if (VIsual.lnum != curwin->w_cursor.lnum)
- return FALSE;
-
- vis_bef_curs = LT_POS(VIsual, curwin->w_cursor);
- vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
- if (*p_sel == 'e')
- {
- if (vis_bef_curs)
- {
- dec_cursor();
- did_exclusive_adj = TRUE;
- }
- else if (!vis_empty)
- {
- dec(&VIsual);
- did_exclusive_adj = TRUE;
- }
- vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
- if (!vis_bef_curs && !vis_empty)
- {
- // VIsual needs to be the start of Visual selection.
- pos_T t = curwin->w_cursor;
-
- curwin->w_cursor = VIsual;
- VIsual = t;
- vis_bef_curs = TRUE;
- restore_vis_bef = TRUE;
- }
- }
- }
-
- if (!vis_empty)
- {
- // Check if the existing selection exactly spans the text inside
- // quotes.
- if (vis_bef_curs)
- {
- inside_quotes = VIsual.col > 0
- && line[VIsual.col - 1] == quotechar
- && line[curwin->w_cursor.col] != NUL
- && line[curwin->w_cursor.col + 1] == quotechar;
- i = VIsual.col;
- col_end = curwin->w_cursor.col;
- }
- else
- {
- inside_quotes = curwin->w_cursor.col > 0
- && line[curwin->w_cursor.col - 1] == quotechar
- && line[VIsual.col] != NUL
- && line[VIsual.col + 1] == quotechar;
- i = curwin->w_cursor.col;
- col_end = VIsual.col;
- }
-
- // Find out if we have a quote in the selection.
- while (i <= col_end)
- if (line[i++] == quotechar)
- {
- selected_quote = TRUE;
- break;
- }
- }
-
- if (!vis_empty && line[col_start] == quotechar)
- {
- // Already selecting something and on a quote character. Find the
- // next quoted string.
- if (vis_bef_curs)
- {
- // Assume we are on a closing quote: move to after the next
- // opening quote.
- col_start = find_next_quote(line, col_start + 1, quotechar, NULL);
- if (col_start < 0)
- goto abort_search;
- col_end = find_next_quote(line, col_start + 1, quotechar,
- curbuf->b_p_qe);
- if (col_end < 0)
- {
- // We were on a starting quote perhaps?
- col_end = col_start;
- col_start = curwin->w_cursor.col;
- }
- }
- else
- {
- col_end = find_prev_quote(line, col_start, quotechar, NULL);
- if (line[col_end] != quotechar)
- goto abort_search;
- col_start = find_prev_quote(line, col_end, quotechar,
- curbuf->b_p_qe);
- if (line[col_start] != quotechar)
- {
- // We were on an ending quote perhaps?
- col_start = col_end;
- col_end = curwin->w_cursor.col;
- }
- }
- }
- else
-
- if (line[col_start] == quotechar || !vis_empty)
- {
- int first_col = col_start;
-
- if (!vis_empty)
- {
- if (vis_bef_curs)
- first_col = find_next_quote(line, col_start, quotechar, NULL);
- else
- first_col = find_prev_quote(line, col_start, quotechar, NULL);
- }
-
- // The cursor is on a quote, we don't know if it's the opening or
- // closing quote. Search from the start of the line to find out.
- // Also do this when there is a Visual area, a' may leave the cursor
- // in between two strings.
- col_start = 0;
- for (;;)
- {
- // Find open quote character.
- col_start = find_next_quote(line, col_start, quotechar, NULL);
- if (col_start < 0 || col_start > first_col)
- goto abort_search;
- // Find close quote character.
- col_end = find_next_quote(line, col_start + 1, quotechar,
- curbuf->b_p_qe);
- if (col_end < 0)
- goto abort_search;
- // If is cursor between start and end quote character, it is
- // target text object.
- if (col_start <= first_col && first_col <= col_end)
- break;
- col_start = col_end + 1;
- }
- }
- else
- {
- // Search backward for a starting quote.
- col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe);
- if (line[col_start] != quotechar)
- {
- // No quote before the cursor, look after the cursor.
- col_start = find_next_quote(line, col_start, quotechar, NULL);
- if (col_start < 0)
- goto abort_search;
- }
-
- // Find close quote character.
- col_end = find_next_quote(line, col_start + 1, quotechar,
- curbuf->b_p_qe);
- if (col_end < 0)
- goto abort_search;
- }
-
- // When "include" is TRUE, include spaces after closing quote or before
- // the starting quote.
- if (include)
- {
- if (VIM_ISWHITE(line[col_end + 1]))
- while (VIM_ISWHITE(line[col_end + 1]))
- ++col_end;
- else
- while (col_start > 0 && VIM_ISWHITE(line[col_start - 1]))
- --col_start;
- }
-
- // Set start position. After vi" another i" must include the ".
- // For v2i" include the quotes.
- if (!include && count < 2 && (vis_empty || !inside_quotes))
- ++col_start;
- curwin->w_cursor.col = col_start;
- if (VIsual_active)
- {
- // Set the start of the Visual area when the Visual area was empty, we
- // were just inside quotes or the Visual area didn't start at a quote
- // and didn't include a quote.
- if (vis_empty
- || (vis_bef_curs
- && !selected_quote
- && (inside_quotes
- || (line[VIsual.col] != quotechar
- && (VIsual.col == 0
- || line[VIsual.col - 1] != quotechar)))))
- {
- VIsual = curwin->w_cursor;
- redraw_curbuf_later(INVERTED);
- }
- }
- else
- {
- oap->start = curwin->w_cursor;
- oap->motion_type = MCHAR;
- }
-
- // Set end position.
- curwin->w_cursor.col = col_end;
- if ((include || count > 1 // After vi" another i" must include the ".
- || (!vis_empty && inside_quotes)
- ) && inc_cursor() == 2)
- inclusive = TRUE;
- if (VIsual_active)
- {
- if (vis_empty || vis_bef_curs)
- {
- // decrement cursor when 'selection' is not exclusive
- if (*p_sel != 'e')
- dec_cursor();
- }
- else
- {
- // Cursor is at start of Visual area. Set the end of the Visual
- // area when it was just inside quotes or it didn't end at a
- // quote.
- if (inside_quotes
- || (!selected_quote
- && line[VIsual.col] != quotechar
- && (line[VIsual.col] == NUL
- || line[VIsual.col + 1] != quotechar)))
- {
- dec_cursor();
- VIsual = curwin->w_cursor;
- }
- curwin->w_cursor.col = col_start;
- }
- if (VIsual_mode == 'V')
- {
- VIsual_mode = 'v';
- redraw_cmdline = TRUE; // show mode later
- }
- }
- else
- {
- // Set inclusive and other oap's flags.
- oap->inclusive = inclusive;
- }
-
- return OK;
-
- abort_search:
- if (VIsual_active && *p_sel == 'e')
- {
- if (did_exclusive_adj)
- inc_cursor();
- if (restore_vis_bef)
- {
- pos_T t = curwin->w_cursor;
-
- curwin->w_cursor = VIsual;
- VIsual = t;
- }
- }
- return FALSE;
- }
-
- #endif // FEAT_TEXTOBJ
-
- /*
* Check if the pattern is zero-width.
* If move is TRUE, check from the beginning of the buffer, else from position
* "cur".
--- 2836,2841 ----
*** ../vim-8.2.0659/src/textobject.c 2020-04-29 21:03:25.339278952 +0200
--- src/textobject.c 2020-04-29 20:39:26.477343508 +0200
***************
*** 0 ****
--- 1,1965 ----
+ /* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+ /*
+ * textobject.c: functions for text objects
+ */
+ #include "vim.h"
+
+ static int cls(void);
+ static int skip_chars(int, int);
+
+ /*
+ * Find the start of the next sentence, searching in the direction specified
+ * by the "dir" argument. The cursor is positioned on the start of the next
+ * sentence when found. If the next sentence is found, return OK. Return FAIL
+ * otherwise. See ":h sentence" for the precise definition of a "sentence"
+ * text object.
+ */
+ int
+ findsent(int dir, long count)
+ {
+ pos_T pos, tpos;
+ int c;
+ int (*func)(pos_T *);
+ int startlnum;
+ int noskip = FALSE; // do not skip blanks
+ int cpo_J;
+ int found_dot;
+
+ pos = curwin->w_cursor;
+ if (dir == FORWARD)
+ func = incl;
+ else
+ func = decl;
+
+ while (count--)
+ {
+ /*
+ * if on an empty line, skip up to a non-empty line
+ */
+ if (gchar_pos(&pos) == NUL)
+ {
+ do
+ if ((*func)(&pos) == -1)
+ break;
+ while (gchar_pos(&pos) == NUL);
+ if (dir == FORWARD)
+ goto found;
+ }
+ /*
+ * if on the start of a paragraph or a section and searching forward,
+ * go to the next line
+ */
+ else if (dir == FORWARD && pos.col == 0 &&
+ startPS(pos.lnum, NUL, FALSE))
+ {
+ if (pos.lnum == curbuf->b_ml.ml_line_count)
+ return FAIL;
+ ++pos.lnum;
+ goto found;
+ }
+ else if (dir == BACKWARD)
+ decl(&pos);
+
+ // go back to the previous non-white non-punctuation character
+ found_dot = FALSE;
+ while (c = gchar_pos(&pos), VIM_ISWHITE(c)
+ || vim_strchr((char_u *)".!?)]\"'", c) != NULL)
+ {
+ tpos = pos;
+ if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD))
+ break;
+
+ if (found_dot)
+ break;
+ if (vim_strchr((char_u *) ".!?", c) != NULL)
+ found_dot = TRUE;
+
+ if (vim_strchr((char_u *) ")]\"'", c) != NULL
+ && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL)
+ break;
+
+ decl(&pos);
+ }
+
+ // remember the line where the search started
+ startlnum = pos.lnum;
+ cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
+
+ for (;;) // find end of sentence
+ {
+ c = gchar_pos(&pos);
+ if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
+ {
+ if (dir == BACKWARD && pos.lnum != startlnum)
+ ++pos.lnum;
+ break;
+ }
+ if (c == '.' || c == '!' || c == '?')
+ {
+ tpos = pos;
+ do
+ if ((c = inc(&tpos)) == -1)
+ break;
+ while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos))
+ != NULL);
+ if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL
+ || (cpo_J && (c == ' ' && inc(&tpos) >= 0
+ && gchar_pos(&tpos) == ' ')))
+ {
+ pos = tpos;
+ if (gchar_pos(&pos) == NUL) // skip NUL at EOL
+ inc(&pos);
+ break;
+ }
+ }
+ if ((*func)(&pos) == -1)
+ {
+ if (count)
+ return FAIL;
+ noskip = TRUE;
+ break;
+ }
+ }
+ found:
+ // skip white space
+ while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
+ if (incl(&pos) == -1)
+ break;
+ }
+
+ setpcmark();
+ curwin->w_cursor = pos;
+ return OK;
+ }
+
+ /*
+ * Find the next paragraph or section in direction 'dir'.
+ * Paragraphs are currently supposed to be separated by empty lines.
+ * If 'what' is NUL we go to the next paragraph.
+ * If 'what' is '{' or '}' we go to the next section.
+ * If 'both' is TRUE also stop at '}'.
+ * Return TRUE if the next paragraph or section was found.
+ */
+ int
+ findpar(
+ int *pincl, // Return: TRUE if last char is to be included
+ int dir,
+ long count,
+ int what,
+ int both)
+ {
+ linenr_T curr;
+ int did_skip; // TRUE after separating lines have been skipped
+ int first; // TRUE on first line
+ int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL);
+ #ifdef FEAT_FOLDING
+ linenr_T fold_first; // first line of a closed fold
+ linenr_T fold_last; // last line of a closed fold
+ int fold_skipped; // TRUE if a closed fold was skipped this
+ // iteration
+ #endif
+
+ curr = curwin->w_cursor.lnum;
+
+ while (count--)
+ {
+ did_skip = FALSE;
+ for (first = TRUE; ; first = FALSE)
+ {
+ if (*ml_get(curr) != NUL)
+ did_skip = TRUE;
+
+ #ifdef FEAT_FOLDING
+ // skip folded lines
+ fold_skipped = FALSE;
+ if (first && hasFolding(curr, &fold_first, &fold_last))
+ {
+ curr = ((dir > 0) ? fold_last : fold_first) + dir;
+ fold_skipped = TRUE;
+ }
+ #endif
+
+ // POSIX has its own ideas of what a paragraph boundary is and it
+ // doesn't match historical Vi: It also stops at a "{" in the
+ // first column and at an empty line.
+ if (!first && did_skip && (startPS(curr, what, both)
+ || (posix && what == NUL && *ml_get(curr) == '{')))
+ break;
+
+ #ifdef FEAT_FOLDING
+ if (fold_skipped)
+ curr -= dir;
+ #endif
+ if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
+ {
+ if (count)
+ return FALSE;
+ curr -= dir;
+ break;
+ }
+ }
+ }
+ setpcmark();
+ if (both && *ml_get(curr) == '}') // include line with '}'
+ ++curr;
+ curwin->w_cursor.lnum = curr;
+ if (curr == curbuf->b_ml.ml_line_count && what != '}')
+ {
+ char_u *line = ml_get(curr);
+
+ // Put the cursor on the last character in the last line and make the
+ // motion inclusive.
+ if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0)
+ {
+ --curwin->w_cursor.col;
+ curwin->w_cursor.col -=
+ (*mb_head_off)(line, line + curwin->w_cursor.col);
+ *pincl = TRUE;
+ }
+ }
+ else
+ curwin->w_cursor.col = 0;
+ return TRUE;
+ }
+
+ /*
+ * check if the string 's' is a nroff macro that is in option 'opt'
+ */
+ static int
+ inmacro(char_u *opt, char_u *s)
+ {
+ char_u *macro;
+
+ for (macro = opt; macro[0]; ++macro)
+ {
+ // Accept two characters in the option being equal to two characters
+ // in the line. A space in the option matches with a space in the
+ // line or the line having ended.
+ if ( (macro[0] == s[0]
+ || (macro[0] == ' '
+ && (s[0] == NUL || s[0] == ' ')))
+ && (macro[1] == s[1]
+ || ((macro[1] == NUL || macro[1] == ' ')
+ && (s[0] == NUL || s[1] == NUL || s[1] == ' '))))
+ break;
+ ++macro;
+ if (macro[0] == NUL)
+ break;
+ }
+ return (macro[0] != NUL);
+ }
+
+ /*
+ * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
+ * If 'para' is '{' or '}' only check for sections.
+ * If 'both' is TRUE also stop at '}'
+ */
+ int
+ startPS(linenr_T lnum, int para, int both)
+ {
+ char_u *s;
+
+ s = ml_get(lnum);
+ if (*s == para || *s == '\f' || (both && *s == '}'))
+ return TRUE;
+ if (*s == '.' && (inmacro(p_sections, s + 1) ||
+ (!para && inmacro(p_para, s + 1))))
+ return TRUE;
+ return FALSE;
+ }
+
+ /*
+ * The following routines do the word searches performed by the 'w', 'W',
+ * 'b', 'B', 'e', and 'E' commands.
+ */
+
+ /*
+ * To perform these searches, characters are placed into one of three
+ * classes, and transitions between classes determine word boundaries.
+ *
+ * The classes are:
+ *
+ * 0 - white space
+ * 1 - punctuation
+ * 2 or higher - keyword characters (letters, digits and underscore)
+ */
+
+ static int cls_bigword; // TRUE for "W", "B" or "E"
+
+ /*
+ * cls() - returns the class of character at curwin->w_cursor
+ *
+ * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars
+ * from class 2 and higher are reported as class 1 since only white space
+ * boundaries are of interest.
+ */
+ static int
+ cls(void)
+ {
+ int c;
+
+ c = gchar_cursor();
+ if (c == ' ' || c == '\t' || c == NUL)
+ return 0;
+ if (enc_dbcs != 0 && c > 0xFF)
+ {
+ // If cls_bigword, report multi-byte chars as class 1.
+ if (enc_dbcs == DBCS_KOR && cls_bigword)
+ return 1;
+
+ // process code leading/trailing bytes
+ return dbcs_class(((unsigned)c >> 8), (c & 0xFF));
+ }
+ if (enc_utf8)
+ {
+ c = utf_class(c);
+ if (c != 0 && cls_bigword)
+ return 1;
+ return c;
+ }
+
+ // If cls_bigword is TRUE, report all non-blanks as class 1.
+ if (cls_bigword)
+ return 1;
+
+ if (vim_iswordc(c))
+ return 2;
+ return 1;
+ }
+
+
+ /*
+ * fwd_word(count, type, eol) - move forward one word
+ *
+ * Returns FAIL if the cursor was already at the end of the file.
+ * If eol is TRUE, last word stops at end of line (for operators).
+ */
+ int
+ fwd_word(
+ long count,
+ int bigword, // "W", "E" or "B"
+ int eol)
+ {
+ int sclass; // starting class
+ int i;
+ int last_line;
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+ #ifdef FEAT_FOLDING
+ // When inside a range of folded lines, move to the last char of the
+ // last line.
+ if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
+ coladvance((colnr_T)MAXCOL);
+ #endif
+ sclass = cls();
+
+ /*
+ * We always move at least one character, unless on the last
+ * character in the buffer.
+ */
+ last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
+ i = inc_cursor();
+ if (i == -1 || (i >= 1 && last_line)) // started at last char in file
+ return FAIL;
+ if (i >= 1 && eol && count == 0) // started at last char in line
+ return OK;
+
+ /*
+ * Go one char past end of current word (if any)
+ */
+ if (sclass != 0)
+ while (cls() == sclass)
+ {
+ i = inc_cursor();
+ if (i == -1 || (i >= 1 && eol && count == 0))
+ return OK;
+ }
+
+ /*
+ * go to next non-white
+ */
+ while (cls() == 0)
+ {
+ /*
+ * We'll stop if we land on a blank line
+ */
+ if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
+ break;
+
+ i = inc_cursor();
+ if (i == -1 || (i >= 1 && eol && count == 0))
+ return OK;
+ }
+ }
+ return OK;
+ }
+
+ /*
+ * bck_word() - move backward 'count' words
+ *
+ * If stop is TRUE and we are already on the start of a word, move one less.
+ *
+ * Returns FAIL if top of the file was reached.
+ */
+ int
+ bck_word(long count, int bigword, int stop)
+ {
+ int sclass; // starting class
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+ #ifdef FEAT_FOLDING
+ // When inside a range of folded lines, move to the first char of the
+ // first line.
+ if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL))
+ curwin->w_cursor.col = 0;
+ #endif
+ sclass = cls();
+ if (dec_cursor() == -1) // started at start of file
+ return FAIL;
+
+ if (!stop || sclass == cls() || sclass == 0)
+ {
+ /*
+ * Skip white space before the word.
+ * Stop on an empty line.
+ */
+ while (cls() == 0)
+ {
+ if (curwin->w_cursor.col == 0
+ && LINEEMPTY(curwin->w_cursor.lnum))
+ goto finished;
+ if (dec_cursor() == -1) // hit start of file, stop here
+ return OK;
+ }
+
+ /*
+ * Move backward to start of this word.
+ */
+ if (skip_chars(cls(), BACKWARD))
+ return OK;
+ }
+
+ inc_cursor(); // overshot - forward one
+ finished:
+ stop = FALSE;
+ }
+ return OK;
+ }
+
+ /*
+ * end_word() - move to the end of the word
+ *
+ * There is an apparent bug in the 'e' motion of the real vi. At least on the
+ * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
+ * motion crosses blank lines. When the real vi crosses a blank line in an
+ * 'e' motion, the cursor is placed on the FIRST character of the next
+ * non-blank line. The 'E' command, however, works correctly. Since this
+ * appears to be a bug, I have not duplicated it here.
+ *
+ * Returns FAIL if end of the file was reached.
+ *
+ * If stop is TRUE and we are already on the end of a word, move one less.
+ * If empty is TRUE stop on an empty line.
+ */
+ int
+ end_word(
+ long count,
+ int bigword,
+ int stop,
+ int empty)
+ {
+ int sclass; // starting class
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+ #ifdef FEAT_FOLDING
+ // When inside a range of folded lines, move to the last char of the
+ // last line.
+ if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
+ coladvance((colnr_T)MAXCOL);
+ #endif
+ sclass = cls();
+ if (inc_cursor() == -1)
+ return FAIL;
+
+ /*
+ * If we're in the middle of a word, we just have to move to the end
+ * of it.
+ */
+ if (cls() == sclass && sclass != 0)
+ {
+ /*
+ * Move forward to end of the current word
+ */
+ if (skip_chars(sclass, FORWARD))
+ return FAIL;
+ }
+ else if (!stop || sclass == 0)
+ {
+ /*
+ * We were at the end of a word. Go to the end of the next word.
+ * First skip white space, if 'empty' is TRUE, stop at empty line.
+ */
+ while (cls() == 0)
+ {
+ if (empty && curwin->w_cursor.col == 0
+ && LINEEMPTY(curwin->w_cursor.lnum))
+ goto finished;
+ if (inc_cursor() == -1) // hit end of file, stop here
+ return FAIL;
+ }
+
+ /*
+ * Move forward to the end of this word.
+ */
+ if (skip_chars(cls(), FORWARD))
+ return FAIL;
+ }
+ dec_cursor(); // overshot - one char backward
+ finished:
+ stop = FALSE; // we move only one word less
+ }
+ return OK;
+ }
+
+ /*
+ * Move back to the end of the word.
+ *
+ * Returns FAIL if start of the file was reached.
+ */
+ int
+ bckend_word(
+ long count,
+ int bigword, // TRUE for "B"
+ int eol) // TRUE: stop at end of line.
+ {
+ int sclass; // starting class
+ int i;
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+ sclass = cls();
+ if ((i = dec_cursor()) == -1)
+ return FAIL;
+ if (eol && i == 1)
+ return OK;
+
+ /*
+ * Move backward to before the start of this word.
+ */
+ if (sclass != 0)
+ {
+ while (cls() == sclass)
+ if ((i = dec_cursor()) == -1 || (eol && i == 1))
+ return OK;
+ }
+
+ /*
+ * Move backward to end of the previous word
+ */
+ while (cls() == 0)
+ {
+ if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum))
+ break;
+ if ((i = dec_cursor()) == -1 || (eol && i == 1))
+ return OK;
+ }
+ }
+ return OK;
+ }
+
+ /*
+ * Skip a row of characters of the same class.
+ * Return TRUE when end-of-file reached, FALSE otherwise.
+ */
+ static int
+ skip_chars(int cclass, int dir)
+ {
+ while (cls() == cclass)
+ if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
+ return TRUE;
+ return FALSE;
+ }
+
+ #if defined(FEAT_TEXTOBJ) || defined(PROTO)
+ /*
+ * Go back to the start of the word or the start of white space
+ */
+ static void
+ back_in_line(void)
+ {
+ int sclass; // starting class
+
+ sclass = cls();
+ for (;;)
+ {
+ if (curwin->w_cursor.col == 0) // stop at start of line
+ break;
+ dec_cursor();
+ if (cls() != sclass) // stop at start of word
+ {
+ inc_cursor();
+ break;
+ }
+ }
+ }
+
+ static void
+ find_first_blank(pos_T *posp)
+ {
+ int c;
+
+ while (decl(posp) != -1)
+ {
+ c = gchar_pos(posp);
+ if (!VIM_ISWHITE(c))
+ {
+ incl(posp);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Skip count/2 sentences and count/2 separating white spaces.
+ */
+ static void
+ findsent_forward(
+ long count,
+ int at_start_sent) // cursor is at start of sentence
+ {
+ while (count--)
+ {
+ findsent(FORWARD, 1L);
+ if (at_start_sent)
+ find_first_blank(&curwin->w_cursor);
+ if (count == 0 || at_start_sent)
+ decl(&curwin->w_cursor);
+ at_start_sent = !at_start_sent;
+ }
+ }
+
+ /*
+ * Find word under cursor, cursor at end.
+ * Used while an operator is pending, and in Visual mode.
+ */
+ int
+ current_word(
+ oparg_T *oap,
+ long count,
+ int include, // TRUE: include word and white space
+ int bigword) // FALSE == word, TRUE == WORD
+ {
+ pos_T start_pos;
+ pos_T pos;
+ int inclusive = TRUE;
+ int include_white = FALSE;
+
+ cls_bigword = bigword;
+ CLEAR_POS(&start_pos);
+
+ // Correct cursor when 'selection' is exclusive
+ if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
+ dec_cursor();
+
+ /*
+ * When Visual mode is not active, or when the VIsual area is only one
+ * character, select the word and/or white space under the cursor.
+ */
+ if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual))
+ {
+ /*
+ * Go to start of current word or white space.
+ */
+ back_in_line();
+ start_pos = curwin->w_cursor;
+
+ /*
+ * If the start is on white space, and white space should be included
+ * (" word"), or start is not on white space, and white space should
+ * not be included ("word"), find end of word.
+ */
+ if ((cls() == 0) == include)
+ {
+ if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ /*
+ * If the start is not on white space, and white space should be
+ * included ("word "), or start is on white space and white
+ * space should not be included (" "), find start of word.
+ * If we end up in the first column of the next line (single char
+ * word) back up to end of the line.
+ */
+ fwd_word(1L, bigword, TRUE);
+ if (curwin->w_cursor.col == 0)
+ decl(&curwin->w_cursor);
+ else
+ oneleft();
+
+ if (include)
+ include_white = TRUE;
+ }
+
+ if (VIsual_active)
+ {
+ // should do something when inclusive == FALSE !
+ VIsual = start_pos;
+ redraw_curbuf_later(INVERTED); // update the inversion
+ }
+ else
+ {
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ }
+ --count;
+ }
+
+ /*
+ * When count is still > 0, extend with more objects.
+ */
+ while (count > 0)
+ {
+ inclusive = TRUE;
+ if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
+ {
+ /*
+ * In Visual mode, with cursor at start: move cursor back.
+ */
+ if (decl(&curwin->w_cursor) == -1)
+ return FAIL;
+ if (include != (cls() != 0))
+ {
+ if (bck_word(1L, bigword, TRUE) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (bckend_word(1L, bigword, TRUE) == FAIL)
+ return FAIL;
+ (void)incl(&curwin->w_cursor);
+ }
+ }
+ else
+ {
+ /*
+ * Move cursor forward one word and/or white area.
+ */
+ if (incl(&curwin->w_cursor) == -1)
+ return FAIL;
+ if (include != (cls() == 0))
+ {
+ if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
+ return FAIL;
+ /*
+ * If end is just past a new-line, we don't want to include
+ * the first character on the line.
+ * Put cursor on last char of white.
+ */
+ if (oneleft() == FAIL)
+ inclusive = FALSE;
+ }
+ else
+ {
+ if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
+ return FAIL;
+ }
+ }
+ --count;
+ }
+
+ if (include_white && (cls() != 0
+ || (curwin->w_cursor.col == 0 && !inclusive)))
+ {
+ /*
+ * If we don't include white space at the end, move the start
+ * to include some white space there. This makes "daw" work
+ * better on the last word in a sentence (and "2daw" on last-but-one
+ * word). Also when "2daw" deletes "word." at the end of the line
+ * (cursor is at start of next line).
+ * But don't delete white space at start of line (indent).
+ */
+ pos = curwin->w_cursor; // save cursor position
+ curwin->w_cursor = start_pos;
+ if (oneleft() == OK)
+ {
+ back_in_line();
+ if (cls() == 0 && curwin->w_cursor.col > 0)
+ {
+ if (VIsual_active)
+ VIsual = curwin->w_cursor;
+ else
+ oap->start = curwin->w_cursor;
+ }
+ }
+ curwin->w_cursor = pos; // put cursor back at end
+ }
+
+ if (VIsual_active)
+ {
+ if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor))
+ inc_cursor();
+ if (VIsual_mode == 'V')
+ {
+ VIsual_mode = 'v';
+ redraw_cmdline = TRUE; // show mode later
+ }
+ }
+ else
+ oap->inclusive = inclusive;
+
+ return OK;
+ }
+
+ /*
+ * Find sentence(s) under the cursor, cursor at end.
+ * When Visual active, extend it by one or more sentences.
+ */
+ int
+ current_sent(oparg_T *oap, long count, int include)
+ {
+ pos_T start_pos;
+ pos_T pos;
+ int start_blank;
+ int c;
+ int at_start_sent;
+ long ncount;
+
+ start_pos = curwin->w_cursor;
+ pos = start_pos;
+ findsent(FORWARD, 1L); // Find start of next sentence.
+
+ /*
+ * When the Visual area is bigger than one character: Extend it.
+ */
+ if (VIsual_active && !EQUAL_POS(start_pos, VIsual))
+ {
+ extend:
+ if (LT_POS(start_pos, VIsual))
+ {
+ /*
+ * Cursor at start of Visual area.
+ * Find out where we are:
+ * - in the white space before a sentence
+ * - in a sentence or just after it
+ * - at the start of a sentence
+ */
+ at_start_sent = TRUE;
+ decl(&pos);
+ while (LT_POS(pos, curwin->w_cursor))
+ {
+ c = gchar_pos(&pos);
+ if (!VIM_ISWHITE(c))
+ {
+ at_start_sent = FALSE;
+ break;
+ }
+ incl(&pos);
+ }
+ if (!at_start_sent)
+ {
+ findsent(BACKWARD, 1L);
+ if (EQUAL_POS(curwin->w_cursor, start_pos))
+ at_start_sent = TRUE; // exactly at start of sentence
+ else
+ // inside a sentence, go to its end (start of next)
+ findsent(FORWARD, 1L);
+ }
+ if (include) // "as" gets twice as much as "is"
+ count *= 2;
+ while (count--)
+ {
+ if (at_start_sent)
+ find_first_blank(&curwin->w_cursor);
+ c = gchar_cursor();
+ if (!at_start_sent || (!include && !VIM_ISWHITE(c)))
+ findsent(BACKWARD, 1L);
+ at_start_sent = !at_start_sent;
+ }
+ }
+ else
+ {
+ /*
+ * Cursor at end of Visual area.
+ * Find out where we are:
+ * - just before a sentence
+ * - just before or in the white space before a sentence
+ * - in a sentence
+ */
+ incl(&pos);
+ at_start_sent = TRUE;
+ // not just before a sentence
+ if (!EQUAL_POS(pos, curwin->w_cursor))
+ {
+ at_start_sent = FALSE;
+ while (LT_POS(pos, curwin->w_cursor))
+ {
+ c = gchar_pos(&pos);
+ if (!VIM_ISWHITE(c))
+ {
+ at_start_sent = TRUE;
+ break;
+ }
+ incl(&pos);
+ }
+ if (at_start_sent) // in the sentence
+ findsent(BACKWARD, 1L);
+ else // in/before white before a sentence
+ curwin->w_cursor = start_pos;
+ }
+
+ if (include) // "as" gets twice as much as "is"
+ count *= 2;
+ findsent_forward(count, at_start_sent);
+ if (*p_sel == 'e')
+ ++curwin->w_cursor.col;
+ }
+ return OK;
+ }
+
+ /*
+ * If the cursor started on a blank, check if it is just before the start
+ * of the next sentence.
+ */
+ while (c = gchar_pos(&pos), VIM_ISWHITE(c)) // VIM_ISWHITE() is a macro
+ incl(&pos);
+ if (EQUAL_POS(pos, curwin->w_cursor))
+ {
+ start_blank = TRUE;
+ find_first_blank(&start_pos); // go back to first blank
+ }
+ else
+ {
+ start_blank = FALSE;
+ findsent(BACKWARD, 1L);
+ start_pos = curwin->w_cursor;
+ }
+ if (include)
+ ncount = count * 2;
+ else
+ {
+ ncount = count;
+ if (start_blank)
+ --ncount;
+ }
+ if (ncount > 0)
+ findsent_forward(ncount, TRUE);
+ else
+ decl(&curwin->w_cursor);
+
+ if (include)
+ {
+ /*
+ * If the blank in front of the sentence is included, exclude the
+ * blanks at the end of the sentence, go back to the first blank.
+ * If there are no trailing blanks, try to include leading blanks.
+ */
+ if (start_blank)
+ {
+ find_first_blank(&curwin->w_cursor);
+ c = gchar_pos(&curwin->w_cursor); // VIM_ISWHITE() is a macro
+ if (VIM_ISWHITE(c))
+ decl(&curwin->w_cursor);
+ }
+ else if (c = gchar_cursor(), !VIM_ISWHITE(c))
+ find_first_blank(&start_pos);
+ }
+
+ if (VIsual_active)
+ {
+ // Avoid getting stuck with "is" on a single space before a sentence.
+ if (EQUAL_POS(start_pos, curwin->w_cursor))
+ goto extend;
+ if (*p_sel == 'e')
+ ++curwin->w_cursor.col;
+ VIsual = start_pos;
+ VIsual_mode = 'v';
+ redraw_cmdline = TRUE; // show mode later
+ redraw_curbuf_later(INVERTED); // update the inversion
+ }
+ else
+ {
+ // include a newline after the sentence, if there is one
+ if (incl(&curwin->w_cursor) == -1)
+ oap->inclusive = TRUE;
+ else
+ oap->inclusive = FALSE;
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ }
+ return OK;
+ }
+
+ /*
+ * Find block under the cursor, cursor at end.
+ * "what" and "other" are two matching parenthesis/brace/etc.
+ */
+ int
+ current_block(
+ oparg_T *oap,
+ long count,
+ int include, // TRUE == include white space
+ int what, // '(', '{', etc.
+ int other) // ')', '}', etc.
+ {
+ pos_T old_pos;
+ pos_T *pos = NULL;
+ pos_T start_pos;
+ pos_T *end_pos;
+ pos_T old_start, old_end;
+ char_u *save_cpo;
+ int sol = FALSE; // '{' at start of line
+
+ old_pos = curwin->w_cursor;
+ old_end = curwin->w_cursor; // remember where we started
+ old_start = old_end;
+
+ /*
+ * If we start on '(', '{', ')', '}', etc., use the whole block inclusive.
+ */
+ if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
+ {
+ setpcmark();
+ if (what == '{') // ignore indent
+ while (inindent(1))
+ if (inc_cursor() != 0)
+ break;
+ if (gchar_cursor() == what)
+ // cursor on '(' or '{', move cursor just after it
+ ++curwin->w_cursor.col;
+ }
+ else if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ old_start = VIsual;
+ curwin->w_cursor = VIsual; // cursor at low end of Visual
+ }
+ else
+ old_end = VIsual;
+
+ /*
+ * Search backwards for unclosed '(', '{', etc..
+ * Put this position in start_pos.
+ * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the
+ * user wants.
+ */
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%");
+ while (count-- > 0)
+ {
+ if ((pos = findmatch(NULL, what)) == NULL)
+ break;
+ curwin->w_cursor = *pos;
+ start_pos = *pos; // the findmatch for end_pos will overwrite *pos
+ }
+ p_cpo = save_cpo;
+
+ /*
+ * Search for matching ')', '}', etc.
+ * Put this position in curwin->w_cursor.
+ */
+ if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
+ {
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ curwin->w_cursor = *end_pos;
+
+ /*
+ * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE.
+ * If the ending '}', ')' or ']' is only preceded by indent, skip that
+ * indent. But only if the resulting area is not smaller than what we
+ * started with.
+ */
+ while (!include)
+ {
+ incl(&start_pos);
+ sol = (curwin->w_cursor.col == 0);
+ decl(&curwin->w_cursor);
+ while (inindent(1))
+ {
+ sol = TRUE;
+ if (decl(&curwin->w_cursor) != 0)
+ break;
+ }
+
+ /*
+ * In Visual mode, when the resulting area is not bigger than what we
+ * started with, extend it to the next block, and then exclude again.
+ */
+ if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor)
+ && VIsual_active)
+ {
+ curwin->w_cursor = old_start;
+ decl(&curwin->w_cursor);
+ if ((pos = findmatch(NULL, what)) == NULL)
+ {
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ start_pos = *pos;
+ curwin->w_cursor = *pos;
+ if ((end_pos = findmatch(NULL, other)) == NULL)
+ {
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ curwin->w_cursor = *end_pos;
+ }
+ else
+ break;
+ }
+
+ if (VIsual_active)
+ {
+ if (*p_sel == 'e')
+ inc(&curwin->w_cursor);
+ if (sol && gchar_cursor() != NUL)
+ inc(&curwin->w_cursor); // include the line break
+ VIsual = start_pos;
+ VIsual_mode = 'v';
+ redraw_curbuf_later(INVERTED); // update the inversion
+ showmode();
+ }
+ else
+ {
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ oap->inclusive = FALSE;
+ if (sol)
+ incl(&curwin->w_cursor);
+ else if (LTOREQ_POS(start_pos, curwin->w_cursor))
+ // Include the character under the cursor.
+ oap->inclusive = TRUE;
+ else
+ // End is before the start (no text in between <>, [], etc.): don't
+ // operate on any text.
+ curwin->w_cursor = start_pos;
+ }
+
+ return OK;
+ }
+
+ /*
+ * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>".
+ * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>".
+ */
+ static int
+ in_html_tag(
+ int end_tag)
+ {
+ char_u *line = ml_get_curline();
+ char_u *p;
+ int c;
+ int lc = NUL;
+ pos_T pos;
+
+ if (enc_dbcs)
+ {
+ char_u *lp = NULL;
+
+ // We search forward until the cursor, because searching backwards is
+ // very slow for DBCS encodings.
+ for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p))
+ if (*p == '>' || *p == '<')
+ {
+ lc = *p;
+ lp = p;
+ }
+ if (*p != '<') // check for '<' under cursor
+ {
+ if (lc != '<')
+ return FALSE;
+ p = lp;
+ }
+ }
+ else
+ {
+ for (p = line + curwin->w_cursor.col; p > line; )
+ {
+ if (*p == '<') // find '<' under/before cursor
+ break;
+ MB_PTR_BACK(line, p);
+ if (*p == '>') // find '>' before cursor
+ break;
+ }
+ if (*p != '<')
+ return FALSE;
+ }
+
+ pos.lnum = curwin->w_cursor.lnum;
+ pos.col = (colnr_T)(p - line);
+
+ MB_PTR_ADV(p);
+ if (end_tag)
+ // check that there is a '/' after the '<'
+ return *p == '/';
+
+ // check that there is no '/' after the '<'
+ if (*p == '/')
+ return FALSE;
+
+ // check that the matching '>' is not preceded by '/'
+ for (;;)
+ {
+ if (inc(&pos) < 0)
+ return FALSE;
+ c = *ml_get_pos(&pos);
+ if (c == '>')
+ break;
+ lc = c;
+ }
+ return lc != '/';
+ }
+
+ /*
+ * Find tag block under the cursor, cursor at end.
+ */
+ int
+ current_tagblock(
+ oparg_T *oap,
+ long count_arg,
+ int include) // TRUE == include white space
+ {
+ long count = count_arg;
+ long n;
+ pos_T old_pos;
+ pos_T start_pos;
+ pos_T end_pos;
+ pos_T old_start, old_end;
+ char_u *spat, *epat;
+ char_u *p;
+ char_u *cp;
+ int len;
+ int r;
+ int do_include = include;
+ int save_p_ws = p_ws;
+ int retval = FAIL;
+ int is_inclusive = TRUE;
+
+ p_ws = FALSE;
+
+ old_pos = curwin->w_cursor;
+ old_end = curwin->w_cursor; // remember where we started
+ old_start = old_end;
+ if (!VIsual_active || *p_sel == 'e')
+ decl(&old_end); // old_end is inclusive
+
+ /*
+ * If we start on "<aaa>" select that block.
+ */
+ if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
+ {
+ setpcmark();
+
+ // ignore indent
+ while (inindent(1))
+ if (inc_cursor() != 0)
+ break;
+
+ if (in_html_tag(FALSE))
+ {
+ // cursor on start tag, move to its '>'
+ while (*ml_get_cursor() != '>')
+ if (inc_cursor() < 0)
+ break;
+ }
+ else if (in_html_tag(TRUE))
+ {
+ // cursor on end tag, move to just before it
+ while (*ml_get_cursor() != '<')
+ if (dec_cursor() < 0)
+ break;
+ dec_cursor();
+ old_end = curwin->w_cursor;
+ }
+ }
+ else if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ old_start = VIsual;
+ curwin->w_cursor = VIsual; // cursor at low end of Visual
+ }
+ else
+ old_end = VIsual;
+
+ again:
+ /*
+ * Search backwards for unclosed "<aaa>".
+ * Put this position in start_pos.
+ */
+ for (n = 0; n < count; ++n)
+ {
+ if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
+ (char_u *)"",
+ (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
+ NULL, (linenr_T)0, 0L) <= 0)
+ {
+ curwin->w_cursor = old_pos;
+ goto theend;
+ }
+ }
+ start_pos = curwin->w_cursor;
+
+ /*
+ * Search for matching "</aaa>". First isolate the "aaa".
+ */
+ inc_cursor();
+ p = ml_get_cursor();
+ for (cp = p; *cp != NUL && *cp != '>' && !VIM_ISWHITE(*cp); MB_PTR_ADV(cp))
+ ;
+ len = (int)(cp - p);
+ if (len == 0)
+ {
+ curwin->w_cursor = old_pos;
+ goto theend;
+ }
+ spat = alloc(len + 31);
+ epat = alloc(len + 9);
+ if (spat == NULL || epat == NULL)
+ {
+ vim_free(spat);
+ vim_free(epat);
+ curwin->w_cursor = old_pos;
+ goto theend;
+ }
+ sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
+ sprintf((char *)epat, "</%.*s>\\c", len, p);
+
+ r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
+ 0, NULL, (linenr_T)0, 0L);
+
+ vim_free(spat);
+ vim_free(epat);
+
+ if (r < 1 || LT_POS(curwin->w_cursor, old_end))
+ {
+ // Can't find other end or it's before the previous end. Could be a
+ // HTML tag that doesn't have a matching end. Search backwards for
+ // another starting tag.
+ count = 1;
+ curwin->w_cursor = start_pos;
+ goto again;
+ }
+
+ if (do_include)
+ {
+ // Include up to the '>'.
+ while (*ml_get_cursor() != '>')
+ if (inc_cursor() < 0)
+ break;
+ }
+ else
+ {
+ char_u *c = ml_get_cursor();
+
+ // Exclude the '<' of the end tag.
+ // If the closing tag is on new line, do not decrement cursor, but
+ // make operation exclusive, so that the linefeed will be selected
+ if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0)
+ // do not decrement cursor
+ is_inclusive = FALSE;
+ else if (*c == '<')
+ dec_cursor();
+ }
+ end_pos = curwin->w_cursor;
+
+ if (!do_include)
+ {
+ // Exclude the start tag.
+ curwin->w_cursor = start_pos;
+ while (inc_cursor() >= 0)
+ if (*ml_get_cursor() == '>')
+ {
+ inc_cursor();
+ start_pos = curwin->w_cursor;
+ break;
+ }
+ curwin->w_cursor = end_pos;
+
+ // If we are in Visual mode and now have the same text as before set
+ // "do_include" and try again.
+ if (VIsual_active && EQUAL_POS(start_pos, old_start)
+ && EQUAL_POS(end_pos, old_end))
+ {
+ do_include = TRUE;
+ curwin->w_cursor = old_start;
+ count = count_arg;
+ goto again;
+ }
+ }
+
+ if (VIsual_active)
+ {
+ // If the end is before the start there is no text between tags, select
+ // the char under the cursor.
+ if (LT_POS(end_pos, start_pos))
+ curwin->w_cursor = start_pos;
+ else if (*p_sel == 'e')
+ inc_cursor();
+ VIsual = start_pos;
+ VIsual_mode = 'v';
+ redraw_curbuf_later(INVERTED); // update the inversion
+ showmode();
+ }
+ else
+ {
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ if (LT_POS(end_pos, start_pos))
+ {
+ // End is before the start: there is no text between tags; operate
+ // on an empty area.
+ curwin->w_cursor = start_pos;
+ oap->inclusive = FALSE;
+ }
+ else
+ oap->inclusive = is_inclusive;
+ }
+ retval = OK;
+
+ theend:
+ p_ws = save_p_ws;
+ return retval;
+ }
+
+ int
+ current_par(
+ oparg_T *oap,
+ long count,
+ int include, // TRUE == include white space
+ int type) // 'p' for paragraph, 'S' for section
+ {
+ linenr_T start_lnum;
+ linenr_T end_lnum;
+ int white_in_front;
+ int dir;
+ int start_is_white;
+ int prev_start_is_white;
+ int retval = OK;
+ int do_white = FALSE;
+ int t;
+ int i;
+
+ if (type == 'S') // not implemented yet
+ return FAIL;
+
+ start_lnum = curwin->w_cursor.lnum;
+
+ /*
+ * When visual area is more than one line: extend it.
+ */
+ if (VIsual_active && start_lnum != VIsual.lnum)
+ {
+ extend:
+ if (start_lnum < VIsual.lnum)
+ dir = BACKWARD;
+ else
+ dir = FORWARD;
+ for (i = count; --i >= 0; )
+ {
+ if (start_lnum ==
+ (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
+ {
+ retval = FAIL;
+ break;
+ }
+
+ prev_start_is_white = -1;
+ for (t = 0; t < 2; ++t)
+ {
+ start_lnum += dir;
+ start_is_white = linewhite(start_lnum);
+ if (prev_start_is_white == start_is_white)
+ {
+ start_lnum -= dir;
+ break;
+ }
+ for (;;)
+ {
+ if (start_lnum == (dir == BACKWARD
+ ? 1 : curbuf->b_ml.ml_line_count))
+ break;
+ if (start_is_white != linewhite(start_lnum + dir)
+ || (!start_is_white
+ && startPS(start_lnum + (dir > 0
+ ? 1 : 0), 0, 0)))
+ break;
+ start_lnum += dir;
+ }
+ if (!include)
+ break;
+ if (start_lnum == (dir == BACKWARD
+ ? 1 : curbuf->b_ml.ml_line_count))
+ break;
+ prev_start_is_white = start_is_white;
+ }
+ }
+ curwin->w_cursor.lnum = start_lnum;
+ curwin->w_cursor.col = 0;
+ return retval;
+ }
+
+ /*
+ * First move back to the start_lnum of the paragraph or white lines
+ */
+ white_in_front = linewhite(start_lnum);
+ while (start_lnum > 1)
+ {
+ if (white_in_front) // stop at first white line
+ {
+ if (!linewhite(start_lnum - 1))
+ break;
+ }
+ else // stop at first non-white line of start of paragraph
+ {
+ if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0))
+ break;
+ }
+ --start_lnum;
+ }
+
+ /*
+ * Move past the end of any white lines.
+ */
+ end_lnum = start_lnum;
+ while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum))
+ ++end_lnum;
+
+ --end_lnum;
+ i = count;
+ if (!include && white_in_front)
+ --i;
+ while (i--)
+ {
+ if (end_lnum == curbuf->b_ml.ml_line_count)
+ return FAIL;
+
+ if (!include)
+ do_white = linewhite(end_lnum + 1);
+
+ if (include || !do_white)
+ {
+ ++end_lnum;
+ /*
+ * skip to end of paragraph
+ */
+ while (end_lnum < curbuf->b_ml.ml_line_count
+ && !linewhite(end_lnum + 1)
+ && !startPS(end_lnum + 1, 0, 0))
+ ++end_lnum;
+ }
+
+ if (i == 0 && white_in_front && include)
+ break;
+
+ /*
+ * skip to end of white lines after paragraph
+ */
+ if (include || do_white)
+ while (end_lnum < curbuf->b_ml.ml_line_count
+ && linewhite(end_lnum + 1))
+ ++end_lnum;
+ }
+
+ /*
+ * If there are no empty lines at the end, try to find some empty lines at
+ * the start (unless that has been done already).
+ */
+ if (!white_in_front && !linewhite(end_lnum) && include)
+ while (start_lnum > 1 && linewhite(start_lnum - 1))
+ --start_lnum;
+
+ if (VIsual_active)
+ {
+ // Problem: when doing "Vipipip" nothing happens in a single white
+ // line, we get stuck there. Trap this here.
+ if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
+ goto extend;
+ if (VIsual.lnum != start_lnum)
+ {
+ VIsual.lnum = start_lnum;
+ VIsual.col = 0;
+ }
+ VIsual_mode = 'V';
+ redraw_curbuf_later(INVERTED); // update the inversion
+ showmode();
+ }
+ else
+ {
+ oap->start.lnum = start_lnum;
+ oap->start.col = 0;
+ oap->motion_type = MLINE;
+ }
+ curwin->w_cursor.lnum = end_lnum;
+ curwin->w_cursor.col = 0;
+
+ return OK;
+ }
+
+ /*
+ * Search quote char from string line[col].
+ * Quote character escaped by one of the characters in "escape" is not counted
+ * as a quote.
+ * Returns column number of "quotechar" or -1 when not found.
+ */
+ static int
+ find_next_quote(
+ char_u *line,
+ int col,
+ int quotechar,
+ char_u *escape) // escape characters, can be NULL
+ {
+ int c;
+
+ for (;;)
+ {
+ c = line[col];
+ if (c == NUL)
+ return -1;
+ else if (escape != NULL && vim_strchr(escape, c))
+ ++col;
+ else if (c == quotechar)
+ break;
+ if (has_mbyte)
+ col += (*mb_ptr2len)(line + col);
+ else
+ ++col;
+ }
+ return col;
+ }
+
+ /*
+ * Search backwards in "line" from column "col_start" to find "quotechar".
+ * Quote character escaped by one of the characters in "escape" is not counted
+ * as a quote.
+ * Return the found column or zero.
+ */
+ static int
+ find_prev_quote(
+ char_u *line,
+ int col_start,
+ int quotechar,
+ char_u *escape) // escape characters, can be NULL
+ {
+ int n;
+
+ while (col_start > 0)
+ {
+ --col_start;
+ col_start -= (*mb_head_off)(line, line + col_start);
+ n = 0;
+ if (escape != NULL)
+ while (col_start - n > 0 && vim_strchr(escape,
+ line[col_start - n - 1]) != NULL)
+ ++n;
+ if (n & 1)
+ col_start -= n; // uneven number of escape chars, skip it
+ else if (line[col_start] == quotechar)
+ break;
+ }
+ return col_start;
+ }
+
+ /*
+ * Find quote under the cursor, cursor at end.
+ * Returns TRUE if found, else FALSE.
+ */
+ int
+ current_quote(
+ oparg_T *oap,
+ long count,
+ int include, // TRUE == include quote char
+ int quotechar) // Quote character
+ {
+ char_u *line = ml_get_curline();
+ int col_end;
+ int col_start = curwin->w_cursor.col;
+ int inclusive = FALSE;
+ int vis_empty = TRUE; // Visual selection <= 1 char
+ int vis_bef_curs = FALSE; // Visual starts before cursor
+ int did_exclusive_adj = FALSE; // adjusted pos for 'selection'
+ int inside_quotes = FALSE; // Looks like "i'" done before
+ int selected_quote = FALSE; // Has quote inside selection
+ int i;
+ int restore_vis_bef = FALSE; // restore VIsual on abort
+
+ // When 'selection' is "exclusive" move the cursor to where it would be
+ // with 'selection' "inclusive", so that the logic is the same for both.
+ // The cursor then is moved forward after adjusting the area.
+ if (VIsual_active)
+ {
+ // this only works within one line
+ if (VIsual.lnum != curwin->w_cursor.lnum)
+ return FALSE;
+
+ vis_bef_curs = LT_POS(VIsual, curwin->w_cursor);
+ vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
+ if (*p_sel == 'e')
+ {
+ if (vis_bef_curs)
+ {
+ dec_cursor();
+ did_exclusive_adj = TRUE;
+ }
+ else if (!vis_empty)
+ {
+ dec(&VIsual);
+ did_exclusive_adj = TRUE;
+ }
+ vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
+ if (!vis_bef_curs && !vis_empty)
+ {
+ // VIsual needs to be the start of Visual selection.
+ pos_T t = curwin->w_cursor;
+
+ curwin->w_cursor = VIsual;
+ VIsual = t;
+ vis_bef_curs = TRUE;
+ restore_vis_bef = TRUE;
+ }
+ }
+ }
+
+ if (!vis_empty)
+ {
+ // Check if the existing selection exactly spans the text inside
+ // quotes.
+ if (vis_bef_curs)
+ {
+ inside_quotes = VIsual.col > 0
+ && line[VIsual.col - 1] == quotechar
+ && line[curwin->w_cursor.col] != NUL
+ && line[curwin->w_cursor.col + 1] == quotechar;
+ i = VIsual.col;
+ col_end = curwin->w_cursor.col;
+ }
+ else
+ {
+ inside_quotes = curwin->w_cursor.col > 0
+ && line[curwin->w_cursor.col - 1] == quotechar
+ && line[VIsual.col] != NUL
+ && line[VIsual.col + 1] == quotechar;
+ i = curwin->w_cursor.col;
+ col_end = VIsual.col;
+ }
+
+ // Find out if we have a quote in the selection.
+ while (i <= col_end)
+ if (line[i++] == quotechar)
+ {
+ selected_quote = TRUE;
+ break;
+ }
+ }
+
+ if (!vis_empty && line[col_start] == quotechar)
+ {
+ // Already selecting something and on a quote character. Find the
+ // next quoted string.
+ if (vis_bef_curs)
+ {
+ // Assume we are on a closing quote: move to after the next
+ // opening quote.
+ col_start = find_next_quote(line, col_start + 1, quotechar, NULL);
+ if (col_start < 0)
+ goto abort_search;
+ col_end = find_next_quote(line, col_start + 1, quotechar,
+ curbuf->b_p_qe);
+ if (col_end < 0)
+ {
+ // We were on a starting quote perhaps?
+ col_end = col_start;
+ col_start = curwin->w_cursor.col;
+ }
+ }
+ else
+ {
+ col_end = find_prev_quote(line, col_start, quotechar, NULL);
+ if (line[col_end] != quotechar)
+ goto abort_search;
+ col_start = find_prev_quote(line, col_end, quotechar,
+ curbuf->b_p_qe);
+ if (line[col_start] != quotechar)
+ {
+ // We were on an ending quote perhaps?
+ col_start = col_end;
+ col_end = curwin->w_cursor.col;
+ }
+ }
+ }
+ else
+
+ if (line[col_start] == quotechar || !vis_empty)
+ {
+ int first_col = col_start;
+
+ if (!vis_empty)
+ {
+ if (vis_bef_curs)
+ first_col = find_next_quote(line, col_start, quotechar, NULL);
+ else
+ first_col = find_prev_quote(line, col_start, quotechar, NULL);
+ }
+
+ // The cursor is on a quote, we don't know if it's the opening or
+ // closing quote. Search from the start of the line to find out.
+ // Also do this when there is a Visual area, a' may leave the cursor
+ // in between two strings.
+ col_start = 0;
+ for (;;)
+ {
+ // Find open quote character.
+ col_start = find_next_quote(line, col_start, quotechar, NULL);
+ if (col_start < 0 || col_start > first_col)
+ goto abort_search;
+ // Find close quote character.
+ col_end = find_next_quote(line, col_start + 1, quotechar,
+ curbuf->b_p_qe);
+ if (col_end < 0)
+ goto abort_search;
+ // If is cursor between start and end quote character, it is
+ // target text object.
+ if (col_start <= first_col && first_col <= col_end)
+ break;
+ col_start = col_end + 1;
+ }
+ }
+ else
+ {
+ // Search backward for a starting quote.
+ col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe);
+ if (line[col_start] != quotechar)
+ {
+ // No quote before the cursor, look after the cursor.
+ col_start = find_next_quote(line, col_start, quotechar, NULL);
+ if (col_start < 0)
+ goto abort_search;
+ }
+
+ // Find close quote character.
+ col_end = find_next_quote(line, col_start + 1, quotechar,
+ curbuf->b_p_qe);
+ if (col_end < 0)
+ goto abort_search;
+ }
+
+ // When "include" is TRUE, include spaces after closing quote or before
+ // the starting quote.
+ if (include)
+ {
+ if (VIM_ISWHITE(line[col_end + 1]))
+ while (VIM_ISWHITE(line[col_end + 1]))
+ ++col_end;
+ else
+ while (col_start > 0 && VIM_ISWHITE(line[col_start - 1]))
+ --col_start;
+ }
+
+ // Set start position. After vi" another i" must include the ".
+ // For v2i" include the quotes.
+ if (!include && count < 2 && (vis_empty || !inside_quotes))
+ ++col_start;
+ curwin->w_cursor.col = col_start;
+ if (VIsual_active)
+ {
+ // Set the start of the Visual area when the Visual area was empty, we
+ // were just inside quotes or the Visual area didn't start at a quote
+ // and didn't include a quote.
+ if (vis_empty
+ || (vis_bef_curs
+ && !selected_quote
+ && (inside_quotes
+ || (line[VIsual.col] != quotechar
+ && (VIsual.col == 0
+ || line[VIsual.col - 1] != quotechar)))))
+ {
+ VIsual = curwin->w_cursor;
+ redraw_curbuf_later(INVERTED);
+ }
+ }
+ else
+ {
+ oap->start = curwin->w_cursor;
+ oap->motion_type = MCHAR;
+ }
+
+ // Set end position.
+ curwin->w_cursor.col = col_end;
+ if ((include || count > 1 // After vi" another i" must include the ".
+ || (!vis_empty && inside_quotes)
+ ) && inc_cursor() == 2)
+ inclusive = TRUE;
+ if (VIsual_active)
+ {
+ if (vis_empty || vis_bef_curs)
+ {
+ // decrement cursor when 'selection' is not exclusive
+ if (*p_sel != 'e')
+ dec_cursor();
+ }
+ else
+ {
+ // Cursor is at start of Visual area. Set the end of the Visual
+ // area when it was just inside quotes or it didn't end at a
+ // quote.
+ if (inside_quotes
+ || (!selected_quote
+ && line[VIsual.col] != quotechar
+ && (line[VIsual.col] == NUL
+ || line[VIsual.col + 1] != quotechar)))
+ {
+ dec_cursor();
+ VIsual = curwin->w_cursor;
+ }
+ curwin->w_cursor.col = col_start;
+ }
+ if (VIsual_mode == 'V')
+ {
+ VIsual_mode = 'v';
+ redraw_cmdline = TRUE; // show mode later
+ }
+ }
+ else
+ {
+ // Set inclusive and other oap's flags.
+ oap->inclusive = inclusive;
+ }
+
+ return OK;
+
+ abort_search:
+ if (VIsual_active && *p_sel == 'e')
+ {
+ if (did_exclusive_adj)
+ inc_cursor();
+ if (restore_vis_bef)
+ {
+ pos_T t = curwin->w_cursor;
+
+ curwin->w_cursor = VIsual;
+ VIsual = t;
+ }
+ }
+ return FALSE;
+ }
+
+ #endif // FEAT_TEXTOBJ
*** ../vim-8.2.0659/src/version.c 2020-04-28 22:49:04.592008615 +0200
--- src/version.c 2020-04-29 20:40:38.305040505 +0200
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 660,
/**/

--
"So this is it," said Arthur, "we are going to die."
"Yes," said Ford, "except...no! Wait a minute!" He suddenly lunged across
the chamber at something behind Arthur's line of vision. "What's this
switch?" he cried.
"What? Where?" cried Arthur, twisting around.
"No, I was only fooling," said Ford, "we are going to die after all."
-- Douglas Adams, "The Hitchhiker's Guide to the Galaxy"

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Yegappan Lakshmanan

unread,
Apr 29, 2020, 4:08:32 PM4/29/20
to vim_dev
Hi Bram,

On Wed, Apr 29, 2020 at 12:04 PM Bram Moolenaar <Br...@moolenaar.net> wrote:

Patch 8.2.0660
Problem:    The search.c file is a bit big.
Solution:   Split off the text object code to a separate file. (Yegappan
            Lakshmanan, closes #6007)
Files:      Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
            src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
            src/proto.h, src/proto/search.pro, src/proto/textobject.pro,
            src/search.c, src/textobject.c



I think the above changes are not intentional and needs to be removed.

- Yegappan 

Tony Mechelynck

unread,
Apr 29, 2020, 4:09:03 PM4/29/20
to vim_dev
On Wed, Apr 29, 2020 at 9:04 PM Bram Moolenaar <Br...@moolenaar.net> wrote:
>
>
> Patch 8.2.0660
> Problem: The search.c file is a bit big.
> Solution: Split off the text object code to a separate file. (Yegappan
> Lakshmanan, closes #6007)
> Files: Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
> src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
> src/proto.h, src/proto/search.pro, src/proto/textobject.pro,
> src/search.c, src/textobject.c

After applying this patch, I get two compilation warnings for every
module in every build, as follows:

gcc -c -I. -Iproto -DHAVE_CONFIG_H -g -Wall -Wextra -Wshadow
-Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type
-Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
-DEXITFREE -DABORT_ON_INTERNAL_ERROR version.c -o objects/version.o
In file included from /usr/include/bits/libc-header-start.h:33:0,
from /usr/include/limits.h:26,
from
/usr/lib64/gcc/x86_64-suse-linux/7/include-fixed/limits.h:194,
from
/usr/lib64/gcc/x86_64-suse-linux/7/include-fixed/syslimits.h:7,
from
/usr/lib64/gcc/x86_64-suse-linux/7/include-fixed/limits.h:34,
from vim.h:50,
from version.c:10:
/usr/include/features.h:376:4: warning: #warning _FORTIFY_SOURCE
requires compiling with optimization (-O) [-Wcpp]
# warning _FORTIFY_SOURCE requires compiling with optimization (-O)
^~~~~~~
cc1: warning: unrecognized command line option ‘-Wno-cast-function-type’


This is with gcc 7.5.0 on openSUSE Linux 15.1

Bram Moolenaar

unread,
Apr 29, 2020, 5:17:06 PM4/29/20
to vim...@googlegroups.com, Yegappan Lakshmanan
[...]

> I think the above changes are not intentional and needs to be removed.

Oops, forgot to diff against the clean file.

--
"Space is big. Really big. You just won't believe how vastly hugely mind-
bogglingly big it is. I mean, you may think it's a long way down the
road to the chemist, but that's just peanuts to space."

Tony Mechelynck

unread,
Apr 29, 2020, 6:55:58 PM4/29/20
to vim_dev
On Wed, Apr 29, 2020 at 11:17 PM Bram Moolenaar <Br...@moolenaar.net> wrote:
> Oops, forgot to diff against the clean file.

Indeed, patch 664 makes my compilation warnings disappear.

This is one of the risks one runs when using a modified Makefile.
Maybe you should set your configure arguments by means of environment
variables (in the underlying shell) instead? That way your Makefile
would stay "clean". Me too I'm sometimes absent-minded, but by
sourcing an apropriate set of "export" statements I keep out of
trouble with no changes to the "official" Makefile.

For instance when compiling a Huge Vim I source the following script
at shell startup. Of course it is not exactly what you need but I
suppose you would know how to fit it to your own preferences:

##### Configure arguments for Huge Vim #####
export CONF_OPT_GUI='--enable-gui=gnome2'
export CONF_OPT_PERL='--enable-perlinterp'
export CONF_OPT_PYTHON='--enable-pythoninterp'
export CONF_OPT_PYTHON3='--disable-python3interp'
export CONF_OPT_TCL='--enable-tclinterp'
# /usr/bin/tclsh (softlink) is correctly set
export CONF_OPT_RUBY='--enable-rubyinterp'
export CONF_OPT_LUA='--enable-luainterp'
export CONF_OPT_MZSCHEME='--disable-mzschemeinterp'
# export CONF_OPT_PLTHOME='--with-plthome=/usr/local/plt'
export CONF_OPT_CSCOPE='--enable-cscope'
export CONF_OPT_MULTIBYTE='--enable-multibyte'
export CONF_OPT_TERMINAL='--enable-terminal'
export CONF_OPT_AUTOSERVE='--enable-autoservername'
export CONF_OPT_FEAT='--with-features=huge'
export CONF_ARGS2='--with-vim-name=vim-huge'
export CONF_OPT_COMPBY='"--with-compiledby=antoine.m...@gmail.com"'

Best regards, avoid the epidemy, and let's hear of you soon, :-)
Tony.
Reply all
Reply to author
Forward
0 new messages