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 <[email protected]>"
--- 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 <[email protected]>"
***************
*** 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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202004291904.03TJ4l0x021961%40masaka.moolenaar.net.

Raspunde prin e-mail lui