1ed8ce057SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2ed8ce057SBram Moolenaar *
3ed8ce057SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4ed8ce057SBram Moolenaar *
5ed8ce057SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6ed8ce057SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7ed8ce057SBram Moolenaar * See README.txt for an overview of the Vim source code.
8ed8ce057SBram Moolenaar */
9ed8ce057SBram Moolenaar
10ed8ce057SBram Moolenaar /*
11ed8ce057SBram Moolenaar * textobject.c: functions for text objects
12ed8ce057SBram Moolenaar */
13ed8ce057SBram Moolenaar #include "vim.h"
14ed8ce057SBram Moolenaar
15ed8ce057SBram Moolenaar static int cls(void);
16ed8ce057SBram Moolenaar static int skip_chars(int, int);
17ed8ce057SBram Moolenaar
18ed8ce057SBram Moolenaar /*
19ed8ce057SBram Moolenaar * Find the start of the next sentence, searching in the direction specified
20ed8ce057SBram Moolenaar * by the "dir" argument. The cursor is positioned on the start of the next
21ed8ce057SBram Moolenaar * sentence when found. If the next sentence is found, return OK. Return FAIL
22ed8ce057SBram Moolenaar * otherwise. See ":h sentence" for the precise definition of a "sentence"
23ed8ce057SBram Moolenaar * text object.
24ed8ce057SBram Moolenaar */
25ed8ce057SBram Moolenaar int
findsent(int dir,long count)26ed8ce057SBram Moolenaar findsent(int dir, long count)
27ed8ce057SBram Moolenaar {
28ed8ce057SBram Moolenaar pos_T pos, tpos;
292f03e5a0SBram Moolenaar pos_T prev_pos;
30ed8ce057SBram Moolenaar int c;
31ed8ce057SBram Moolenaar int (*func)(pos_T *);
32ed8ce057SBram Moolenaar int startlnum;
33ed8ce057SBram Moolenaar int noskip = FALSE; // do not skip blanks
34ed8ce057SBram Moolenaar int cpo_J;
35ed8ce057SBram Moolenaar int found_dot;
36ed8ce057SBram Moolenaar
37ed8ce057SBram Moolenaar pos = curwin->w_cursor;
38ed8ce057SBram Moolenaar if (dir == FORWARD)
39ed8ce057SBram Moolenaar func = incl;
40ed8ce057SBram Moolenaar else
41ed8ce057SBram Moolenaar func = decl;
42ed8ce057SBram Moolenaar
43ed8ce057SBram Moolenaar while (count--)
44ed8ce057SBram Moolenaar {
452f03e5a0SBram Moolenaar prev_pos = pos;
462f03e5a0SBram Moolenaar
47ed8ce057SBram Moolenaar /*
48ed8ce057SBram Moolenaar * if on an empty line, skip up to a non-empty line
49ed8ce057SBram Moolenaar */
50ed8ce057SBram Moolenaar if (gchar_pos(&pos) == NUL)
51ed8ce057SBram Moolenaar {
52ed8ce057SBram Moolenaar do
53ed8ce057SBram Moolenaar if ((*func)(&pos) == -1)
54ed8ce057SBram Moolenaar break;
55ed8ce057SBram Moolenaar while (gchar_pos(&pos) == NUL);
56ed8ce057SBram Moolenaar if (dir == FORWARD)
57ed8ce057SBram Moolenaar goto found;
58ed8ce057SBram Moolenaar }
59ed8ce057SBram Moolenaar /*
60ed8ce057SBram Moolenaar * if on the start of a paragraph or a section and searching forward,
61ed8ce057SBram Moolenaar * go to the next line
62ed8ce057SBram Moolenaar */
63ed8ce057SBram Moolenaar else if (dir == FORWARD && pos.col == 0 &&
64ed8ce057SBram Moolenaar startPS(pos.lnum, NUL, FALSE))
65ed8ce057SBram Moolenaar {
66ed8ce057SBram Moolenaar if (pos.lnum == curbuf->b_ml.ml_line_count)
67ed8ce057SBram Moolenaar return FAIL;
68ed8ce057SBram Moolenaar ++pos.lnum;
69ed8ce057SBram Moolenaar goto found;
70ed8ce057SBram Moolenaar }
71ed8ce057SBram Moolenaar else if (dir == BACKWARD)
72ed8ce057SBram Moolenaar decl(&pos);
73ed8ce057SBram Moolenaar
74ed8ce057SBram Moolenaar // go back to the previous non-white non-punctuation character
75ed8ce057SBram Moolenaar found_dot = FALSE;
76ed8ce057SBram Moolenaar while (c = gchar_pos(&pos), VIM_ISWHITE(c)
77ed8ce057SBram Moolenaar || vim_strchr((char_u *)".!?)]\"'", c) != NULL)
78ed8ce057SBram Moolenaar {
79ed8ce057SBram Moolenaar tpos = pos;
80ed8ce057SBram Moolenaar if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD))
81ed8ce057SBram Moolenaar break;
82ed8ce057SBram Moolenaar
83ed8ce057SBram Moolenaar if (found_dot)
84ed8ce057SBram Moolenaar break;
85ed8ce057SBram Moolenaar if (vim_strchr((char_u *) ".!?", c) != NULL)
86ed8ce057SBram Moolenaar found_dot = TRUE;
87ed8ce057SBram Moolenaar
88ed8ce057SBram Moolenaar if (vim_strchr((char_u *) ")]\"'", c) != NULL
89ed8ce057SBram Moolenaar && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL)
90ed8ce057SBram Moolenaar break;
91ed8ce057SBram Moolenaar
92ed8ce057SBram Moolenaar decl(&pos);
93ed8ce057SBram Moolenaar }
94ed8ce057SBram Moolenaar
95ed8ce057SBram Moolenaar // remember the line where the search started
96ed8ce057SBram Moolenaar startlnum = pos.lnum;
97ed8ce057SBram Moolenaar cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
98ed8ce057SBram Moolenaar
99ed8ce057SBram Moolenaar for (;;) // find end of sentence
100ed8ce057SBram Moolenaar {
101ed8ce057SBram Moolenaar c = gchar_pos(&pos);
102ed8ce057SBram Moolenaar if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
103ed8ce057SBram Moolenaar {
104ed8ce057SBram Moolenaar if (dir == BACKWARD && pos.lnum != startlnum)
105ed8ce057SBram Moolenaar ++pos.lnum;
106ed8ce057SBram Moolenaar break;
107ed8ce057SBram Moolenaar }
108ed8ce057SBram Moolenaar if (c == '.' || c == '!' || c == '?')
109ed8ce057SBram Moolenaar {
110ed8ce057SBram Moolenaar tpos = pos;
111ed8ce057SBram Moolenaar do
112ed8ce057SBram Moolenaar if ((c = inc(&tpos)) == -1)
113ed8ce057SBram Moolenaar break;
114ed8ce057SBram Moolenaar while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos))
115ed8ce057SBram Moolenaar != NULL);
116ed8ce057SBram Moolenaar if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL
117ed8ce057SBram Moolenaar || (cpo_J && (c == ' ' && inc(&tpos) >= 0
118ed8ce057SBram Moolenaar && gchar_pos(&tpos) == ' ')))
119ed8ce057SBram Moolenaar {
120ed8ce057SBram Moolenaar pos = tpos;
121ed8ce057SBram Moolenaar if (gchar_pos(&pos) == NUL) // skip NUL at EOL
122ed8ce057SBram Moolenaar inc(&pos);
123ed8ce057SBram Moolenaar break;
124ed8ce057SBram Moolenaar }
125ed8ce057SBram Moolenaar }
126ed8ce057SBram Moolenaar if ((*func)(&pos) == -1)
127ed8ce057SBram Moolenaar {
128ed8ce057SBram Moolenaar if (count)
129ed8ce057SBram Moolenaar return FAIL;
130ed8ce057SBram Moolenaar noskip = TRUE;
131ed8ce057SBram Moolenaar break;
132ed8ce057SBram Moolenaar }
133ed8ce057SBram Moolenaar }
134ed8ce057SBram Moolenaar found:
135ed8ce057SBram Moolenaar // skip white space
136ed8ce057SBram Moolenaar while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
137ed8ce057SBram Moolenaar if (incl(&pos) == -1)
138ed8ce057SBram Moolenaar break;
1392f03e5a0SBram Moolenaar
1402f03e5a0SBram Moolenaar if (EQUAL_POS(prev_pos, pos))
1412f03e5a0SBram Moolenaar {
1422f03e5a0SBram Moolenaar // didn't actually move, advance one character and try again
1432f03e5a0SBram Moolenaar if ((*func)(&pos) == -1)
1442f03e5a0SBram Moolenaar {
1452f03e5a0SBram Moolenaar if (count)
1462f03e5a0SBram Moolenaar return FAIL;
1472f03e5a0SBram Moolenaar break;
1482f03e5a0SBram Moolenaar }
1492f03e5a0SBram Moolenaar ++count;
1502f03e5a0SBram Moolenaar }
151ed8ce057SBram Moolenaar }
152ed8ce057SBram Moolenaar
153ed8ce057SBram Moolenaar setpcmark();
154ed8ce057SBram Moolenaar curwin->w_cursor = pos;
155ed8ce057SBram Moolenaar return OK;
156ed8ce057SBram Moolenaar }
157ed8ce057SBram Moolenaar
158ed8ce057SBram Moolenaar /*
159ed8ce057SBram Moolenaar * Find the next paragraph or section in direction 'dir'.
160ed8ce057SBram Moolenaar * Paragraphs are currently supposed to be separated by empty lines.
161ed8ce057SBram Moolenaar * If 'what' is NUL we go to the next paragraph.
162ed8ce057SBram Moolenaar * If 'what' is '{' or '}' we go to the next section.
163ed8ce057SBram Moolenaar * If 'both' is TRUE also stop at '}'.
164ed8ce057SBram Moolenaar * Return TRUE if the next paragraph or section was found.
165ed8ce057SBram Moolenaar */
166ed8ce057SBram Moolenaar int
findpar(int * pincl,int dir,long count,int what,int both)167ed8ce057SBram Moolenaar findpar(
168ed8ce057SBram Moolenaar int *pincl, // Return: TRUE if last char is to be included
169ed8ce057SBram Moolenaar int dir,
170ed8ce057SBram Moolenaar long count,
171ed8ce057SBram Moolenaar int what,
172ed8ce057SBram Moolenaar int both)
173ed8ce057SBram Moolenaar {
174ed8ce057SBram Moolenaar linenr_T curr;
175ed8ce057SBram Moolenaar int did_skip; // TRUE after separating lines have been skipped
176ed8ce057SBram Moolenaar int first; // TRUE on first line
177ed8ce057SBram Moolenaar int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL);
178ed8ce057SBram Moolenaar #ifdef FEAT_FOLDING
179ed8ce057SBram Moolenaar linenr_T fold_first; // first line of a closed fold
180ed8ce057SBram Moolenaar linenr_T fold_last; // last line of a closed fold
181ed8ce057SBram Moolenaar int fold_skipped; // TRUE if a closed fold was skipped this
182ed8ce057SBram Moolenaar // iteration
183ed8ce057SBram Moolenaar #endif
184ed8ce057SBram Moolenaar
185ed8ce057SBram Moolenaar curr = curwin->w_cursor.lnum;
186ed8ce057SBram Moolenaar
187ed8ce057SBram Moolenaar while (count--)
188ed8ce057SBram Moolenaar {
189ed8ce057SBram Moolenaar did_skip = FALSE;
190ed8ce057SBram Moolenaar for (first = TRUE; ; first = FALSE)
191ed8ce057SBram Moolenaar {
192ed8ce057SBram Moolenaar if (*ml_get(curr) != NUL)
193ed8ce057SBram Moolenaar did_skip = TRUE;
194ed8ce057SBram Moolenaar
195ed8ce057SBram Moolenaar #ifdef FEAT_FOLDING
196ed8ce057SBram Moolenaar // skip folded lines
197ed8ce057SBram Moolenaar fold_skipped = FALSE;
198ed8ce057SBram Moolenaar if (first && hasFolding(curr, &fold_first, &fold_last))
199ed8ce057SBram Moolenaar {
200ed8ce057SBram Moolenaar curr = ((dir > 0) ? fold_last : fold_first) + dir;
201ed8ce057SBram Moolenaar fold_skipped = TRUE;
202ed8ce057SBram Moolenaar }
203ed8ce057SBram Moolenaar #endif
204ed8ce057SBram Moolenaar
205ed8ce057SBram Moolenaar // POSIX has its own ideas of what a paragraph boundary is and it
206ed8ce057SBram Moolenaar // doesn't match historical Vi: It also stops at a "{" in the
207ed8ce057SBram Moolenaar // first column and at an empty line.
208ed8ce057SBram Moolenaar if (!first && did_skip && (startPS(curr, what, both)
209ed8ce057SBram Moolenaar || (posix && what == NUL && *ml_get(curr) == '{')))
210ed8ce057SBram Moolenaar break;
211ed8ce057SBram Moolenaar
212ed8ce057SBram Moolenaar #ifdef FEAT_FOLDING
213ed8ce057SBram Moolenaar if (fold_skipped)
214ed8ce057SBram Moolenaar curr -= dir;
215ed8ce057SBram Moolenaar #endif
216ed8ce057SBram Moolenaar if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
217ed8ce057SBram Moolenaar {
218ed8ce057SBram Moolenaar if (count)
219ed8ce057SBram Moolenaar return FALSE;
220ed8ce057SBram Moolenaar curr -= dir;
221ed8ce057SBram Moolenaar break;
222ed8ce057SBram Moolenaar }
223ed8ce057SBram Moolenaar }
224ed8ce057SBram Moolenaar }
225ed8ce057SBram Moolenaar setpcmark();
226ed8ce057SBram Moolenaar if (both && *ml_get(curr) == '}') // include line with '}'
227ed8ce057SBram Moolenaar ++curr;
228ed8ce057SBram Moolenaar curwin->w_cursor.lnum = curr;
229ed8ce057SBram Moolenaar if (curr == curbuf->b_ml.ml_line_count && what != '}')
230ed8ce057SBram Moolenaar {
231ed8ce057SBram Moolenaar char_u *line = ml_get(curr);
232ed8ce057SBram Moolenaar
233ed8ce057SBram Moolenaar // Put the cursor on the last character in the last line and make the
234ed8ce057SBram Moolenaar // motion inclusive.
235ed8ce057SBram Moolenaar if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0)
236ed8ce057SBram Moolenaar {
237ed8ce057SBram Moolenaar --curwin->w_cursor.col;
238ed8ce057SBram Moolenaar curwin->w_cursor.col -=
239ed8ce057SBram Moolenaar (*mb_head_off)(line, line + curwin->w_cursor.col);
240ed8ce057SBram Moolenaar *pincl = TRUE;
241ed8ce057SBram Moolenaar }
242ed8ce057SBram Moolenaar }
243ed8ce057SBram Moolenaar else
244ed8ce057SBram Moolenaar curwin->w_cursor.col = 0;
245ed8ce057SBram Moolenaar return TRUE;
246ed8ce057SBram Moolenaar }
247ed8ce057SBram Moolenaar
248ed8ce057SBram Moolenaar /*
249ed8ce057SBram Moolenaar * check if the string 's' is a nroff macro that is in option 'opt'
250ed8ce057SBram Moolenaar */
251ed8ce057SBram Moolenaar static int
inmacro(char_u * opt,char_u * s)252ed8ce057SBram Moolenaar inmacro(char_u *opt, char_u *s)
253ed8ce057SBram Moolenaar {
254ed8ce057SBram Moolenaar char_u *macro;
255ed8ce057SBram Moolenaar
256ed8ce057SBram Moolenaar for (macro = opt; macro[0]; ++macro)
257ed8ce057SBram Moolenaar {
258ed8ce057SBram Moolenaar // Accept two characters in the option being equal to two characters
259ed8ce057SBram Moolenaar // in the line. A space in the option matches with a space in the
260ed8ce057SBram Moolenaar // line or the line having ended.
261ed8ce057SBram Moolenaar if ( (macro[0] == s[0]
262ed8ce057SBram Moolenaar || (macro[0] == ' '
263ed8ce057SBram Moolenaar && (s[0] == NUL || s[0] == ' ')))
264ed8ce057SBram Moolenaar && (macro[1] == s[1]
265ed8ce057SBram Moolenaar || ((macro[1] == NUL || macro[1] == ' ')
266ed8ce057SBram Moolenaar && (s[0] == NUL || s[1] == NUL || s[1] == ' '))))
267ed8ce057SBram Moolenaar break;
268ed8ce057SBram Moolenaar ++macro;
269ed8ce057SBram Moolenaar if (macro[0] == NUL)
270ed8ce057SBram Moolenaar break;
271ed8ce057SBram Moolenaar }
272ed8ce057SBram Moolenaar return (macro[0] != NUL);
273ed8ce057SBram Moolenaar }
274ed8ce057SBram Moolenaar
275ed8ce057SBram Moolenaar /*
276ed8ce057SBram Moolenaar * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
277ed8ce057SBram Moolenaar * If 'para' is '{' or '}' only check for sections.
278ed8ce057SBram Moolenaar * If 'both' is TRUE also stop at '}'
279ed8ce057SBram Moolenaar */
280ed8ce057SBram Moolenaar int
startPS(linenr_T lnum,int para,int both)281ed8ce057SBram Moolenaar startPS(linenr_T lnum, int para, int both)
282ed8ce057SBram Moolenaar {
283ed8ce057SBram Moolenaar char_u *s;
284ed8ce057SBram Moolenaar
285ed8ce057SBram Moolenaar s = ml_get(lnum);
286ed8ce057SBram Moolenaar if (*s == para || *s == '\f' || (both && *s == '}'))
287ed8ce057SBram Moolenaar return TRUE;
288ed8ce057SBram Moolenaar if (*s == '.' && (inmacro(p_sections, s + 1) ||
289ed8ce057SBram Moolenaar (!para && inmacro(p_para, s + 1))))
290ed8ce057SBram Moolenaar return TRUE;
291ed8ce057SBram Moolenaar return FALSE;
292ed8ce057SBram Moolenaar }
293ed8ce057SBram Moolenaar
294ed8ce057SBram Moolenaar /*
295ed8ce057SBram Moolenaar * The following routines do the word searches performed by the 'w', 'W',
296ed8ce057SBram Moolenaar * 'b', 'B', 'e', and 'E' commands.
297ed8ce057SBram Moolenaar */
298ed8ce057SBram Moolenaar
299ed8ce057SBram Moolenaar /*
300ed8ce057SBram Moolenaar * To perform these searches, characters are placed into one of three
301ed8ce057SBram Moolenaar * classes, and transitions between classes determine word boundaries.
302ed8ce057SBram Moolenaar *
303ed8ce057SBram Moolenaar * The classes are:
304ed8ce057SBram Moolenaar *
305ed8ce057SBram Moolenaar * 0 - white space
306ed8ce057SBram Moolenaar * 1 - punctuation
307ed8ce057SBram Moolenaar * 2 or higher - keyword characters (letters, digits and underscore)
308ed8ce057SBram Moolenaar */
309ed8ce057SBram Moolenaar
310ed8ce057SBram Moolenaar static int cls_bigword; // TRUE for "W", "B" or "E"
311ed8ce057SBram Moolenaar
312ed8ce057SBram Moolenaar /*
313ed8ce057SBram Moolenaar * cls() - returns the class of character at curwin->w_cursor
314ed8ce057SBram Moolenaar *
315ed8ce057SBram Moolenaar * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars
316ed8ce057SBram Moolenaar * from class 2 and higher are reported as class 1 since only white space
317ed8ce057SBram Moolenaar * boundaries are of interest.
318ed8ce057SBram Moolenaar */
319ed8ce057SBram Moolenaar static int
cls(void)320ed8ce057SBram Moolenaar cls(void)
321ed8ce057SBram Moolenaar {
322ed8ce057SBram Moolenaar int c;
323ed8ce057SBram Moolenaar
324ed8ce057SBram Moolenaar c = gchar_cursor();
325ed8ce057SBram Moolenaar if (c == ' ' || c == '\t' || c == NUL)
326ed8ce057SBram Moolenaar return 0;
327ed8ce057SBram Moolenaar if (enc_dbcs != 0 && c > 0xFF)
328ed8ce057SBram Moolenaar {
329ed8ce057SBram Moolenaar // If cls_bigword, report multi-byte chars as class 1.
330ed8ce057SBram Moolenaar if (enc_dbcs == DBCS_KOR && cls_bigword)
331ed8ce057SBram Moolenaar return 1;
332ed8ce057SBram Moolenaar
333ed8ce057SBram Moolenaar // process code leading/trailing bytes
334ed8ce057SBram Moolenaar return dbcs_class(((unsigned)c >> 8), (c & 0xFF));
335ed8ce057SBram Moolenaar }
336ed8ce057SBram Moolenaar if (enc_utf8)
337ed8ce057SBram Moolenaar {
338ed8ce057SBram Moolenaar c = utf_class(c);
339ed8ce057SBram Moolenaar if (c != 0 && cls_bigword)
340ed8ce057SBram Moolenaar return 1;
341ed8ce057SBram Moolenaar return c;
342ed8ce057SBram Moolenaar }
343ed8ce057SBram Moolenaar
344ed8ce057SBram Moolenaar // If cls_bigword is TRUE, report all non-blanks as class 1.
345ed8ce057SBram Moolenaar if (cls_bigword)
346ed8ce057SBram Moolenaar return 1;
347ed8ce057SBram Moolenaar
348ed8ce057SBram Moolenaar if (vim_iswordc(c))
349ed8ce057SBram Moolenaar return 2;
350ed8ce057SBram Moolenaar return 1;
351ed8ce057SBram Moolenaar }
352ed8ce057SBram Moolenaar
353ed8ce057SBram Moolenaar
354ed8ce057SBram Moolenaar /*
355ed8ce057SBram Moolenaar * fwd_word(count, type, eol) - move forward one word
356ed8ce057SBram Moolenaar *
357ed8ce057SBram Moolenaar * Returns FAIL if the cursor was already at the end of the file.
358ed8ce057SBram Moolenaar * If eol is TRUE, last word stops at end of line (for operators).
359ed8ce057SBram Moolenaar */
360ed8ce057SBram Moolenaar int
fwd_word(long count,int bigword,int eol)361ed8ce057SBram Moolenaar fwd_word(
362ed8ce057SBram Moolenaar long count,
363ed8ce057SBram Moolenaar int bigword, // "W", "E" or "B"
364ed8ce057SBram Moolenaar int eol)
365ed8ce057SBram Moolenaar {
366ed8ce057SBram Moolenaar int sclass; // starting class
367ed8ce057SBram Moolenaar int i;
368ed8ce057SBram Moolenaar int last_line;
369ed8ce057SBram Moolenaar
370ed8ce057SBram Moolenaar curwin->w_cursor.coladd = 0;
371ed8ce057SBram Moolenaar cls_bigword = bigword;
372ed8ce057SBram Moolenaar while (--count >= 0)
373ed8ce057SBram Moolenaar {
374ed8ce057SBram Moolenaar #ifdef FEAT_FOLDING
375ed8ce057SBram Moolenaar // When inside a range of folded lines, move to the last char of the
376ed8ce057SBram Moolenaar // last line.
377ed8ce057SBram Moolenaar if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
378ed8ce057SBram Moolenaar coladvance((colnr_T)MAXCOL);
379ed8ce057SBram Moolenaar #endif
380ed8ce057SBram Moolenaar sclass = cls();
381ed8ce057SBram Moolenaar
382ed8ce057SBram Moolenaar /*
383ed8ce057SBram Moolenaar * We always move at least one character, unless on the last
384ed8ce057SBram Moolenaar * character in the buffer.
385ed8ce057SBram Moolenaar */
386ed8ce057SBram Moolenaar last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
387ed8ce057SBram Moolenaar i = inc_cursor();
388ed8ce057SBram Moolenaar if (i == -1 || (i >= 1 && last_line)) // started at last char in file
389ed8ce057SBram Moolenaar return FAIL;
390ed8ce057SBram Moolenaar if (i >= 1 && eol && count == 0) // started at last char in line
391ed8ce057SBram Moolenaar return OK;
392ed8ce057SBram Moolenaar
393ed8ce057SBram Moolenaar /*
394ed8ce057SBram Moolenaar * Go one char past end of current word (if any)
395ed8ce057SBram Moolenaar */
396ed8ce057SBram Moolenaar if (sclass != 0)
397ed8ce057SBram Moolenaar while (cls() == sclass)
398ed8ce057SBram Moolenaar {
399ed8ce057SBram Moolenaar i = inc_cursor();
400ed8ce057SBram Moolenaar if (i == -1 || (i >= 1 && eol && count == 0))
401ed8ce057SBram Moolenaar return OK;
402ed8ce057SBram Moolenaar }
403ed8ce057SBram Moolenaar
404ed8ce057SBram Moolenaar /*
405ed8ce057SBram Moolenaar * go to next non-white
406ed8ce057SBram Moolenaar */
407ed8ce057SBram Moolenaar while (cls() == 0)
408ed8ce057SBram Moolenaar {
409ed8ce057SBram Moolenaar /*
410ed8ce057SBram Moolenaar * We'll stop if we land on a blank line
411ed8ce057SBram Moolenaar */
412ed8ce057SBram Moolenaar if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
413ed8ce057SBram Moolenaar break;
414ed8ce057SBram Moolenaar
415ed8ce057SBram Moolenaar i = inc_cursor();
416ed8ce057SBram Moolenaar if (i == -1 || (i >= 1 && eol && count == 0))
417ed8ce057SBram Moolenaar return OK;
418ed8ce057SBram Moolenaar }
419ed8ce057SBram Moolenaar }
420ed8ce057SBram Moolenaar return OK;
421ed8ce057SBram Moolenaar }
422ed8ce057SBram Moolenaar
423ed8ce057SBram Moolenaar /*
424ed8ce057SBram Moolenaar * bck_word() - move backward 'count' words
425ed8ce057SBram Moolenaar *
426ed8ce057SBram Moolenaar * If stop is TRUE and we are already on the start of a word, move one less.
427ed8ce057SBram Moolenaar *
428ed8ce057SBram Moolenaar * Returns FAIL if top of the file was reached.
429ed8ce057SBram Moolenaar */
430ed8ce057SBram Moolenaar int
bck_word(long count,int bigword,int stop)431ed8ce057SBram Moolenaar bck_word(long count, int bigword, int stop)
432ed8ce057SBram Moolenaar {
433ed8ce057SBram Moolenaar int sclass; // starting class
434ed8ce057SBram Moolenaar
435ed8ce057SBram Moolenaar curwin->w_cursor.coladd = 0;
436ed8ce057SBram Moolenaar cls_bigword = bigword;
437ed8ce057SBram Moolenaar while (--count >= 0)
438ed8ce057SBram Moolenaar {
439ed8ce057SBram Moolenaar #ifdef FEAT_FOLDING
440ed8ce057SBram Moolenaar // When inside a range of folded lines, move to the first char of the
441ed8ce057SBram Moolenaar // first line.
442ed8ce057SBram Moolenaar if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL))
443ed8ce057SBram Moolenaar curwin->w_cursor.col = 0;
444ed8ce057SBram Moolenaar #endif
445ed8ce057SBram Moolenaar sclass = cls();
446ed8ce057SBram Moolenaar if (dec_cursor() == -1) // started at start of file
447ed8ce057SBram Moolenaar return FAIL;
448ed8ce057SBram Moolenaar
449ed8ce057SBram Moolenaar if (!stop || sclass == cls() || sclass == 0)
450ed8ce057SBram Moolenaar {
451ed8ce057SBram Moolenaar /*
452ed8ce057SBram Moolenaar * Skip white space before the word.
453ed8ce057SBram Moolenaar * Stop on an empty line.
454ed8ce057SBram Moolenaar */
455ed8ce057SBram Moolenaar while (cls() == 0)
456ed8ce057SBram Moolenaar {
457ed8ce057SBram Moolenaar if (curwin->w_cursor.col == 0
458ed8ce057SBram Moolenaar && LINEEMPTY(curwin->w_cursor.lnum))
459ed8ce057SBram Moolenaar goto finished;
460ed8ce057SBram Moolenaar if (dec_cursor() == -1) // hit start of file, stop here
461ed8ce057SBram Moolenaar return OK;
462ed8ce057SBram Moolenaar }
463ed8ce057SBram Moolenaar
464ed8ce057SBram Moolenaar /*
465ed8ce057SBram Moolenaar * Move backward to start of this word.
466ed8ce057SBram Moolenaar */
467ed8ce057SBram Moolenaar if (skip_chars(cls(), BACKWARD))
468ed8ce057SBram Moolenaar return OK;
469ed8ce057SBram Moolenaar }
470ed8ce057SBram Moolenaar
471ed8ce057SBram Moolenaar inc_cursor(); // overshot - forward one
472ed8ce057SBram Moolenaar finished:
473ed8ce057SBram Moolenaar stop = FALSE;
474ed8ce057SBram Moolenaar }
475ed8ce057SBram Moolenaar return OK;
476ed8ce057SBram Moolenaar }
477ed8ce057SBram Moolenaar
478ed8ce057SBram Moolenaar /*
479ed8ce057SBram Moolenaar * end_word() - move to the end of the word
480ed8ce057SBram Moolenaar *
481ed8ce057SBram Moolenaar * There is an apparent bug in the 'e' motion of the real vi. At least on the
482ed8ce057SBram Moolenaar * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
483ed8ce057SBram Moolenaar * motion crosses blank lines. When the real vi crosses a blank line in an
484ed8ce057SBram Moolenaar * 'e' motion, the cursor is placed on the FIRST character of the next
485ed8ce057SBram Moolenaar * non-blank line. The 'E' command, however, works correctly. Since this
486ed8ce057SBram Moolenaar * appears to be a bug, I have not duplicated it here.
487ed8ce057SBram Moolenaar *
488ed8ce057SBram Moolenaar * Returns FAIL if end of the file was reached.
489ed8ce057SBram Moolenaar *
490ed8ce057SBram Moolenaar * If stop is TRUE and we are already on the end of a word, move one less.
491ed8ce057SBram Moolenaar * If empty is TRUE stop on an empty line.
492ed8ce057SBram Moolenaar */
493ed8ce057SBram Moolenaar int
end_word(long count,int bigword,int stop,int empty)494ed8ce057SBram Moolenaar end_word(
495ed8ce057SBram Moolenaar long count,
496ed8ce057SBram Moolenaar int bigword,
497ed8ce057SBram Moolenaar int stop,
498ed8ce057SBram Moolenaar int empty)
499ed8ce057SBram Moolenaar {
500ed8ce057SBram Moolenaar int sclass; // starting class
501ed8ce057SBram Moolenaar
502ed8ce057SBram Moolenaar curwin->w_cursor.coladd = 0;
503ed8ce057SBram Moolenaar cls_bigword = bigword;
504ed8ce057SBram Moolenaar while (--count >= 0)
505ed8ce057SBram Moolenaar {
506ed8ce057SBram Moolenaar #ifdef FEAT_FOLDING
507ed8ce057SBram Moolenaar // When inside a range of folded lines, move to the last char of the
508ed8ce057SBram Moolenaar // last line.
509ed8ce057SBram Moolenaar if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
510ed8ce057SBram Moolenaar coladvance((colnr_T)MAXCOL);
511ed8ce057SBram Moolenaar #endif
512ed8ce057SBram Moolenaar sclass = cls();
513ed8ce057SBram Moolenaar if (inc_cursor() == -1)
514ed8ce057SBram Moolenaar return FAIL;
515ed8ce057SBram Moolenaar
516ed8ce057SBram Moolenaar /*
517ed8ce057SBram Moolenaar * If we're in the middle of a word, we just have to move to the end
518ed8ce057SBram Moolenaar * of it.
519ed8ce057SBram Moolenaar */
520ed8ce057SBram Moolenaar if (cls() == sclass && sclass != 0)
521ed8ce057SBram Moolenaar {
522ed8ce057SBram Moolenaar /*
523ed8ce057SBram Moolenaar * Move forward to end of the current word
524ed8ce057SBram Moolenaar */
525ed8ce057SBram Moolenaar if (skip_chars(sclass, FORWARD))
526ed8ce057SBram Moolenaar return FAIL;
527ed8ce057SBram Moolenaar }
528ed8ce057SBram Moolenaar else if (!stop || sclass == 0)
529ed8ce057SBram Moolenaar {
530ed8ce057SBram Moolenaar /*
531ed8ce057SBram Moolenaar * We were at the end of a word. Go to the end of the next word.
532ed8ce057SBram Moolenaar * First skip white space, if 'empty' is TRUE, stop at empty line.
533ed8ce057SBram Moolenaar */
534ed8ce057SBram Moolenaar while (cls() == 0)
535ed8ce057SBram Moolenaar {
536ed8ce057SBram Moolenaar if (empty && curwin->w_cursor.col == 0
537ed8ce057SBram Moolenaar && LINEEMPTY(curwin->w_cursor.lnum))
538ed8ce057SBram Moolenaar goto finished;
539ed8ce057SBram Moolenaar if (inc_cursor() == -1) // hit end of file, stop here
540ed8ce057SBram Moolenaar return FAIL;
541ed8ce057SBram Moolenaar }
542ed8ce057SBram Moolenaar
543ed8ce057SBram Moolenaar /*
544ed8ce057SBram Moolenaar * Move forward to the end of this word.
545ed8ce057SBram Moolenaar */
546ed8ce057SBram Moolenaar if (skip_chars(cls(), FORWARD))
547ed8ce057SBram Moolenaar return FAIL;
548ed8ce057SBram Moolenaar }
549ed8ce057SBram Moolenaar dec_cursor(); // overshot - one char backward
550ed8ce057SBram Moolenaar finished:
551ed8ce057SBram Moolenaar stop = FALSE; // we move only one word less
552ed8ce057SBram Moolenaar }
553ed8ce057SBram Moolenaar return OK;
554ed8ce057SBram Moolenaar }
555ed8ce057SBram Moolenaar
556ed8ce057SBram Moolenaar /*
557ed8ce057SBram Moolenaar * Move back to the end of the word.
558ed8ce057SBram Moolenaar *
559ed8ce057SBram Moolenaar * Returns FAIL if start of the file was reached.
560ed8ce057SBram Moolenaar */
561ed8ce057SBram Moolenaar int
bckend_word(long count,int bigword,int eol)562ed8ce057SBram Moolenaar bckend_word(
563ed8ce057SBram Moolenaar long count,
564ed8ce057SBram Moolenaar int bigword, // TRUE for "B"
565ed8ce057SBram Moolenaar int eol) // TRUE: stop at end of line.
566ed8ce057SBram Moolenaar {
567ed8ce057SBram Moolenaar int sclass; // starting class
568ed8ce057SBram Moolenaar int i;
569ed8ce057SBram Moolenaar
570ed8ce057SBram Moolenaar curwin->w_cursor.coladd = 0;
571ed8ce057SBram Moolenaar cls_bigword = bigword;
572ed8ce057SBram Moolenaar while (--count >= 0)
573ed8ce057SBram Moolenaar {
574ed8ce057SBram Moolenaar sclass = cls();
575ed8ce057SBram Moolenaar if ((i = dec_cursor()) == -1)
576ed8ce057SBram Moolenaar return FAIL;
577ed8ce057SBram Moolenaar if (eol && i == 1)
578ed8ce057SBram Moolenaar return OK;
579ed8ce057SBram Moolenaar
580ed8ce057SBram Moolenaar /*
581ed8ce057SBram Moolenaar * Move backward to before the start of this word.
582ed8ce057SBram Moolenaar */
583ed8ce057SBram Moolenaar if (sclass != 0)
584ed8ce057SBram Moolenaar {
585ed8ce057SBram Moolenaar while (cls() == sclass)
586ed8ce057SBram Moolenaar if ((i = dec_cursor()) == -1 || (eol && i == 1))
587ed8ce057SBram Moolenaar return OK;
588ed8ce057SBram Moolenaar }
589ed8ce057SBram Moolenaar
590ed8ce057SBram Moolenaar /*
591ed8ce057SBram Moolenaar * Move backward to end of the previous word
592ed8ce057SBram Moolenaar */
593ed8ce057SBram Moolenaar while (cls() == 0)
594ed8ce057SBram Moolenaar {
595ed8ce057SBram Moolenaar if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum))
596ed8ce057SBram Moolenaar break;
597ed8ce057SBram Moolenaar if ((i = dec_cursor()) == -1 || (eol && i == 1))
598ed8ce057SBram Moolenaar return OK;
599ed8ce057SBram Moolenaar }
600ed8ce057SBram Moolenaar }
601ed8ce057SBram Moolenaar return OK;
602ed8ce057SBram Moolenaar }
603ed8ce057SBram Moolenaar
604ed8ce057SBram Moolenaar /*
605ed8ce057SBram Moolenaar * Skip a row of characters of the same class.
606ed8ce057SBram Moolenaar * Return TRUE when end-of-file reached, FALSE otherwise.
607ed8ce057SBram Moolenaar */
608ed8ce057SBram Moolenaar static int
skip_chars(int cclass,int dir)609ed8ce057SBram Moolenaar skip_chars(int cclass, int dir)
610ed8ce057SBram Moolenaar {
611ed8ce057SBram Moolenaar while (cls() == cclass)
612ed8ce057SBram Moolenaar if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
613ed8ce057SBram Moolenaar return TRUE;
614ed8ce057SBram Moolenaar return FALSE;
615ed8ce057SBram Moolenaar }
616ed8ce057SBram Moolenaar
617ed8ce057SBram Moolenaar #if defined(FEAT_TEXTOBJ) || defined(PROTO)
618ed8ce057SBram Moolenaar /*
619ed8ce057SBram Moolenaar * Go back to the start of the word or the start of white space
620ed8ce057SBram Moolenaar */
621ed8ce057SBram Moolenaar static void
back_in_line(void)622ed8ce057SBram Moolenaar back_in_line(void)
623ed8ce057SBram Moolenaar {
624ed8ce057SBram Moolenaar int sclass; // starting class
625ed8ce057SBram Moolenaar
626ed8ce057SBram Moolenaar sclass = cls();
627ed8ce057SBram Moolenaar for (;;)
628ed8ce057SBram Moolenaar {
629ed8ce057SBram Moolenaar if (curwin->w_cursor.col == 0) // stop at start of line
630ed8ce057SBram Moolenaar break;
631ed8ce057SBram Moolenaar dec_cursor();
632ed8ce057SBram Moolenaar if (cls() != sclass) // stop at start of word
633ed8ce057SBram Moolenaar {
634ed8ce057SBram Moolenaar inc_cursor();
635ed8ce057SBram Moolenaar break;
636ed8ce057SBram Moolenaar }
637ed8ce057SBram Moolenaar }
638ed8ce057SBram Moolenaar }
639ed8ce057SBram Moolenaar
640ed8ce057SBram Moolenaar static void
find_first_blank(pos_T * posp)641ed8ce057SBram Moolenaar find_first_blank(pos_T *posp)
642ed8ce057SBram Moolenaar {
643ed8ce057SBram Moolenaar int c;
644ed8ce057SBram Moolenaar
645ed8ce057SBram Moolenaar while (decl(posp) != -1)
646ed8ce057SBram Moolenaar {
647ed8ce057SBram Moolenaar c = gchar_pos(posp);
648ed8ce057SBram Moolenaar if (!VIM_ISWHITE(c))
649ed8ce057SBram Moolenaar {
650ed8ce057SBram Moolenaar incl(posp);
651ed8ce057SBram Moolenaar break;
652ed8ce057SBram Moolenaar }
653ed8ce057SBram Moolenaar }
654ed8ce057SBram Moolenaar }
655ed8ce057SBram Moolenaar
656ed8ce057SBram Moolenaar /*
657ed8ce057SBram Moolenaar * Skip count/2 sentences and count/2 separating white spaces.
658ed8ce057SBram Moolenaar */
659ed8ce057SBram Moolenaar static void
findsent_forward(long count,int at_start_sent)660ed8ce057SBram Moolenaar findsent_forward(
661ed8ce057SBram Moolenaar long count,
662ed8ce057SBram Moolenaar int at_start_sent) // cursor is at start of sentence
663ed8ce057SBram Moolenaar {
664ed8ce057SBram Moolenaar while (count--)
665ed8ce057SBram Moolenaar {
666ed8ce057SBram Moolenaar findsent(FORWARD, 1L);
667ed8ce057SBram Moolenaar if (at_start_sent)
668ed8ce057SBram Moolenaar find_first_blank(&curwin->w_cursor);
669ed8ce057SBram Moolenaar if (count == 0 || at_start_sent)
670ed8ce057SBram Moolenaar decl(&curwin->w_cursor);
671ed8ce057SBram Moolenaar at_start_sent = !at_start_sent;
672ed8ce057SBram Moolenaar }
673ed8ce057SBram Moolenaar }
674ed8ce057SBram Moolenaar
675ed8ce057SBram Moolenaar /*
676ed8ce057SBram Moolenaar * Find word under cursor, cursor at end.
677ed8ce057SBram Moolenaar * Used while an operator is pending, and in Visual mode.
678ed8ce057SBram Moolenaar */
679ed8ce057SBram Moolenaar int
current_word(oparg_T * oap,long count,int include,int bigword)680ed8ce057SBram Moolenaar current_word(
681ed8ce057SBram Moolenaar oparg_T *oap,
682ed8ce057SBram Moolenaar long count,
683ed8ce057SBram Moolenaar int include, // TRUE: include word and white space
684ed8ce057SBram Moolenaar int bigword) // FALSE == word, TRUE == WORD
685ed8ce057SBram Moolenaar {
686ed8ce057SBram Moolenaar pos_T start_pos;
687ed8ce057SBram Moolenaar pos_T pos;
688ed8ce057SBram Moolenaar int inclusive = TRUE;
689ed8ce057SBram Moolenaar int include_white = FALSE;
690ed8ce057SBram Moolenaar
691ed8ce057SBram Moolenaar cls_bigword = bigword;
692ed8ce057SBram Moolenaar CLEAR_POS(&start_pos);
693ed8ce057SBram Moolenaar
694ed8ce057SBram Moolenaar // Correct cursor when 'selection' is exclusive
695ed8ce057SBram Moolenaar if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
696ed8ce057SBram Moolenaar dec_cursor();
697ed8ce057SBram Moolenaar
698ed8ce057SBram Moolenaar /*
699ed8ce057SBram Moolenaar * When Visual mode is not active, or when the VIsual area is only one
700ed8ce057SBram Moolenaar * character, select the word and/or white space under the cursor.
701ed8ce057SBram Moolenaar */
702ed8ce057SBram Moolenaar if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual))
703ed8ce057SBram Moolenaar {
704ed8ce057SBram Moolenaar /*
705ed8ce057SBram Moolenaar * Go to start of current word or white space.
706ed8ce057SBram Moolenaar */
707ed8ce057SBram Moolenaar back_in_line();
708ed8ce057SBram Moolenaar start_pos = curwin->w_cursor;
709ed8ce057SBram Moolenaar
710ed8ce057SBram Moolenaar /*
711ed8ce057SBram Moolenaar * If the start is on white space, and white space should be included
712ed8ce057SBram Moolenaar * (" word"), or start is not on white space, and white space should
713ed8ce057SBram Moolenaar * not be included ("word"), find end of word.
714ed8ce057SBram Moolenaar */
715ed8ce057SBram Moolenaar if ((cls() == 0) == include)
716ed8ce057SBram Moolenaar {
717ed8ce057SBram Moolenaar if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
718ed8ce057SBram Moolenaar return FAIL;
719ed8ce057SBram Moolenaar }
720ed8ce057SBram Moolenaar else
721ed8ce057SBram Moolenaar {
722ed8ce057SBram Moolenaar /*
723ed8ce057SBram Moolenaar * If the start is not on white space, and white space should be
724ed8ce057SBram Moolenaar * included ("word "), or start is on white space and white
725ed8ce057SBram Moolenaar * space should not be included (" "), find start of word.
726ed8ce057SBram Moolenaar * If we end up in the first column of the next line (single char
727ed8ce057SBram Moolenaar * word) back up to end of the line.
728ed8ce057SBram Moolenaar */
729ed8ce057SBram Moolenaar fwd_word(1L, bigword, TRUE);
730ed8ce057SBram Moolenaar if (curwin->w_cursor.col == 0)
731ed8ce057SBram Moolenaar decl(&curwin->w_cursor);
732ed8ce057SBram Moolenaar else
733ed8ce057SBram Moolenaar oneleft();
734ed8ce057SBram Moolenaar
735ed8ce057SBram Moolenaar if (include)
736ed8ce057SBram Moolenaar include_white = TRUE;
737ed8ce057SBram Moolenaar }
738ed8ce057SBram Moolenaar
739ed8ce057SBram Moolenaar if (VIsual_active)
740ed8ce057SBram Moolenaar {
741ed8ce057SBram Moolenaar // should do something when inclusive == FALSE !
742ed8ce057SBram Moolenaar VIsual = start_pos;
743ed8ce057SBram Moolenaar redraw_curbuf_later(INVERTED); // update the inversion
744ed8ce057SBram Moolenaar }
745ed8ce057SBram Moolenaar else
746ed8ce057SBram Moolenaar {
747ed8ce057SBram Moolenaar oap->start = start_pos;
748ed8ce057SBram Moolenaar oap->motion_type = MCHAR;
749ed8ce057SBram Moolenaar }
750ed8ce057SBram Moolenaar --count;
751ed8ce057SBram Moolenaar }
752ed8ce057SBram Moolenaar
753ed8ce057SBram Moolenaar /*
754ed8ce057SBram Moolenaar * When count is still > 0, extend with more objects.
755ed8ce057SBram Moolenaar */
756ed8ce057SBram Moolenaar while (count > 0)
757ed8ce057SBram Moolenaar {
758ed8ce057SBram Moolenaar inclusive = TRUE;
759ed8ce057SBram Moolenaar if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
760ed8ce057SBram Moolenaar {
761ed8ce057SBram Moolenaar /*
762ed8ce057SBram Moolenaar * In Visual mode, with cursor at start: move cursor back.
763ed8ce057SBram Moolenaar */
764ed8ce057SBram Moolenaar if (decl(&curwin->w_cursor) == -1)
765ed8ce057SBram Moolenaar return FAIL;
766ed8ce057SBram Moolenaar if (include != (cls() != 0))
767ed8ce057SBram Moolenaar {
768ed8ce057SBram Moolenaar if (bck_word(1L, bigword, TRUE) == FAIL)
769ed8ce057SBram Moolenaar return FAIL;
770ed8ce057SBram Moolenaar }
771ed8ce057SBram Moolenaar else
772ed8ce057SBram Moolenaar {
773ed8ce057SBram Moolenaar if (bckend_word(1L, bigword, TRUE) == FAIL)
774ed8ce057SBram Moolenaar return FAIL;
775ed8ce057SBram Moolenaar (void)incl(&curwin->w_cursor);
776ed8ce057SBram Moolenaar }
777ed8ce057SBram Moolenaar }
778ed8ce057SBram Moolenaar else
779ed8ce057SBram Moolenaar {
780ed8ce057SBram Moolenaar /*
781ed8ce057SBram Moolenaar * Move cursor forward one word and/or white area.
782ed8ce057SBram Moolenaar */
783ed8ce057SBram Moolenaar if (incl(&curwin->w_cursor) == -1)
784ed8ce057SBram Moolenaar return FAIL;
785ed8ce057SBram Moolenaar if (include != (cls() == 0))
786ed8ce057SBram Moolenaar {
787ed8ce057SBram Moolenaar if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
788ed8ce057SBram Moolenaar return FAIL;
789ed8ce057SBram Moolenaar /*
790ed8ce057SBram Moolenaar * If end is just past a new-line, we don't want to include
791ed8ce057SBram Moolenaar * the first character on the line.
792ed8ce057SBram Moolenaar * Put cursor on last char of white.
793ed8ce057SBram Moolenaar */
794ed8ce057SBram Moolenaar if (oneleft() == FAIL)
795ed8ce057SBram Moolenaar inclusive = FALSE;
796ed8ce057SBram Moolenaar }
797ed8ce057SBram Moolenaar else
798ed8ce057SBram Moolenaar {
799ed8ce057SBram Moolenaar if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
800ed8ce057SBram Moolenaar return FAIL;
801ed8ce057SBram Moolenaar }
802ed8ce057SBram Moolenaar }
803ed8ce057SBram Moolenaar --count;
804ed8ce057SBram Moolenaar }
805ed8ce057SBram Moolenaar
806ed8ce057SBram Moolenaar if (include_white && (cls() != 0
807ed8ce057SBram Moolenaar || (curwin->w_cursor.col == 0 && !inclusive)))
808ed8ce057SBram Moolenaar {
809ed8ce057SBram Moolenaar /*
810ed8ce057SBram Moolenaar * If we don't include white space at the end, move the start
811ed8ce057SBram Moolenaar * to include some white space there. This makes "daw" work
812ed8ce057SBram Moolenaar * better on the last word in a sentence (and "2daw" on last-but-one
813ed8ce057SBram Moolenaar * word). Also when "2daw" deletes "word." at the end of the line
814ed8ce057SBram Moolenaar * (cursor is at start of next line).
815ed8ce057SBram Moolenaar * But don't delete white space at start of line (indent).
816ed8ce057SBram Moolenaar */
817ed8ce057SBram Moolenaar pos = curwin->w_cursor; // save cursor position
818ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
819ed8ce057SBram Moolenaar if (oneleft() == OK)
820ed8ce057SBram Moolenaar {
821ed8ce057SBram Moolenaar back_in_line();
822ed8ce057SBram Moolenaar if (cls() == 0 && curwin->w_cursor.col > 0)
823ed8ce057SBram Moolenaar {
824ed8ce057SBram Moolenaar if (VIsual_active)
825ed8ce057SBram Moolenaar VIsual = curwin->w_cursor;
826ed8ce057SBram Moolenaar else
827ed8ce057SBram Moolenaar oap->start = curwin->w_cursor;
828ed8ce057SBram Moolenaar }
829ed8ce057SBram Moolenaar }
830ed8ce057SBram Moolenaar curwin->w_cursor = pos; // put cursor back at end
831ed8ce057SBram Moolenaar }
832ed8ce057SBram Moolenaar
833ed8ce057SBram Moolenaar if (VIsual_active)
834ed8ce057SBram Moolenaar {
835ed8ce057SBram Moolenaar if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor))
836ed8ce057SBram Moolenaar inc_cursor();
837ed8ce057SBram Moolenaar if (VIsual_mode == 'V')
838ed8ce057SBram Moolenaar {
839ed8ce057SBram Moolenaar VIsual_mode = 'v';
840ed8ce057SBram Moolenaar redraw_cmdline = TRUE; // show mode later
841ed8ce057SBram Moolenaar }
842ed8ce057SBram Moolenaar }
843ed8ce057SBram Moolenaar else
844ed8ce057SBram Moolenaar oap->inclusive = inclusive;
845ed8ce057SBram Moolenaar
846ed8ce057SBram Moolenaar return OK;
847ed8ce057SBram Moolenaar }
848ed8ce057SBram Moolenaar
849ed8ce057SBram Moolenaar /*
850ed8ce057SBram Moolenaar * Find sentence(s) under the cursor, cursor at end.
851ed8ce057SBram Moolenaar * When Visual active, extend it by one or more sentences.
852ed8ce057SBram Moolenaar */
853ed8ce057SBram Moolenaar int
current_sent(oparg_T * oap,long count,int include)854ed8ce057SBram Moolenaar current_sent(oparg_T *oap, long count, int include)
855ed8ce057SBram Moolenaar {
856ed8ce057SBram Moolenaar pos_T start_pos;
857ed8ce057SBram Moolenaar pos_T pos;
858ed8ce057SBram Moolenaar int start_blank;
859ed8ce057SBram Moolenaar int c;
860ed8ce057SBram Moolenaar int at_start_sent;
861ed8ce057SBram Moolenaar long ncount;
862ed8ce057SBram Moolenaar
863ed8ce057SBram Moolenaar start_pos = curwin->w_cursor;
864ed8ce057SBram Moolenaar pos = start_pos;
865ed8ce057SBram Moolenaar findsent(FORWARD, 1L); // Find start of next sentence.
866ed8ce057SBram Moolenaar
867ed8ce057SBram Moolenaar /*
868ed8ce057SBram Moolenaar * When the Visual area is bigger than one character: Extend it.
869ed8ce057SBram Moolenaar */
870ed8ce057SBram Moolenaar if (VIsual_active && !EQUAL_POS(start_pos, VIsual))
871ed8ce057SBram Moolenaar {
872ed8ce057SBram Moolenaar extend:
873ed8ce057SBram Moolenaar if (LT_POS(start_pos, VIsual))
874ed8ce057SBram Moolenaar {
875ed8ce057SBram Moolenaar /*
876ed8ce057SBram Moolenaar * Cursor at start of Visual area.
877ed8ce057SBram Moolenaar * Find out where we are:
878ed8ce057SBram Moolenaar * - in the white space before a sentence
879ed8ce057SBram Moolenaar * - in a sentence or just after it
880ed8ce057SBram Moolenaar * - at the start of a sentence
881ed8ce057SBram Moolenaar */
882ed8ce057SBram Moolenaar at_start_sent = TRUE;
883ed8ce057SBram Moolenaar decl(&pos);
884ed8ce057SBram Moolenaar while (LT_POS(pos, curwin->w_cursor))
885ed8ce057SBram Moolenaar {
886ed8ce057SBram Moolenaar c = gchar_pos(&pos);
887ed8ce057SBram Moolenaar if (!VIM_ISWHITE(c))
888ed8ce057SBram Moolenaar {
889ed8ce057SBram Moolenaar at_start_sent = FALSE;
890ed8ce057SBram Moolenaar break;
891ed8ce057SBram Moolenaar }
892ed8ce057SBram Moolenaar incl(&pos);
893ed8ce057SBram Moolenaar }
894ed8ce057SBram Moolenaar if (!at_start_sent)
895ed8ce057SBram Moolenaar {
896ed8ce057SBram Moolenaar findsent(BACKWARD, 1L);
897ed8ce057SBram Moolenaar if (EQUAL_POS(curwin->w_cursor, start_pos))
898ed8ce057SBram Moolenaar at_start_sent = TRUE; // exactly at start of sentence
899ed8ce057SBram Moolenaar else
900ed8ce057SBram Moolenaar // inside a sentence, go to its end (start of next)
901ed8ce057SBram Moolenaar findsent(FORWARD, 1L);
902ed8ce057SBram Moolenaar }
903ed8ce057SBram Moolenaar if (include) // "as" gets twice as much as "is"
904ed8ce057SBram Moolenaar count *= 2;
905ed8ce057SBram Moolenaar while (count--)
906ed8ce057SBram Moolenaar {
907ed8ce057SBram Moolenaar if (at_start_sent)
908ed8ce057SBram Moolenaar find_first_blank(&curwin->w_cursor);
909ed8ce057SBram Moolenaar c = gchar_cursor();
910ed8ce057SBram Moolenaar if (!at_start_sent || (!include && !VIM_ISWHITE(c)))
911ed8ce057SBram Moolenaar findsent(BACKWARD, 1L);
912ed8ce057SBram Moolenaar at_start_sent = !at_start_sent;
913ed8ce057SBram Moolenaar }
914ed8ce057SBram Moolenaar }
915ed8ce057SBram Moolenaar else
916ed8ce057SBram Moolenaar {
917ed8ce057SBram Moolenaar /*
918ed8ce057SBram Moolenaar * Cursor at end of Visual area.
919ed8ce057SBram Moolenaar * Find out where we are:
920ed8ce057SBram Moolenaar * - just before a sentence
921ed8ce057SBram Moolenaar * - just before or in the white space before a sentence
922ed8ce057SBram Moolenaar * - in a sentence
923ed8ce057SBram Moolenaar */
924ed8ce057SBram Moolenaar incl(&pos);
925ed8ce057SBram Moolenaar at_start_sent = TRUE;
926ed8ce057SBram Moolenaar // not just before a sentence
927ed8ce057SBram Moolenaar if (!EQUAL_POS(pos, curwin->w_cursor))
928ed8ce057SBram Moolenaar {
929ed8ce057SBram Moolenaar at_start_sent = FALSE;
930ed8ce057SBram Moolenaar while (LT_POS(pos, curwin->w_cursor))
931ed8ce057SBram Moolenaar {
932ed8ce057SBram Moolenaar c = gchar_pos(&pos);
933ed8ce057SBram Moolenaar if (!VIM_ISWHITE(c))
934ed8ce057SBram Moolenaar {
935ed8ce057SBram Moolenaar at_start_sent = TRUE;
936ed8ce057SBram Moolenaar break;
937ed8ce057SBram Moolenaar }
938ed8ce057SBram Moolenaar incl(&pos);
939ed8ce057SBram Moolenaar }
940ed8ce057SBram Moolenaar if (at_start_sent) // in the sentence
941ed8ce057SBram Moolenaar findsent(BACKWARD, 1L);
942ed8ce057SBram Moolenaar else // in/before white before a sentence
943ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
944ed8ce057SBram Moolenaar }
945ed8ce057SBram Moolenaar
946ed8ce057SBram Moolenaar if (include) // "as" gets twice as much as "is"
947ed8ce057SBram Moolenaar count *= 2;
948ed8ce057SBram Moolenaar findsent_forward(count, at_start_sent);
949ed8ce057SBram Moolenaar if (*p_sel == 'e')
950ed8ce057SBram Moolenaar ++curwin->w_cursor.col;
951ed8ce057SBram Moolenaar }
952ed8ce057SBram Moolenaar return OK;
953ed8ce057SBram Moolenaar }
954ed8ce057SBram Moolenaar
955ed8ce057SBram Moolenaar /*
956ed8ce057SBram Moolenaar * If the cursor started on a blank, check if it is just before the start
957ed8ce057SBram Moolenaar * of the next sentence.
958ed8ce057SBram Moolenaar */
959ed8ce057SBram Moolenaar while (c = gchar_pos(&pos), VIM_ISWHITE(c)) // VIM_ISWHITE() is a macro
960ed8ce057SBram Moolenaar incl(&pos);
961ed8ce057SBram Moolenaar if (EQUAL_POS(pos, curwin->w_cursor))
962ed8ce057SBram Moolenaar {
963ed8ce057SBram Moolenaar start_blank = TRUE;
964ed8ce057SBram Moolenaar find_first_blank(&start_pos); // go back to first blank
965ed8ce057SBram Moolenaar }
966ed8ce057SBram Moolenaar else
967ed8ce057SBram Moolenaar {
968ed8ce057SBram Moolenaar start_blank = FALSE;
969ed8ce057SBram Moolenaar findsent(BACKWARD, 1L);
970ed8ce057SBram Moolenaar start_pos = curwin->w_cursor;
971ed8ce057SBram Moolenaar }
972ed8ce057SBram Moolenaar if (include)
973ed8ce057SBram Moolenaar ncount = count * 2;
974ed8ce057SBram Moolenaar else
975ed8ce057SBram Moolenaar {
976ed8ce057SBram Moolenaar ncount = count;
977ed8ce057SBram Moolenaar if (start_blank)
978ed8ce057SBram Moolenaar --ncount;
979ed8ce057SBram Moolenaar }
980ed8ce057SBram Moolenaar if (ncount > 0)
981ed8ce057SBram Moolenaar findsent_forward(ncount, TRUE);
982ed8ce057SBram Moolenaar else
983ed8ce057SBram Moolenaar decl(&curwin->w_cursor);
984ed8ce057SBram Moolenaar
985ed8ce057SBram Moolenaar if (include)
986ed8ce057SBram Moolenaar {
987ed8ce057SBram Moolenaar /*
988ed8ce057SBram Moolenaar * If the blank in front of the sentence is included, exclude the
989ed8ce057SBram Moolenaar * blanks at the end of the sentence, go back to the first blank.
990ed8ce057SBram Moolenaar * If there are no trailing blanks, try to include leading blanks.
991ed8ce057SBram Moolenaar */
992ed8ce057SBram Moolenaar if (start_blank)
993ed8ce057SBram Moolenaar {
994ed8ce057SBram Moolenaar find_first_blank(&curwin->w_cursor);
995ed8ce057SBram Moolenaar c = gchar_pos(&curwin->w_cursor); // VIM_ISWHITE() is a macro
996ed8ce057SBram Moolenaar if (VIM_ISWHITE(c))
997ed8ce057SBram Moolenaar decl(&curwin->w_cursor);
998ed8ce057SBram Moolenaar }
999ed8ce057SBram Moolenaar else if (c = gchar_cursor(), !VIM_ISWHITE(c))
1000ed8ce057SBram Moolenaar find_first_blank(&start_pos);
1001ed8ce057SBram Moolenaar }
1002ed8ce057SBram Moolenaar
1003ed8ce057SBram Moolenaar if (VIsual_active)
1004ed8ce057SBram Moolenaar {
1005ed8ce057SBram Moolenaar // Avoid getting stuck with "is" on a single space before a sentence.
1006ed8ce057SBram Moolenaar if (EQUAL_POS(start_pos, curwin->w_cursor))
1007ed8ce057SBram Moolenaar goto extend;
1008ed8ce057SBram Moolenaar if (*p_sel == 'e')
1009ed8ce057SBram Moolenaar ++curwin->w_cursor.col;
1010ed8ce057SBram Moolenaar VIsual = start_pos;
1011ed8ce057SBram Moolenaar VIsual_mode = 'v';
1012ed8ce057SBram Moolenaar redraw_cmdline = TRUE; // show mode later
1013ed8ce057SBram Moolenaar redraw_curbuf_later(INVERTED); // update the inversion
1014ed8ce057SBram Moolenaar }
1015ed8ce057SBram Moolenaar else
1016ed8ce057SBram Moolenaar {
1017ed8ce057SBram Moolenaar // include a newline after the sentence, if there is one
1018ed8ce057SBram Moolenaar if (incl(&curwin->w_cursor) == -1)
1019ed8ce057SBram Moolenaar oap->inclusive = TRUE;
1020ed8ce057SBram Moolenaar else
1021ed8ce057SBram Moolenaar oap->inclusive = FALSE;
1022ed8ce057SBram Moolenaar oap->start = start_pos;
1023ed8ce057SBram Moolenaar oap->motion_type = MCHAR;
1024ed8ce057SBram Moolenaar }
1025ed8ce057SBram Moolenaar return OK;
1026ed8ce057SBram Moolenaar }
1027ed8ce057SBram Moolenaar
1028ed8ce057SBram Moolenaar /*
1029ed8ce057SBram Moolenaar * Find block under the cursor, cursor at end.
1030ed8ce057SBram Moolenaar * "what" and "other" are two matching parenthesis/brace/etc.
1031ed8ce057SBram Moolenaar */
1032ed8ce057SBram Moolenaar int
current_block(oparg_T * oap,long count,int include,int what,int other)1033ed8ce057SBram Moolenaar current_block(
1034ed8ce057SBram Moolenaar oparg_T *oap,
1035ed8ce057SBram Moolenaar long count,
1036ed8ce057SBram Moolenaar int include, // TRUE == include white space
1037ed8ce057SBram Moolenaar int what, // '(', '{', etc.
1038ed8ce057SBram Moolenaar int other) // ')', '}', etc.
1039ed8ce057SBram Moolenaar {
1040ed8ce057SBram Moolenaar pos_T old_pos;
1041ed8ce057SBram Moolenaar pos_T *pos = NULL;
1042ed8ce057SBram Moolenaar pos_T start_pos;
1043ed8ce057SBram Moolenaar pos_T *end_pos;
1044ed8ce057SBram Moolenaar pos_T old_start, old_end;
1045ed8ce057SBram Moolenaar char_u *save_cpo;
1046ed8ce057SBram Moolenaar int sol = FALSE; // '{' at start of line
1047ed8ce057SBram Moolenaar
1048ed8ce057SBram Moolenaar old_pos = curwin->w_cursor;
1049ed8ce057SBram Moolenaar old_end = curwin->w_cursor; // remember where we started
1050ed8ce057SBram Moolenaar old_start = old_end;
1051ed8ce057SBram Moolenaar
1052ed8ce057SBram Moolenaar /*
1053ed8ce057SBram Moolenaar * If we start on '(', '{', ')', '}', etc., use the whole block inclusive.
1054ed8ce057SBram Moolenaar */
1055ed8ce057SBram Moolenaar if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
1056ed8ce057SBram Moolenaar {
1057ed8ce057SBram Moolenaar setpcmark();
1058ed8ce057SBram Moolenaar if (what == '{') // ignore indent
1059ed8ce057SBram Moolenaar while (inindent(1))
1060ed8ce057SBram Moolenaar if (inc_cursor() != 0)
1061ed8ce057SBram Moolenaar break;
1062ed8ce057SBram Moolenaar if (gchar_cursor() == what)
1063ed8ce057SBram Moolenaar // cursor on '(' or '{', move cursor just after it
1064ed8ce057SBram Moolenaar ++curwin->w_cursor.col;
1065ed8ce057SBram Moolenaar }
1066ed8ce057SBram Moolenaar else if (LT_POS(VIsual, curwin->w_cursor))
1067ed8ce057SBram Moolenaar {
1068ed8ce057SBram Moolenaar old_start = VIsual;
1069ed8ce057SBram Moolenaar curwin->w_cursor = VIsual; // cursor at low end of Visual
1070ed8ce057SBram Moolenaar }
1071ed8ce057SBram Moolenaar else
1072ed8ce057SBram Moolenaar old_end = VIsual;
1073ed8ce057SBram Moolenaar
1074ed8ce057SBram Moolenaar /*
1075ed8ce057SBram Moolenaar * Search backwards for unclosed '(', '{', etc..
1076ed8ce057SBram Moolenaar * Put this position in start_pos.
1077ed8ce057SBram Moolenaar * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the
1078ed8ce057SBram Moolenaar * user wants.
1079ed8ce057SBram Moolenaar */
1080ed8ce057SBram Moolenaar save_cpo = p_cpo;
1081ed8ce057SBram Moolenaar p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%");
1082*b9115da4SConnor Lane Smith if ((pos = findmatch(NULL, what)) != NULL)
1083*b9115da4SConnor Lane Smith {
1084ed8ce057SBram Moolenaar while (count-- > 0)
1085ed8ce057SBram Moolenaar {
1086ed8ce057SBram Moolenaar if ((pos = findmatch(NULL, what)) == NULL)
1087ed8ce057SBram Moolenaar break;
1088ed8ce057SBram Moolenaar curwin->w_cursor = *pos;
1089ed8ce057SBram Moolenaar start_pos = *pos; // the findmatch for end_pos will overwrite *pos
1090ed8ce057SBram Moolenaar }
1091*b9115da4SConnor Lane Smith }
1092*b9115da4SConnor Lane Smith else
1093*b9115da4SConnor Lane Smith {
1094*b9115da4SConnor Lane Smith while (count-- > 0)
1095*b9115da4SConnor Lane Smith {
1096*b9115da4SConnor Lane Smith if ((pos = findmatchlimit(NULL, what, FM_FORWARD, 0)) == NULL)
1097*b9115da4SConnor Lane Smith break;
1098*b9115da4SConnor Lane Smith curwin->w_cursor = *pos;
1099*b9115da4SConnor Lane Smith start_pos = *pos; // the findmatch for end_pos will overwrite *pos
1100*b9115da4SConnor Lane Smith }
1101*b9115da4SConnor Lane Smith }
1102ed8ce057SBram Moolenaar p_cpo = save_cpo;
1103ed8ce057SBram Moolenaar
1104ed8ce057SBram Moolenaar /*
1105ed8ce057SBram Moolenaar * Search for matching ')', '}', etc.
1106ed8ce057SBram Moolenaar * Put this position in curwin->w_cursor.
1107ed8ce057SBram Moolenaar */
1108ed8ce057SBram Moolenaar if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
1109ed8ce057SBram Moolenaar {
1110ed8ce057SBram Moolenaar curwin->w_cursor = old_pos;
1111ed8ce057SBram Moolenaar return FAIL;
1112ed8ce057SBram Moolenaar }
1113ed8ce057SBram Moolenaar curwin->w_cursor = *end_pos;
1114ed8ce057SBram Moolenaar
1115ed8ce057SBram Moolenaar /*
1116ed8ce057SBram Moolenaar * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE.
1117ed8ce057SBram Moolenaar * If the ending '}', ')' or ']' is only preceded by indent, skip that
1118ed8ce057SBram Moolenaar * indent. But only if the resulting area is not smaller than what we
1119ed8ce057SBram Moolenaar * started with.
1120ed8ce057SBram Moolenaar */
1121ed8ce057SBram Moolenaar while (!include)
1122ed8ce057SBram Moolenaar {
1123ed8ce057SBram Moolenaar incl(&start_pos);
1124ed8ce057SBram Moolenaar sol = (curwin->w_cursor.col == 0);
1125ed8ce057SBram Moolenaar decl(&curwin->w_cursor);
1126ed8ce057SBram Moolenaar while (inindent(1))
1127ed8ce057SBram Moolenaar {
1128ed8ce057SBram Moolenaar sol = TRUE;
1129ed8ce057SBram Moolenaar if (decl(&curwin->w_cursor) != 0)
1130ed8ce057SBram Moolenaar break;
1131ed8ce057SBram Moolenaar }
1132ed8ce057SBram Moolenaar
1133ed8ce057SBram Moolenaar /*
1134ed8ce057SBram Moolenaar * In Visual mode, when the resulting area is not bigger than what we
1135ed8ce057SBram Moolenaar * started with, extend it to the next block, and then exclude again.
1136ed8ce057SBram Moolenaar */
1137ed8ce057SBram Moolenaar if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor)
1138ed8ce057SBram Moolenaar && VIsual_active)
1139ed8ce057SBram Moolenaar {
1140ed8ce057SBram Moolenaar curwin->w_cursor = old_start;
1141ed8ce057SBram Moolenaar decl(&curwin->w_cursor);
1142ed8ce057SBram Moolenaar if ((pos = findmatch(NULL, what)) == NULL)
1143ed8ce057SBram Moolenaar {
1144ed8ce057SBram Moolenaar curwin->w_cursor = old_pos;
1145ed8ce057SBram Moolenaar return FAIL;
1146ed8ce057SBram Moolenaar }
1147ed8ce057SBram Moolenaar start_pos = *pos;
1148ed8ce057SBram Moolenaar curwin->w_cursor = *pos;
1149ed8ce057SBram Moolenaar if ((end_pos = findmatch(NULL, other)) == NULL)
1150ed8ce057SBram Moolenaar {
1151ed8ce057SBram Moolenaar curwin->w_cursor = old_pos;
1152ed8ce057SBram Moolenaar return FAIL;
1153ed8ce057SBram Moolenaar }
1154ed8ce057SBram Moolenaar curwin->w_cursor = *end_pos;
1155ed8ce057SBram Moolenaar }
1156ed8ce057SBram Moolenaar else
1157ed8ce057SBram Moolenaar break;
1158ed8ce057SBram Moolenaar }
1159ed8ce057SBram Moolenaar
1160ed8ce057SBram Moolenaar if (VIsual_active)
1161ed8ce057SBram Moolenaar {
1162ed8ce057SBram Moolenaar if (*p_sel == 'e')
1163ed8ce057SBram Moolenaar inc(&curwin->w_cursor);
1164ed8ce057SBram Moolenaar if (sol && gchar_cursor() != NUL)
1165ed8ce057SBram Moolenaar inc(&curwin->w_cursor); // include the line break
1166ed8ce057SBram Moolenaar VIsual = start_pos;
1167ed8ce057SBram Moolenaar VIsual_mode = 'v';
1168ed8ce057SBram Moolenaar redraw_curbuf_later(INVERTED); // update the inversion
1169ed8ce057SBram Moolenaar showmode();
1170ed8ce057SBram Moolenaar }
1171ed8ce057SBram Moolenaar else
1172ed8ce057SBram Moolenaar {
1173ed8ce057SBram Moolenaar oap->start = start_pos;
1174ed8ce057SBram Moolenaar oap->motion_type = MCHAR;
1175ed8ce057SBram Moolenaar oap->inclusive = FALSE;
1176ed8ce057SBram Moolenaar if (sol)
1177ed8ce057SBram Moolenaar incl(&curwin->w_cursor);
1178ed8ce057SBram Moolenaar else if (LTOREQ_POS(start_pos, curwin->w_cursor))
1179ed8ce057SBram Moolenaar // Include the character under the cursor.
1180ed8ce057SBram Moolenaar oap->inclusive = TRUE;
1181ed8ce057SBram Moolenaar else
1182ed8ce057SBram Moolenaar // End is before the start (no text in between <>, [], etc.): don't
1183ed8ce057SBram Moolenaar // operate on any text.
1184ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
1185ed8ce057SBram Moolenaar }
1186ed8ce057SBram Moolenaar
1187ed8ce057SBram Moolenaar return OK;
1188ed8ce057SBram Moolenaar }
1189ed8ce057SBram Moolenaar
1190ed8ce057SBram Moolenaar /*
1191ed8ce057SBram Moolenaar * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>".
1192ed8ce057SBram Moolenaar * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>".
1193ed8ce057SBram Moolenaar */
1194ed8ce057SBram Moolenaar static int
in_html_tag(int end_tag)1195ed8ce057SBram Moolenaar in_html_tag(
1196ed8ce057SBram Moolenaar int end_tag)
1197ed8ce057SBram Moolenaar {
1198ed8ce057SBram Moolenaar char_u *line = ml_get_curline();
1199ed8ce057SBram Moolenaar char_u *p;
1200ed8ce057SBram Moolenaar int c;
1201ed8ce057SBram Moolenaar int lc = NUL;
1202ed8ce057SBram Moolenaar pos_T pos;
1203ed8ce057SBram Moolenaar
1204ed8ce057SBram Moolenaar if (enc_dbcs)
1205ed8ce057SBram Moolenaar {
1206ed8ce057SBram Moolenaar char_u *lp = NULL;
1207ed8ce057SBram Moolenaar
1208ed8ce057SBram Moolenaar // We search forward until the cursor, because searching backwards is
1209ed8ce057SBram Moolenaar // very slow for DBCS encodings.
1210ed8ce057SBram Moolenaar for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p))
1211ed8ce057SBram Moolenaar if (*p == '>' || *p == '<')
1212ed8ce057SBram Moolenaar {
1213ed8ce057SBram Moolenaar lc = *p;
1214ed8ce057SBram Moolenaar lp = p;
1215ed8ce057SBram Moolenaar }
1216ed8ce057SBram Moolenaar if (*p != '<') // check for '<' under cursor
1217ed8ce057SBram Moolenaar {
1218ed8ce057SBram Moolenaar if (lc != '<')
1219ed8ce057SBram Moolenaar return FALSE;
1220ed8ce057SBram Moolenaar p = lp;
1221ed8ce057SBram Moolenaar }
1222ed8ce057SBram Moolenaar }
1223ed8ce057SBram Moolenaar else
1224ed8ce057SBram Moolenaar {
1225ed8ce057SBram Moolenaar for (p = line + curwin->w_cursor.col; p > line; )
1226ed8ce057SBram Moolenaar {
1227ed8ce057SBram Moolenaar if (*p == '<') // find '<' under/before cursor
1228ed8ce057SBram Moolenaar break;
1229ed8ce057SBram Moolenaar MB_PTR_BACK(line, p);
1230ed8ce057SBram Moolenaar if (*p == '>') // find '>' before cursor
1231ed8ce057SBram Moolenaar break;
1232ed8ce057SBram Moolenaar }
1233ed8ce057SBram Moolenaar if (*p != '<')
1234ed8ce057SBram Moolenaar return FALSE;
1235ed8ce057SBram Moolenaar }
1236ed8ce057SBram Moolenaar
1237ed8ce057SBram Moolenaar pos.lnum = curwin->w_cursor.lnum;
1238ed8ce057SBram Moolenaar pos.col = (colnr_T)(p - line);
1239ed8ce057SBram Moolenaar
1240ed8ce057SBram Moolenaar MB_PTR_ADV(p);
1241ed8ce057SBram Moolenaar if (end_tag)
1242ed8ce057SBram Moolenaar // check that there is a '/' after the '<'
1243ed8ce057SBram Moolenaar return *p == '/';
1244ed8ce057SBram Moolenaar
1245ed8ce057SBram Moolenaar // check that there is no '/' after the '<'
1246ed8ce057SBram Moolenaar if (*p == '/')
1247ed8ce057SBram Moolenaar return FALSE;
1248ed8ce057SBram Moolenaar
1249ed8ce057SBram Moolenaar // check that the matching '>' is not preceded by '/'
1250ed8ce057SBram Moolenaar for (;;)
1251ed8ce057SBram Moolenaar {
1252ed8ce057SBram Moolenaar if (inc(&pos) < 0)
1253ed8ce057SBram Moolenaar return FALSE;
1254ed8ce057SBram Moolenaar c = *ml_get_pos(&pos);
1255ed8ce057SBram Moolenaar if (c == '>')
1256ed8ce057SBram Moolenaar break;
1257ed8ce057SBram Moolenaar lc = c;
1258ed8ce057SBram Moolenaar }
1259ed8ce057SBram Moolenaar return lc != '/';
1260ed8ce057SBram Moolenaar }
1261ed8ce057SBram Moolenaar
1262ed8ce057SBram Moolenaar /*
1263ed8ce057SBram Moolenaar * Find tag block under the cursor, cursor at end.
1264ed8ce057SBram Moolenaar */
1265ed8ce057SBram Moolenaar int
current_tagblock(oparg_T * oap,long count_arg,int include)1266ed8ce057SBram Moolenaar current_tagblock(
1267ed8ce057SBram Moolenaar oparg_T *oap,
1268ed8ce057SBram Moolenaar long count_arg,
1269ed8ce057SBram Moolenaar int include) // TRUE == include white space
1270ed8ce057SBram Moolenaar {
1271ed8ce057SBram Moolenaar long count = count_arg;
1272ed8ce057SBram Moolenaar long n;
1273ed8ce057SBram Moolenaar pos_T old_pos;
1274ed8ce057SBram Moolenaar pos_T start_pos;
1275ed8ce057SBram Moolenaar pos_T end_pos;
1276ed8ce057SBram Moolenaar pos_T old_start, old_end;
1277ed8ce057SBram Moolenaar char_u *spat, *epat;
1278ed8ce057SBram Moolenaar char_u *p;
1279ed8ce057SBram Moolenaar char_u *cp;
1280ed8ce057SBram Moolenaar int len;
1281ed8ce057SBram Moolenaar int r;
1282ed8ce057SBram Moolenaar int do_include = include;
1283ed8ce057SBram Moolenaar int save_p_ws = p_ws;
1284ed8ce057SBram Moolenaar int retval = FAIL;
1285ed8ce057SBram Moolenaar int is_inclusive = TRUE;
1286ed8ce057SBram Moolenaar
1287ed8ce057SBram Moolenaar p_ws = FALSE;
1288ed8ce057SBram Moolenaar
1289ed8ce057SBram Moolenaar old_pos = curwin->w_cursor;
1290ed8ce057SBram Moolenaar old_end = curwin->w_cursor; // remember where we started
1291ed8ce057SBram Moolenaar old_start = old_end;
1292ed8ce057SBram Moolenaar if (!VIsual_active || *p_sel == 'e')
1293ed8ce057SBram Moolenaar decl(&old_end); // old_end is inclusive
1294ed8ce057SBram Moolenaar
1295ed8ce057SBram Moolenaar /*
1296ed8ce057SBram Moolenaar * If we start on "<aaa>" select that block.
1297ed8ce057SBram Moolenaar */
1298ed8ce057SBram Moolenaar if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
1299ed8ce057SBram Moolenaar {
1300ed8ce057SBram Moolenaar setpcmark();
1301ed8ce057SBram Moolenaar
1302ed8ce057SBram Moolenaar // ignore indent
1303ed8ce057SBram Moolenaar while (inindent(1))
1304ed8ce057SBram Moolenaar if (inc_cursor() != 0)
1305ed8ce057SBram Moolenaar break;
1306ed8ce057SBram Moolenaar
1307ed8ce057SBram Moolenaar if (in_html_tag(FALSE))
1308ed8ce057SBram Moolenaar {
1309ed8ce057SBram Moolenaar // cursor on start tag, move to its '>'
1310ed8ce057SBram Moolenaar while (*ml_get_cursor() != '>')
1311ed8ce057SBram Moolenaar if (inc_cursor() < 0)
1312ed8ce057SBram Moolenaar break;
1313ed8ce057SBram Moolenaar }
1314ed8ce057SBram Moolenaar else if (in_html_tag(TRUE))
1315ed8ce057SBram Moolenaar {
1316ed8ce057SBram Moolenaar // cursor on end tag, move to just before it
1317ed8ce057SBram Moolenaar while (*ml_get_cursor() != '<')
1318ed8ce057SBram Moolenaar if (dec_cursor() < 0)
1319ed8ce057SBram Moolenaar break;
1320ed8ce057SBram Moolenaar dec_cursor();
1321ed8ce057SBram Moolenaar old_end = curwin->w_cursor;
1322ed8ce057SBram Moolenaar }
1323ed8ce057SBram Moolenaar }
1324ed8ce057SBram Moolenaar else if (LT_POS(VIsual, curwin->w_cursor))
1325ed8ce057SBram Moolenaar {
1326ed8ce057SBram Moolenaar old_start = VIsual;
1327ed8ce057SBram Moolenaar curwin->w_cursor = VIsual; // cursor at low end of Visual
1328ed8ce057SBram Moolenaar }
1329ed8ce057SBram Moolenaar else
1330ed8ce057SBram Moolenaar old_end = VIsual;
1331ed8ce057SBram Moolenaar
1332ed8ce057SBram Moolenaar again:
1333ed8ce057SBram Moolenaar /*
1334ed8ce057SBram Moolenaar * Search backwards for unclosed "<aaa>".
1335ed8ce057SBram Moolenaar * Put this position in start_pos.
1336ed8ce057SBram Moolenaar */
1337ed8ce057SBram Moolenaar for (n = 0; n < count; ++n)
1338ed8ce057SBram Moolenaar {
1339ed8ce057SBram Moolenaar if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
1340ed8ce057SBram Moolenaar (char_u *)"",
1341ed8ce057SBram Moolenaar (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
1342ed8ce057SBram Moolenaar NULL, (linenr_T)0, 0L) <= 0)
1343ed8ce057SBram Moolenaar {
1344ed8ce057SBram Moolenaar curwin->w_cursor = old_pos;
1345ed8ce057SBram Moolenaar goto theend;
1346ed8ce057SBram Moolenaar }
1347ed8ce057SBram Moolenaar }
1348ed8ce057SBram Moolenaar start_pos = curwin->w_cursor;
1349ed8ce057SBram Moolenaar
1350ed8ce057SBram Moolenaar /*
1351ed8ce057SBram Moolenaar * Search for matching "</aaa>". First isolate the "aaa".
1352ed8ce057SBram Moolenaar */
1353ed8ce057SBram Moolenaar inc_cursor();
1354ed8ce057SBram Moolenaar p = ml_get_cursor();
1355ed8ce057SBram Moolenaar for (cp = p; *cp != NUL && *cp != '>' && !VIM_ISWHITE(*cp); MB_PTR_ADV(cp))
1356ed8ce057SBram Moolenaar ;
1357ed8ce057SBram Moolenaar len = (int)(cp - p);
1358ed8ce057SBram Moolenaar if (len == 0)
1359ed8ce057SBram Moolenaar {
1360ed8ce057SBram Moolenaar curwin->w_cursor = old_pos;
1361ed8ce057SBram Moolenaar goto theend;
1362ed8ce057SBram Moolenaar }
1363a604ccc9SBram Moolenaar spat = alloc(len + 39);
1364ed8ce057SBram Moolenaar epat = alloc(len + 9);
1365ed8ce057SBram Moolenaar if (spat == NULL || epat == NULL)
1366ed8ce057SBram Moolenaar {
1367ed8ce057SBram Moolenaar vim_free(spat);
1368ed8ce057SBram Moolenaar vim_free(epat);
1369ed8ce057SBram Moolenaar curwin->w_cursor = old_pos;
1370ed8ce057SBram Moolenaar goto theend;
1371ed8ce057SBram Moolenaar }
1372a604ccc9SBram Moolenaar sprintf((char *)spat, "<%.*s\\>\\%%(\\_s\\_[^>]\\{-}\\_[^/]>\\|\\_s\\?>\\)\\c", len, p);
1373ed8ce057SBram Moolenaar sprintf((char *)epat, "</%.*s>\\c", len, p);
1374ed8ce057SBram Moolenaar
1375ed8ce057SBram Moolenaar r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
1376ed8ce057SBram Moolenaar 0, NULL, (linenr_T)0, 0L);
1377ed8ce057SBram Moolenaar
1378ed8ce057SBram Moolenaar vim_free(spat);
1379ed8ce057SBram Moolenaar vim_free(epat);
1380ed8ce057SBram Moolenaar
1381ed8ce057SBram Moolenaar if (r < 1 || LT_POS(curwin->w_cursor, old_end))
1382ed8ce057SBram Moolenaar {
1383ed8ce057SBram Moolenaar // Can't find other end or it's before the previous end. Could be a
1384ed8ce057SBram Moolenaar // HTML tag that doesn't have a matching end. Search backwards for
1385ed8ce057SBram Moolenaar // another starting tag.
1386ed8ce057SBram Moolenaar count = 1;
1387ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
1388ed8ce057SBram Moolenaar goto again;
1389ed8ce057SBram Moolenaar }
1390ed8ce057SBram Moolenaar
1391ed8ce057SBram Moolenaar if (do_include)
1392ed8ce057SBram Moolenaar {
1393ed8ce057SBram Moolenaar // Include up to the '>'.
1394ed8ce057SBram Moolenaar while (*ml_get_cursor() != '>')
1395ed8ce057SBram Moolenaar if (inc_cursor() < 0)
1396ed8ce057SBram Moolenaar break;
1397ed8ce057SBram Moolenaar }
1398ed8ce057SBram Moolenaar else
1399ed8ce057SBram Moolenaar {
1400ed8ce057SBram Moolenaar char_u *c = ml_get_cursor();
1401ed8ce057SBram Moolenaar
1402ed8ce057SBram Moolenaar // Exclude the '<' of the end tag.
1403ed8ce057SBram Moolenaar // If the closing tag is on new line, do not decrement cursor, but
1404ed8ce057SBram Moolenaar // make operation exclusive, so that the linefeed will be selected
1405ed8ce057SBram Moolenaar if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0)
1406ed8ce057SBram Moolenaar // do not decrement cursor
1407ed8ce057SBram Moolenaar is_inclusive = FALSE;
1408ed8ce057SBram Moolenaar else if (*c == '<')
1409ed8ce057SBram Moolenaar dec_cursor();
1410ed8ce057SBram Moolenaar }
1411ed8ce057SBram Moolenaar end_pos = curwin->w_cursor;
1412ed8ce057SBram Moolenaar
1413ed8ce057SBram Moolenaar if (!do_include)
1414ed8ce057SBram Moolenaar {
1415ed8ce057SBram Moolenaar // Exclude the start tag.
1416ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
1417ed8ce057SBram Moolenaar while (inc_cursor() >= 0)
1418ed8ce057SBram Moolenaar if (*ml_get_cursor() == '>')
1419ed8ce057SBram Moolenaar {
1420ed8ce057SBram Moolenaar inc_cursor();
1421ed8ce057SBram Moolenaar start_pos = curwin->w_cursor;
1422ed8ce057SBram Moolenaar break;
1423ed8ce057SBram Moolenaar }
1424ed8ce057SBram Moolenaar curwin->w_cursor = end_pos;
1425ed8ce057SBram Moolenaar
1426ed8ce057SBram Moolenaar // If we are in Visual mode and now have the same text as before set
1427ed8ce057SBram Moolenaar // "do_include" and try again.
1428ed8ce057SBram Moolenaar if (VIsual_active && EQUAL_POS(start_pos, old_start)
1429ed8ce057SBram Moolenaar && EQUAL_POS(end_pos, old_end))
1430ed8ce057SBram Moolenaar {
1431ed8ce057SBram Moolenaar do_include = TRUE;
1432ed8ce057SBram Moolenaar curwin->w_cursor = old_start;
1433ed8ce057SBram Moolenaar count = count_arg;
1434ed8ce057SBram Moolenaar goto again;
1435ed8ce057SBram Moolenaar }
1436ed8ce057SBram Moolenaar }
1437ed8ce057SBram Moolenaar
1438ed8ce057SBram Moolenaar if (VIsual_active)
1439ed8ce057SBram Moolenaar {
1440ed8ce057SBram Moolenaar // If the end is before the start there is no text between tags, select
1441ed8ce057SBram Moolenaar // the char under the cursor.
1442ed8ce057SBram Moolenaar if (LT_POS(end_pos, start_pos))
1443ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
1444ed8ce057SBram Moolenaar else if (*p_sel == 'e')
1445ed8ce057SBram Moolenaar inc_cursor();
1446ed8ce057SBram Moolenaar VIsual = start_pos;
1447ed8ce057SBram Moolenaar VIsual_mode = 'v';
1448ed8ce057SBram Moolenaar redraw_curbuf_later(INVERTED); // update the inversion
1449ed8ce057SBram Moolenaar showmode();
1450ed8ce057SBram Moolenaar }
1451ed8ce057SBram Moolenaar else
1452ed8ce057SBram Moolenaar {
1453ed8ce057SBram Moolenaar oap->start = start_pos;
1454ed8ce057SBram Moolenaar oap->motion_type = MCHAR;
1455ed8ce057SBram Moolenaar if (LT_POS(end_pos, start_pos))
1456ed8ce057SBram Moolenaar {
1457ed8ce057SBram Moolenaar // End is before the start: there is no text between tags; operate
1458ed8ce057SBram Moolenaar // on an empty area.
1459ed8ce057SBram Moolenaar curwin->w_cursor = start_pos;
1460ed8ce057SBram Moolenaar oap->inclusive = FALSE;
1461ed8ce057SBram Moolenaar }
1462ed8ce057SBram Moolenaar else
1463ed8ce057SBram Moolenaar oap->inclusive = is_inclusive;
1464ed8ce057SBram Moolenaar }
1465ed8ce057SBram Moolenaar retval = OK;
1466ed8ce057SBram Moolenaar
1467ed8ce057SBram Moolenaar theend:
1468ed8ce057SBram Moolenaar p_ws = save_p_ws;
1469ed8ce057SBram Moolenaar return retval;
1470ed8ce057SBram Moolenaar }
1471ed8ce057SBram Moolenaar
1472ed8ce057SBram Moolenaar int
current_par(oparg_T * oap,long count,int include,int type)1473ed8ce057SBram Moolenaar current_par(
1474ed8ce057SBram Moolenaar oparg_T *oap,
1475ed8ce057SBram Moolenaar long count,
1476ed8ce057SBram Moolenaar int include, // TRUE == include white space
1477ed8ce057SBram Moolenaar int type) // 'p' for paragraph, 'S' for section
1478ed8ce057SBram Moolenaar {
1479ed8ce057SBram Moolenaar linenr_T start_lnum;
1480ed8ce057SBram Moolenaar linenr_T end_lnum;
1481ed8ce057SBram Moolenaar int white_in_front;
1482ed8ce057SBram Moolenaar int dir;
1483ed8ce057SBram Moolenaar int start_is_white;
1484ed8ce057SBram Moolenaar int prev_start_is_white;
1485ed8ce057SBram Moolenaar int retval = OK;
1486ed8ce057SBram Moolenaar int do_white = FALSE;
1487ed8ce057SBram Moolenaar int t;
1488ed8ce057SBram Moolenaar int i;
1489ed8ce057SBram Moolenaar
1490ed8ce057SBram Moolenaar if (type == 'S') // not implemented yet
1491ed8ce057SBram Moolenaar return FAIL;
1492ed8ce057SBram Moolenaar
1493ed8ce057SBram Moolenaar start_lnum = curwin->w_cursor.lnum;
1494ed8ce057SBram Moolenaar
1495ed8ce057SBram Moolenaar /*
1496ed8ce057SBram Moolenaar * When visual area is more than one line: extend it.
1497ed8ce057SBram Moolenaar */
1498ed8ce057SBram Moolenaar if (VIsual_active && start_lnum != VIsual.lnum)
1499ed8ce057SBram Moolenaar {
1500ed8ce057SBram Moolenaar extend:
1501ed8ce057SBram Moolenaar if (start_lnum < VIsual.lnum)
1502ed8ce057SBram Moolenaar dir = BACKWARD;
1503ed8ce057SBram Moolenaar else
1504ed8ce057SBram Moolenaar dir = FORWARD;
1505ed8ce057SBram Moolenaar for (i = count; --i >= 0; )
1506ed8ce057SBram Moolenaar {
1507ed8ce057SBram Moolenaar if (start_lnum ==
1508ed8ce057SBram Moolenaar (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
1509ed8ce057SBram Moolenaar {
1510ed8ce057SBram Moolenaar retval = FAIL;
1511ed8ce057SBram Moolenaar break;
1512ed8ce057SBram Moolenaar }
1513ed8ce057SBram Moolenaar
1514ed8ce057SBram Moolenaar prev_start_is_white = -1;
1515ed8ce057SBram Moolenaar for (t = 0; t < 2; ++t)
1516ed8ce057SBram Moolenaar {
1517ed8ce057SBram Moolenaar start_lnum += dir;
1518ed8ce057SBram Moolenaar start_is_white = linewhite(start_lnum);
1519ed8ce057SBram Moolenaar if (prev_start_is_white == start_is_white)
1520ed8ce057SBram Moolenaar {
1521ed8ce057SBram Moolenaar start_lnum -= dir;
1522ed8ce057SBram Moolenaar break;
1523ed8ce057SBram Moolenaar }
1524ed8ce057SBram Moolenaar for (;;)
1525ed8ce057SBram Moolenaar {
1526ed8ce057SBram Moolenaar if (start_lnum == (dir == BACKWARD
1527ed8ce057SBram Moolenaar ? 1 : curbuf->b_ml.ml_line_count))
1528ed8ce057SBram Moolenaar break;
1529ed8ce057SBram Moolenaar if (start_is_white != linewhite(start_lnum + dir)
1530ed8ce057SBram Moolenaar || (!start_is_white
1531ed8ce057SBram Moolenaar && startPS(start_lnum + (dir > 0
1532ed8ce057SBram Moolenaar ? 1 : 0), 0, 0)))
1533ed8ce057SBram Moolenaar break;
1534ed8ce057SBram Moolenaar start_lnum += dir;
1535ed8ce057SBram Moolenaar }
1536ed8ce057SBram Moolenaar if (!include)
1537ed8ce057SBram Moolenaar break;
1538ed8ce057SBram Moolenaar if (start_lnum == (dir == BACKWARD
1539ed8ce057SBram Moolenaar ? 1 : curbuf->b_ml.ml_line_count))
1540ed8ce057SBram Moolenaar break;
1541ed8ce057SBram Moolenaar prev_start_is_white = start_is_white;
1542ed8ce057SBram Moolenaar }
1543ed8ce057SBram Moolenaar }
1544ed8ce057SBram Moolenaar curwin->w_cursor.lnum = start_lnum;
1545ed8ce057SBram Moolenaar curwin->w_cursor.col = 0;
1546ed8ce057SBram Moolenaar return retval;
1547ed8ce057SBram Moolenaar }
1548ed8ce057SBram Moolenaar
1549ed8ce057SBram Moolenaar /*
1550ed8ce057SBram Moolenaar * First move back to the start_lnum of the paragraph or white lines
1551ed8ce057SBram Moolenaar */
1552ed8ce057SBram Moolenaar white_in_front = linewhite(start_lnum);
1553ed8ce057SBram Moolenaar while (start_lnum > 1)
1554ed8ce057SBram Moolenaar {
1555ed8ce057SBram Moolenaar if (white_in_front) // stop at first white line
1556ed8ce057SBram Moolenaar {
1557ed8ce057SBram Moolenaar if (!linewhite(start_lnum - 1))
1558ed8ce057SBram Moolenaar break;
1559ed8ce057SBram Moolenaar }
1560ed8ce057SBram Moolenaar else // stop at first non-white line of start of paragraph
1561ed8ce057SBram Moolenaar {
1562ed8ce057SBram Moolenaar if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0))
1563ed8ce057SBram Moolenaar break;
1564ed8ce057SBram Moolenaar }
1565ed8ce057SBram Moolenaar --start_lnum;
1566ed8ce057SBram Moolenaar }
1567ed8ce057SBram Moolenaar
1568ed8ce057SBram Moolenaar /*
1569ed8ce057SBram Moolenaar * Move past the end of any white lines.
1570ed8ce057SBram Moolenaar */
1571ed8ce057SBram Moolenaar end_lnum = start_lnum;
1572ed8ce057SBram Moolenaar while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum))
1573ed8ce057SBram Moolenaar ++end_lnum;
1574ed8ce057SBram Moolenaar
1575ed8ce057SBram Moolenaar --end_lnum;
1576ed8ce057SBram Moolenaar i = count;
1577ed8ce057SBram Moolenaar if (!include && white_in_front)
1578ed8ce057SBram Moolenaar --i;
1579ed8ce057SBram Moolenaar while (i--)
1580ed8ce057SBram Moolenaar {
1581ed8ce057SBram Moolenaar if (end_lnum == curbuf->b_ml.ml_line_count)
1582ed8ce057SBram Moolenaar return FAIL;
1583ed8ce057SBram Moolenaar
1584ed8ce057SBram Moolenaar if (!include)
1585ed8ce057SBram Moolenaar do_white = linewhite(end_lnum + 1);
1586ed8ce057SBram Moolenaar
1587ed8ce057SBram Moolenaar if (include || !do_white)
1588ed8ce057SBram Moolenaar {
1589ed8ce057SBram Moolenaar ++end_lnum;
1590ed8ce057SBram Moolenaar /*
1591ed8ce057SBram Moolenaar * skip to end of paragraph
1592ed8ce057SBram Moolenaar */
1593ed8ce057SBram Moolenaar while (end_lnum < curbuf->b_ml.ml_line_count
1594ed8ce057SBram Moolenaar && !linewhite(end_lnum + 1)
1595ed8ce057SBram Moolenaar && !startPS(end_lnum + 1, 0, 0))
1596ed8ce057SBram Moolenaar ++end_lnum;
1597ed8ce057SBram Moolenaar }
1598ed8ce057SBram Moolenaar
1599ed8ce057SBram Moolenaar if (i == 0 && white_in_front && include)
1600ed8ce057SBram Moolenaar break;
1601ed8ce057SBram Moolenaar
1602ed8ce057SBram Moolenaar /*
1603ed8ce057SBram Moolenaar * skip to end of white lines after paragraph
1604ed8ce057SBram Moolenaar */
1605ed8ce057SBram Moolenaar if (include || do_white)
1606ed8ce057SBram Moolenaar while (end_lnum < curbuf->b_ml.ml_line_count
1607ed8ce057SBram Moolenaar && linewhite(end_lnum + 1))
1608ed8ce057SBram Moolenaar ++end_lnum;
1609ed8ce057SBram Moolenaar }
1610ed8ce057SBram Moolenaar
1611ed8ce057SBram Moolenaar /*
1612ed8ce057SBram Moolenaar * If there are no empty lines at the end, try to find some empty lines at
1613ed8ce057SBram Moolenaar * the start (unless that has been done already).
1614ed8ce057SBram Moolenaar */
1615ed8ce057SBram Moolenaar if (!white_in_front && !linewhite(end_lnum) && include)
1616ed8ce057SBram Moolenaar while (start_lnum > 1 && linewhite(start_lnum - 1))
1617ed8ce057SBram Moolenaar --start_lnum;
1618ed8ce057SBram Moolenaar
1619ed8ce057SBram Moolenaar if (VIsual_active)
1620ed8ce057SBram Moolenaar {
1621ed8ce057SBram Moolenaar // Problem: when doing "Vipipip" nothing happens in a single white
1622ed8ce057SBram Moolenaar // line, we get stuck there. Trap this here.
1623ed8ce057SBram Moolenaar if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
1624ed8ce057SBram Moolenaar goto extend;
1625ed8ce057SBram Moolenaar if (VIsual.lnum != start_lnum)
1626ed8ce057SBram Moolenaar {
1627ed8ce057SBram Moolenaar VIsual.lnum = start_lnum;
1628ed8ce057SBram Moolenaar VIsual.col = 0;
1629ed8ce057SBram Moolenaar }
1630ed8ce057SBram Moolenaar VIsual_mode = 'V';
1631ed8ce057SBram Moolenaar redraw_curbuf_later(INVERTED); // update the inversion
1632ed8ce057SBram Moolenaar showmode();
1633ed8ce057SBram Moolenaar }
1634ed8ce057SBram Moolenaar else
1635ed8ce057SBram Moolenaar {
1636ed8ce057SBram Moolenaar oap->start.lnum = start_lnum;
1637ed8ce057SBram Moolenaar oap->start.col = 0;
1638ed8ce057SBram Moolenaar oap->motion_type = MLINE;
1639ed8ce057SBram Moolenaar }
1640ed8ce057SBram Moolenaar curwin->w_cursor.lnum = end_lnum;
1641ed8ce057SBram Moolenaar curwin->w_cursor.col = 0;
1642ed8ce057SBram Moolenaar
1643ed8ce057SBram Moolenaar return OK;
1644ed8ce057SBram Moolenaar }
1645ed8ce057SBram Moolenaar
1646ed8ce057SBram Moolenaar /*
1647ed8ce057SBram Moolenaar * Search quote char from string line[col].
1648ed8ce057SBram Moolenaar * Quote character escaped by one of the characters in "escape" is not counted
1649ed8ce057SBram Moolenaar * as a quote.
1650ed8ce057SBram Moolenaar * Returns column number of "quotechar" or -1 when not found.
1651ed8ce057SBram Moolenaar */
1652ed8ce057SBram Moolenaar static int
find_next_quote(char_u * line,int col,int quotechar,char_u * escape)1653ed8ce057SBram Moolenaar find_next_quote(
1654ed8ce057SBram Moolenaar char_u *line,
1655ed8ce057SBram Moolenaar int col,
1656ed8ce057SBram Moolenaar int quotechar,
1657ed8ce057SBram Moolenaar char_u *escape) // escape characters, can be NULL
1658ed8ce057SBram Moolenaar {
1659ed8ce057SBram Moolenaar int c;
1660ed8ce057SBram Moolenaar
1661ed8ce057SBram Moolenaar for (;;)
1662ed8ce057SBram Moolenaar {
1663ed8ce057SBram Moolenaar c = line[col];
1664ed8ce057SBram Moolenaar if (c == NUL)
1665ed8ce057SBram Moolenaar return -1;
1666ed8ce057SBram Moolenaar else if (escape != NULL && vim_strchr(escape, c))
1667ed8ce057SBram Moolenaar ++col;
1668ed8ce057SBram Moolenaar else if (c == quotechar)
1669ed8ce057SBram Moolenaar break;
1670ed8ce057SBram Moolenaar if (has_mbyte)
1671ed8ce057SBram Moolenaar col += (*mb_ptr2len)(line + col);
1672ed8ce057SBram Moolenaar else
1673ed8ce057SBram Moolenaar ++col;
1674ed8ce057SBram Moolenaar }
1675ed8ce057SBram Moolenaar return col;
1676ed8ce057SBram Moolenaar }
1677ed8ce057SBram Moolenaar
1678ed8ce057SBram Moolenaar /*
1679ed8ce057SBram Moolenaar * Search backwards in "line" from column "col_start" to find "quotechar".
1680ed8ce057SBram Moolenaar * Quote character escaped by one of the characters in "escape" is not counted
1681ed8ce057SBram Moolenaar * as a quote.
1682ed8ce057SBram Moolenaar * Return the found column or zero.
1683ed8ce057SBram Moolenaar */
1684ed8ce057SBram Moolenaar static int
find_prev_quote(char_u * line,int col_start,int quotechar,char_u * escape)1685ed8ce057SBram Moolenaar find_prev_quote(
1686ed8ce057SBram Moolenaar char_u *line,
1687ed8ce057SBram Moolenaar int col_start,
1688ed8ce057SBram Moolenaar int quotechar,
1689ed8ce057SBram Moolenaar char_u *escape) // escape characters, can be NULL
1690ed8ce057SBram Moolenaar {
1691ed8ce057SBram Moolenaar int n;
1692ed8ce057SBram Moolenaar
1693ed8ce057SBram Moolenaar while (col_start > 0)
1694ed8ce057SBram Moolenaar {
1695ed8ce057SBram Moolenaar --col_start;
1696ed8ce057SBram Moolenaar col_start -= (*mb_head_off)(line, line + col_start);
1697ed8ce057SBram Moolenaar n = 0;
1698ed8ce057SBram Moolenaar if (escape != NULL)
1699ed8ce057SBram Moolenaar while (col_start - n > 0 && vim_strchr(escape,
1700ed8ce057SBram Moolenaar line[col_start - n - 1]) != NULL)
1701ed8ce057SBram Moolenaar ++n;
1702ed8ce057SBram Moolenaar if (n & 1)
1703ed8ce057SBram Moolenaar col_start -= n; // uneven number of escape chars, skip it
1704ed8ce057SBram Moolenaar else if (line[col_start] == quotechar)
1705ed8ce057SBram Moolenaar break;
1706ed8ce057SBram Moolenaar }
1707ed8ce057SBram Moolenaar return col_start;
1708ed8ce057SBram Moolenaar }
1709ed8ce057SBram Moolenaar
1710ed8ce057SBram Moolenaar /*
1711ed8ce057SBram Moolenaar * Find quote under the cursor, cursor at end.
1712ed8ce057SBram Moolenaar * Returns TRUE if found, else FALSE.
1713ed8ce057SBram Moolenaar */
1714ed8ce057SBram Moolenaar int
current_quote(oparg_T * oap,long count,int include,int quotechar)1715ed8ce057SBram Moolenaar current_quote(
1716ed8ce057SBram Moolenaar oparg_T *oap,
1717ed8ce057SBram Moolenaar long count,
1718ed8ce057SBram Moolenaar int include, // TRUE == include quote char
1719ed8ce057SBram Moolenaar int quotechar) // Quote character
1720ed8ce057SBram Moolenaar {
1721ed8ce057SBram Moolenaar char_u *line = ml_get_curline();
1722ed8ce057SBram Moolenaar int col_end;
1723ed8ce057SBram Moolenaar int col_start = curwin->w_cursor.col;
1724ed8ce057SBram Moolenaar int inclusive = FALSE;
1725ed8ce057SBram Moolenaar int vis_empty = TRUE; // Visual selection <= 1 char
1726ed8ce057SBram Moolenaar int vis_bef_curs = FALSE; // Visual starts before cursor
1727ed8ce057SBram Moolenaar int did_exclusive_adj = FALSE; // adjusted pos for 'selection'
1728ed8ce057SBram Moolenaar int inside_quotes = FALSE; // Looks like "i'" done before
1729ed8ce057SBram Moolenaar int selected_quote = FALSE; // Has quote inside selection
1730ed8ce057SBram Moolenaar int i;
1731ed8ce057SBram Moolenaar int restore_vis_bef = FALSE; // restore VIsual on abort
1732ed8ce057SBram Moolenaar
1733ed8ce057SBram Moolenaar // When 'selection' is "exclusive" move the cursor to where it would be
1734ed8ce057SBram Moolenaar // with 'selection' "inclusive", so that the logic is the same for both.
1735ed8ce057SBram Moolenaar // The cursor then is moved forward after adjusting the area.
1736ed8ce057SBram Moolenaar if (VIsual_active)
1737ed8ce057SBram Moolenaar {
1738ed8ce057SBram Moolenaar // this only works within one line
1739ed8ce057SBram Moolenaar if (VIsual.lnum != curwin->w_cursor.lnum)
1740ed8ce057SBram Moolenaar return FALSE;
1741ed8ce057SBram Moolenaar
1742ed8ce057SBram Moolenaar vis_bef_curs = LT_POS(VIsual, curwin->w_cursor);
1743ed8ce057SBram Moolenaar vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
1744ed8ce057SBram Moolenaar if (*p_sel == 'e')
1745ed8ce057SBram Moolenaar {
1746ed8ce057SBram Moolenaar if (vis_bef_curs)
1747ed8ce057SBram Moolenaar {
1748ed8ce057SBram Moolenaar dec_cursor();
1749ed8ce057SBram Moolenaar did_exclusive_adj = TRUE;
1750ed8ce057SBram Moolenaar }
1751ed8ce057SBram Moolenaar else if (!vis_empty)
1752ed8ce057SBram Moolenaar {
1753ed8ce057SBram Moolenaar dec(&VIsual);
1754ed8ce057SBram Moolenaar did_exclusive_adj = TRUE;
1755ed8ce057SBram Moolenaar }
1756ed8ce057SBram Moolenaar vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
1757ed8ce057SBram Moolenaar if (!vis_bef_curs && !vis_empty)
1758ed8ce057SBram Moolenaar {
1759ed8ce057SBram Moolenaar // VIsual needs to be the start of Visual selection.
1760ed8ce057SBram Moolenaar pos_T t = curwin->w_cursor;
1761ed8ce057SBram Moolenaar
1762ed8ce057SBram Moolenaar curwin->w_cursor = VIsual;
1763ed8ce057SBram Moolenaar VIsual = t;
1764ed8ce057SBram Moolenaar vis_bef_curs = TRUE;
1765ed8ce057SBram Moolenaar restore_vis_bef = TRUE;
1766ed8ce057SBram Moolenaar }
1767ed8ce057SBram Moolenaar }
1768ed8ce057SBram Moolenaar }
1769ed8ce057SBram Moolenaar
1770ed8ce057SBram Moolenaar if (!vis_empty)
1771ed8ce057SBram Moolenaar {
1772ed8ce057SBram Moolenaar // Check if the existing selection exactly spans the text inside
1773ed8ce057SBram Moolenaar // quotes.
1774ed8ce057SBram Moolenaar if (vis_bef_curs)
1775ed8ce057SBram Moolenaar {
1776ed8ce057SBram Moolenaar inside_quotes = VIsual.col > 0
1777ed8ce057SBram Moolenaar && line[VIsual.col - 1] == quotechar
1778ed8ce057SBram Moolenaar && line[curwin->w_cursor.col] != NUL
1779ed8ce057SBram Moolenaar && line[curwin->w_cursor.col + 1] == quotechar;
1780ed8ce057SBram Moolenaar i = VIsual.col;
1781ed8ce057SBram Moolenaar col_end = curwin->w_cursor.col;
1782ed8ce057SBram Moolenaar }
1783ed8ce057SBram Moolenaar else
1784ed8ce057SBram Moolenaar {
1785ed8ce057SBram Moolenaar inside_quotes = curwin->w_cursor.col > 0
1786ed8ce057SBram Moolenaar && line[curwin->w_cursor.col - 1] == quotechar
1787ed8ce057SBram Moolenaar && line[VIsual.col] != NUL
1788ed8ce057SBram Moolenaar && line[VIsual.col + 1] == quotechar;
1789ed8ce057SBram Moolenaar i = curwin->w_cursor.col;
1790ed8ce057SBram Moolenaar col_end = VIsual.col;
1791ed8ce057SBram Moolenaar }
1792ed8ce057SBram Moolenaar
1793ed8ce057SBram Moolenaar // Find out if we have a quote in the selection.
1794ed8ce057SBram Moolenaar while (i <= col_end)
1795ed8ce057SBram Moolenaar if (line[i++] == quotechar)
1796ed8ce057SBram Moolenaar {
1797ed8ce057SBram Moolenaar selected_quote = TRUE;
1798ed8ce057SBram Moolenaar break;
1799ed8ce057SBram Moolenaar }
1800ed8ce057SBram Moolenaar }
1801ed8ce057SBram Moolenaar
1802ed8ce057SBram Moolenaar if (!vis_empty && line[col_start] == quotechar)
1803ed8ce057SBram Moolenaar {
1804ed8ce057SBram Moolenaar // Already selecting something and on a quote character. Find the
1805ed8ce057SBram Moolenaar // next quoted string.
1806ed8ce057SBram Moolenaar if (vis_bef_curs)
1807ed8ce057SBram Moolenaar {
1808ed8ce057SBram Moolenaar // Assume we are on a closing quote: move to after the next
1809ed8ce057SBram Moolenaar // opening quote.
1810ed8ce057SBram Moolenaar col_start = find_next_quote(line, col_start + 1, quotechar, NULL);
1811ed8ce057SBram Moolenaar if (col_start < 0)
1812ed8ce057SBram Moolenaar goto abort_search;
1813ed8ce057SBram Moolenaar col_end = find_next_quote(line, col_start + 1, quotechar,
1814ed8ce057SBram Moolenaar curbuf->b_p_qe);
1815ed8ce057SBram Moolenaar if (col_end < 0)
1816ed8ce057SBram Moolenaar {
1817ed8ce057SBram Moolenaar // We were on a starting quote perhaps?
1818ed8ce057SBram Moolenaar col_end = col_start;
1819ed8ce057SBram Moolenaar col_start = curwin->w_cursor.col;
1820ed8ce057SBram Moolenaar }
1821ed8ce057SBram Moolenaar }
1822ed8ce057SBram Moolenaar else
1823ed8ce057SBram Moolenaar {
1824ed8ce057SBram Moolenaar col_end = find_prev_quote(line, col_start, quotechar, NULL);
1825ed8ce057SBram Moolenaar if (line[col_end] != quotechar)
1826ed8ce057SBram Moolenaar goto abort_search;
1827ed8ce057SBram Moolenaar col_start = find_prev_quote(line, col_end, quotechar,
1828ed8ce057SBram Moolenaar curbuf->b_p_qe);
1829ed8ce057SBram Moolenaar if (line[col_start] != quotechar)
1830ed8ce057SBram Moolenaar {
1831ed8ce057SBram Moolenaar // We were on an ending quote perhaps?
1832ed8ce057SBram Moolenaar col_start = col_end;
1833ed8ce057SBram Moolenaar col_end = curwin->w_cursor.col;
1834ed8ce057SBram Moolenaar }
1835ed8ce057SBram Moolenaar }
1836ed8ce057SBram Moolenaar }
1837ed8ce057SBram Moolenaar else
1838ed8ce057SBram Moolenaar
1839ed8ce057SBram Moolenaar if (line[col_start] == quotechar || !vis_empty)
1840ed8ce057SBram Moolenaar {
1841ed8ce057SBram Moolenaar int first_col = col_start;
1842ed8ce057SBram Moolenaar
1843ed8ce057SBram Moolenaar if (!vis_empty)
1844ed8ce057SBram Moolenaar {
1845ed8ce057SBram Moolenaar if (vis_bef_curs)
1846ed8ce057SBram Moolenaar first_col = find_next_quote(line, col_start, quotechar, NULL);
1847ed8ce057SBram Moolenaar else
1848ed8ce057SBram Moolenaar first_col = find_prev_quote(line, col_start, quotechar, NULL);
1849ed8ce057SBram Moolenaar }
1850ed8ce057SBram Moolenaar
1851ed8ce057SBram Moolenaar // The cursor is on a quote, we don't know if it's the opening or
1852ed8ce057SBram Moolenaar // closing quote. Search from the start of the line to find out.
1853ed8ce057SBram Moolenaar // Also do this when there is a Visual area, a' may leave the cursor
1854ed8ce057SBram Moolenaar // in between two strings.
1855ed8ce057SBram Moolenaar col_start = 0;
1856ed8ce057SBram Moolenaar for (;;)
1857ed8ce057SBram Moolenaar {
1858ed8ce057SBram Moolenaar // Find open quote character.
1859ed8ce057SBram Moolenaar col_start = find_next_quote(line, col_start, quotechar, NULL);
1860ed8ce057SBram Moolenaar if (col_start < 0 || col_start > first_col)
1861ed8ce057SBram Moolenaar goto abort_search;
1862ed8ce057SBram Moolenaar // Find close quote character.
1863ed8ce057SBram Moolenaar col_end = find_next_quote(line, col_start + 1, quotechar,
1864ed8ce057SBram Moolenaar curbuf->b_p_qe);
1865ed8ce057SBram Moolenaar if (col_end < 0)
1866ed8ce057SBram Moolenaar goto abort_search;
1867ed8ce057SBram Moolenaar // If is cursor between start and end quote character, it is
1868ed8ce057SBram Moolenaar // target text object.
1869ed8ce057SBram Moolenaar if (col_start <= first_col && first_col <= col_end)
1870ed8ce057SBram Moolenaar break;
1871ed8ce057SBram Moolenaar col_start = col_end + 1;
1872ed8ce057SBram Moolenaar }
1873ed8ce057SBram Moolenaar }
1874ed8ce057SBram Moolenaar else
1875ed8ce057SBram Moolenaar {
1876ed8ce057SBram Moolenaar // Search backward for a starting quote.
1877ed8ce057SBram Moolenaar col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe);
1878ed8ce057SBram Moolenaar if (line[col_start] != quotechar)
1879ed8ce057SBram Moolenaar {
1880ed8ce057SBram Moolenaar // No quote before the cursor, look after the cursor.
1881ed8ce057SBram Moolenaar col_start = find_next_quote(line, col_start, quotechar, NULL);
1882ed8ce057SBram Moolenaar if (col_start < 0)
1883ed8ce057SBram Moolenaar goto abort_search;
1884ed8ce057SBram Moolenaar }
1885ed8ce057SBram Moolenaar
1886ed8ce057SBram Moolenaar // Find close quote character.
1887ed8ce057SBram Moolenaar col_end = find_next_quote(line, col_start + 1, quotechar,
1888ed8ce057SBram Moolenaar curbuf->b_p_qe);
1889ed8ce057SBram Moolenaar if (col_end < 0)
1890ed8ce057SBram Moolenaar goto abort_search;
1891ed8ce057SBram Moolenaar }
1892ed8ce057SBram Moolenaar
1893ed8ce057SBram Moolenaar // When "include" is TRUE, include spaces after closing quote or before
1894ed8ce057SBram Moolenaar // the starting quote.
1895ed8ce057SBram Moolenaar if (include)
1896ed8ce057SBram Moolenaar {
1897ed8ce057SBram Moolenaar if (VIM_ISWHITE(line[col_end + 1]))
1898ed8ce057SBram Moolenaar while (VIM_ISWHITE(line[col_end + 1]))
1899ed8ce057SBram Moolenaar ++col_end;
1900ed8ce057SBram Moolenaar else
1901ed8ce057SBram Moolenaar while (col_start > 0 && VIM_ISWHITE(line[col_start - 1]))
1902ed8ce057SBram Moolenaar --col_start;
1903ed8ce057SBram Moolenaar }
1904ed8ce057SBram Moolenaar
1905ed8ce057SBram Moolenaar // Set start position. After vi" another i" must include the ".
1906ed8ce057SBram Moolenaar // For v2i" include the quotes.
1907ed8ce057SBram Moolenaar if (!include && count < 2 && (vis_empty || !inside_quotes))
1908ed8ce057SBram Moolenaar ++col_start;
1909ed8ce057SBram Moolenaar curwin->w_cursor.col = col_start;
1910ed8ce057SBram Moolenaar if (VIsual_active)
1911ed8ce057SBram Moolenaar {
1912ed8ce057SBram Moolenaar // Set the start of the Visual area when the Visual area was empty, we
1913ed8ce057SBram Moolenaar // were just inside quotes or the Visual area didn't start at a quote
1914ed8ce057SBram Moolenaar // and didn't include a quote.
1915ed8ce057SBram Moolenaar if (vis_empty
1916ed8ce057SBram Moolenaar || (vis_bef_curs
1917ed8ce057SBram Moolenaar && !selected_quote
1918ed8ce057SBram Moolenaar && (inside_quotes
1919ed8ce057SBram Moolenaar || (line[VIsual.col] != quotechar
1920ed8ce057SBram Moolenaar && (VIsual.col == 0
1921ed8ce057SBram Moolenaar || line[VIsual.col - 1] != quotechar)))))
1922ed8ce057SBram Moolenaar {
1923ed8ce057SBram Moolenaar VIsual = curwin->w_cursor;
1924ed8ce057SBram Moolenaar redraw_curbuf_later(INVERTED);
1925ed8ce057SBram Moolenaar }
1926ed8ce057SBram Moolenaar }
1927ed8ce057SBram Moolenaar else
1928ed8ce057SBram Moolenaar {
1929ed8ce057SBram Moolenaar oap->start = curwin->w_cursor;
1930ed8ce057SBram Moolenaar oap->motion_type = MCHAR;
1931ed8ce057SBram Moolenaar }
1932ed8ce057SBram Moolenaar
1933ed8ce057SBram Moolenaar // Set end position.
1934ed8ce057SBram Moolenaar curwin->w_cursor.col = col_end;
1935ed8ce057SBram Moolenaar if ((include || count > 1 // After vi" another i" must include the ".
1936ed8ce057SBram Moolenaar || (!vis_empty && inside_quotes)
1937ed8ce057SBram Moolenaar ) && inc_cursor() == 2)
1938ed8ce057SBram Moolenaar inclusive = TRUE;
1939ed8ce057SBram Moolenaar if (VIsual_active)
1940ed8ce057SBram Moolenaar {
1941ed8ce057SBram Moolenaar if (vis_empty || vis_bef_curs)
1942ed8ce057SBram Moolenaar {
1943ed8ce057SBram Moolenaar // decrement cursor when 'selection' is not exclusive
1944ed8ce057SBram Moolenaar if (*p_sel != 'e')
1945ed8ce057SBram Moolenaar dec_cursor();
1946ed8ce057SBram Moolenaar }
1947ed8ce057SBram Moolenaar else
1948ed8ce057SBram Moolenaar {
1949ed8ce057SBram Moolenaar // Cursor is at start of Visual area. Set the end of the Visual
1950ed8ce057SBram Moolenaar // area when it was just inside quotes or it didn't end at a
1951ed8ce057SBram Moolenaar // quote.
1952ed8ce057SBram Moolenaar if (inside_quotes
1953ed8ce057SBram Moolenaar || (!selected_quote
1954ed8ce057SBram Moolenaar && line[VIsual.col] != quotechar
1955ed8ce057SBram Moolenaar && (line[VIsual.col] == NUL
1956ed8ce057SBram Moolenaar || line[VIsual.col + 1] != quotechar)))
1957ed8ce057SBram Moolenaar {
1958ed8ce057SBram Moolenaar dec_cursor();
1959ed8ce057SBram Moolenaar VIsual = curwin->w_cursor;
1960ed8ce057SBram Moolenaar }
1961ed8ce057SBram Moolenaar curwin->w_cursor.col = col_start;
1962ed8ce057SBram Moolenaar }
1963ed8ce057SBram Moolenaar if (VIsual_mode == 'V')
1964ed8ce057SBram Moolenaar {
1965ed8ce057SBram Moolenaar VIsual_mode = 'v';
1966ed8ce057SBram Moolenaar redraw_cmdline = TRUE; // show mode later
1967ed8ce057SBram Moolenaar }
1968ed8ce057SBram Moolenaar }
1969ed8ce057SBram Moolenaar else
1970ed8ce057SBram Moolenaar {
1971ed8ce057SBram Moolenaar // Set inclusive and other oap's flags.
1972ed8ce057SBram Moolenaar oap->inclusive = inclusive;
1973ed8ce057SBram Moolenaar }
1974ed8ce057SBram Moolenaar
1975ed8ce057SBram Moolenaar return OK;
1976ed8ce057SBram Moolenaar
1977ed8ce057SBram Moolenaar abort_search:
1978ed8ce057SBram Moolenaar if (VIsual_active && *p_sel == 'e')
1979ed8ce057SBram Moolenaar {
1980ed8ce057SBram Moolenaar if (did_exclusive_adj)
1981ed8ce057SBram Moolenaar inc_cursor();
1982ed8ce057SBram Moolenaar if (restore_vis_bef)
1983ed8ce057SBram Moolenaar {
1984ed8ce057SBram Moolenaar pos_T t = curwin->w_cursor;
1985ed8ce057SBram Moolenaar
1986ed8ce057SBram Moolenaar curwin->w_cursor = VIsual;
1987ed8ce057SBram Moolenaar VIsual = t;
1988ed8ce057SBram Moolenaar }
1989ed8ce057SBram Moolenaar }
1990ed8ce057SBram Moolenaar return FALSE;
1991ed8ce057SBram Moolenaar }
1992ed8ce057SBram Moolenaar
1993ed8ce057SBram Moolenaar #endif // FEAT_TEXTOBJ
1994