blob: aa9445ed03529f91aa25726b6243acffcab2558c [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * mark.c: functions for setting marks and jumping to them
12 */
13
14#include "vim.h"
15
16/*
17 * This file contains routines to maintain and manipulate marks.
18 */
19
20/*
21 * If a named file mark's lnum is non-zero, it is valid.
22 * If a named file mark's fnum is non-zero, it is for an existing buffer,
23 * otherwise it is from .viminfo and namedfm[n].fname is the file name.
24 * There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing
25 * viminfo).
26 */
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010027static xfmark_T namedfm[NMARKS + EXTRA_MARKS]; // marks with file nr
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
Bram Moolenaar5843f5f2019-08-20 20:13:45 +020029static void fname2fnum(xfmark_T *fm);
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +010030static void fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf);
31static char_u *mark_line(pos_T *mp, int lead_len);
32static void show_one_mark(int, char_u *, pos_T *, char_u *, int current);
Bram Moolenaar88d298a2017-03-14 21:53:58 +010033static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount,
34 long amount_after, int adjust_folds);
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
36/*
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000037 * Set named mark "c" at current cursor position.
Bram Moolenaar071d4272004-06-13 20:20:40 +000038 * Returns OK on success, FAIL if bad name given.
39 */
40 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +010041setmark(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +000042{
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000043 return setmark_pos(c, &curwin->w_cursor, curbuf->b_fnum);
44}
45
46/*
47 * Set named mark "c" to position "pos".
48 * When "c" is upper case use file "fnum".
49 * Returns OK on success, FAIL if bad name given.
50 */
51 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +010052setmark_pos(int c, pos_T *pos, int fnum)
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000053{
Bram Moolenaar071d4272004-06-13 20:20:40 +000054 int i;
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010055 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +000056
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010057 // Check for a special key (may cause islower() to crash).
Bram Moolenaar071d4272004-06-13 20:20:40 +000058 if (c < 0)
59 return FAIL;
60
61 if (c == '\'' || c == '`')
62 {
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000063 if (pos == &curwin->w_cursor)
64 {
65 setpcmark();
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010066 // keep it even when the cursor doesn't move
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000067 curwin->w_prev_pcmark = curwin->w_pcmark;
68 }
69 else
70 curwin->w_pcmark = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +000071 return OK;
72 }
73
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010074 buf = buflist_findnr(fnum);
75 if (buf == NULL)
76 return FAIL;
77
Bram Moolenaar08250432008-02-13 11:42:46 +000078 if (c == '"')
79 {
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010080 buf->b_last_cursor = *pos;
Bram Moolenaar08250432008-02-13 11:42:46 +000081 return OK;
82 }
83
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010084 // Allow setting '[ and '] for an autocommand that simulates reading a
85 // file.
Bram Moolenaar071d4272004-06-13 20:20:40 +000086 if (c == '[')
87 {
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010088 buf->b_op_start = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +000089 return OK;
90 }
91 if (c == ']')
92 {
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010093 buf->b_op_end = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 return OK;
95 }
96
Bram Moolenaarbc88a272013-08-02 17:22:23 +020097 if (c == '<' || c == '>')
Bram Moolenaar0306ac32012-07-06 17:51:28 +020098 {
Bram Moolenaarbc88a272013-08-02 17:22:23 +020099 if (c == '<')
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100100 buf->b_visual.vi_start = *pos;
Bram Moolenaarbc88a272013-08-02 17:22:23 +0200101 else
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100102 buf->b_visual.vi_end = *pos;
103 if (buf->b_visual.vi_mode == NUL)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100104 // Visual_mode has not yet been set, use a sane default.
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100105 buf->b_visual.vi_mode = 'v';
Bram Moolenaar0306ac32012-07-06 17:51:28 +0200106 return OK;
107 }
Bram Moolenaar0306ac32012-07-06 17:51:28 +0200108
Bram Moolenaar2d358992016-06-12 21:20:54 +0200109 if (ASCII_ISLOWER(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110 {
111 i = c - 'a';
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100112 buf->b_namedm[i] = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113 return OK;
114 }
Bram Moolenaar2d358992016-06-12 21:20:54 +0200115 if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 {
Bram Moolenaar2d358992016-06-12 21:20:54 +0200117 if (VIM_ISDIGIT(c))
118 i = c - '0' + NMARKS;
119 else
120 i = c - 'A';
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000121 namedfm[i].fmark.mark = *pos;
122 namedfm[i].fmark.fnum = fnum;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100123 VIM_CLEAR(namedfm[i].fname);
Bram Moolenaar2d358992016-06-12 21:20:54 +0200124#ifdef FEAT_VIMINFO
125 namedfm[i].time_set = vim_time();
126#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127 return OK;
128 }
129 return FAIL;
130}
131
132/*
133 * Set the previous context mark to the current position and add it to the
134 * jump list.
135 */
136 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100137setpcmark(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138{
139#ifdef FEAT_JUMPLIST
140 int i;
141 xfmark_T *fm;
142#endif
143#ifdef JUMPLIST_ROTATE
144 xfmark_T tempmark;
145#endif
146
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100147 // for :global the mark is set only once
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148 if (global_busy || listcmd_busy || cmdmod.keepjumps)
149 return;
150
151 curwin->w_prev_pcmark = curwin->w_pcmark;
152 curwin->w_pcmark = curwin->w_cursor;
153
154#ifdef FEAT_JUMPLIST
155# ifdef JUMPLIST_ROTATE
156 /*
157 * If last used entry is not at the top, put it at the top by rotating
158 * the stack until it is (the newer entries will be at the bottom).
159 * Keep one entry (the last used one) at the top.
160 */
161 if (curwin->w_jumplistidx < curwin->w_jumplistlen)
162 ++curwin->w_jumplistidx;
163 while (curwin->w_jumplistidx < curwin->w_jumplistlen)
164 {
165 tempmark = curwin->w_jumplist[curwin->w_jumplistlen - 1];
166 for (i = curwin->w_jumplistlen - 1; i > 0; --i)
167 curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
168 curwin->w_jumplist[0] = tempmark;
169 ++curwin->w_jumplistidx;
170 }
171# endif
172
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100173 // If jumplist is full: remove oldest entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174 if (++curwin->w_jumplistlen > JUMPLISTSIZE)
175 {
176 curwin->w_jumplistlen = JUMPLISTSIZE;
177 vim_free(curwin->w_jumplist[0].fname);
178 for (i = 1; i < JUMPLISTSIZE; ++i)
179 curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
180 }
181 curwin->w_jumplistidx = curwin->w_jumplistlen;
182 fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
183
184 fm->fmark.mark = curwin->w_pcmark;
185 fm->fmark.fnum = curbuf->b_fnum;
186 fm->fname = NULL;
Bram Moolenaar2d358992016-06-12 21:20:54 +0200187# ifdef FEAT_VIMINFO
188 fm->time_set = vim_time();
189# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190#endif
191}
192
193/*
194 * To change context, call setpcmark(), then move the current position to
195 * where ever, then call checkpcmark(). This ensures that the previous
196 * context will only be changed if the cursor moved to a different line.
197 * If pcmark was deleted (with "dG") the previous mark is restored.
198 */
199 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100200checkpcmark(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201{
202 if (curwin->w_prev_pcmark.lnum != 0
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100203 && (EQUAL_POS(curwin->w_pcmark, curwin->w_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204 || curwin->w_pcmark.lnum == 0))
205 {
206 curwin->w_pcmark = curwin->w_prev_pcmark;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100207 curwin->w_prev_pcmark.lnum = 0; // Show it has been checked
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208 }
209}
210
211#if defined(FEAT_JUMPLIST) || defined(PROTO)
212/*
213 * move "count" positions in the jump list (count may be negative)
214 */
215 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100216movemark(int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217{
218 pos_T *pos;
219 xfmark_T *jmp;
220
Bram Moolenaar48679742018-02-13 13:33:29 +0100221 cleanup_jumplist(curwin, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000222
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100223 if (curwin->w_jumplistlen == 0) // nothing to jump to
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224 return (pos_T *)NULL;
225
226 for (;;)
227 {
228 if (curwin->w_jumplistidx + count < 0
229 || curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
230 return (pos_T *)NULL;
231
232 /*
233 * if first CTRL-O or CTRL-I command after a jump, add cursor position
Bram Moolenaarf711faf2007-05-10 16:48:19 +0000234 * to list. Careful: If there are duplicates (CTRL-O immediately after
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235 * starting Vim on a file), another entry may have been removed.
236 */
237 if (curwin->w_jumplistidx == curwin->w_jumplistlen)
238 {
239 setpcmark();
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100240 --curwin->w_jumplistidx; // skip the new entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 if (curwin->w_jumplistidx + count < 0)
242 return (pos_T *)NULL;
243 }
244
245 curwin->w_jumplistidx += count;
246
247 jmp = curwin->w_jumplist + curwin->w_jumplistidx;
248 if (jmp->fmark.fnum == 0)
249 fname2fnum(jmp);
250 if (jmp->fmark.fnum != curbuf->b_fnum)
251 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100252 // jump to other file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 if (buflist_findnr(jmp->fmark.fnum) == NULL)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100254 { // Skip this one ..
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 count += count < 0 ? -1 : 1;
256 continue;
257 }
258 if (buflist_getfile(jmp->fmark.fnum, jmp->fmark.mark.lnum,
259 0, FALSE) == FAIL)
260 return (pos_T *)NULL;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100261 // Set lnum again, autocommands my have changed it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262 curwin->w_cursor = jmp->fmark.mark;
263 pos = (pos_T *)-1;
264 }
265 else
266 pos = &(jmp->fmark.mark);
267 return pos;
268 }
269}
270
271/*
272 * Move "count" positions in the changelist (count may be negative).
273 */
274 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100275movechangelist(int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276{
277 int n;
278
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100279 if (curbuf->b_changelistlen == 0) // nothing to jump to
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 return (pos_T *)NULL;
281
282 n = curwin->w_changelistidx;
283 if (n + count < 0)
284 {
285 if (n == 0)
286 return (pos_T *)NULL;
287 n = 0;
288 }
289 else if (n + count >= curbuf->b_changelistlen)
290 {
291 if (n == curbuf->b_changelistlen - 1)
292 return (pos_T *)NULL;
293 n = curbuf->b_changelistlen - 1;
294 }
295 else
296 n += count;
297 curwin->w_changelistidx = n;
298 return curbuf->b_changelist + n;
299}
300#endif
301
302/*
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100303 * Find mark "c" in buffer pointed to by "buf".
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000304 * If "changefile" is TRUE it's allowed to edit another file for '0, 'A, etc.
305 * If "fnum" is not NULL store the fnum there for '0, 'A etc., don't edit
306 * another file.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 * Returns:
308 * - pointer to pos_T if found. lnum is 0 when mark not set, -1 when mark is
309 * in another file which can't be gotten. (caller needs to check lnum!)
310 * - NULL if there is no mark called 'c'.
311 * - -1 if mark is in other file and jumped there (only if changefile is TRUE)
312 */
313 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100314getmark_buf(buf_T *buf, int c, int changefile)
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100315{
316 return getmark_buf_fnum(buf, c, changefile, NULL);
317}
318
319 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100320getmark(int c, int changefile)
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000321{
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100322 return getmark_buf_fnum(curbuf, c, changefile, NULL);
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000323}
324
325 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100326getmark_buf_fnum(
327 buf_T *buf,
328 int c,
329 int changefile,
330 int *fnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331{
332 pos_T *posp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000333 pos_T *startp, *endp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000334 static pos_T pos_copy;
335
336 posp = NULL;
337
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100338 // Check for special key, can't be a mark name and might cause islower()
339 // to crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000340 if (c < 0)
341 return posp;
342#ifndef EBCDIC
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100343 if (c > '~') // check for islower()/isupper()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 ;
345 else
346#endif
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100347 if (c == '\'' || c == '`') // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100349 pos_copy = curwin->w_pcmark; // need to make a copy because
350 posp = &pos_copy; // w_pcmark may be changed soon
Bram Moolenaar071d4272004-06-13 20:20:40 +0000351 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100352 else if (c == '"') // to pos when leaving buffer
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100353 posp = &(buf->b_last_cursor);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100354 else if (c == '^') // to where Insert mode stopped
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100355 posp = &(buf->b_last_insert);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100356 else if (c == '.') // to where last change was made
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100357 posp = &(buf->b_last_change);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100358 else if (c == '[') // to start of previous operator
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100359 posp = &(buf->b_op_start);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100360 else if (c == ']') // to end of previous operator
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100361 posp = &(buf->b_op_end);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100362 else if (c == '{' || c == '}') // to previous/next paragraph
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 {
364 pos_T pos;
365 oparg_T oa;
366 int slcb = listcmd_busy;
367
368 pos = curwin->w_cursor;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100369 listcmd_busy = TRUE; // avoid that '' is changed
Bram Moolenaar8b96d642005-09-05 22:05:30 +0000370 if (findpar(&oa.inclusive,
371 c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372 {
373 pos_copy = curwin->w_cursor;
374 posp = &pos_copy;
375 }
376 curwin->w_cursor = pos;
377 listcmd_busy = slcb;
378 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100379 else if (c == '(' || c == ')') // to previous/next sentence
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 {
381 pos_T pos;
382 int slcb = listcmd_busy;
383
384 pos = curwin->w_cursor;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100385 listcmd_busy = TRUE; // avoid that '' is changed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 if (findsent(c == ')' ? FORWARD : BACKWARD, 1L))
387 {
388 pos_copy = curwin->w_cursor;
389 posp = &pos_copy;
390 }
391 curwin->w_cursor = pos;
392 listcmd_busy = slcb;
393 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100394 else if (c == '<' || c == '>') // start/end of visual area
Bram Moolenaar071d4272004-06-13 20:20:40 +0000395 {
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100396 startp = &buf->b_visual.vi_start;
397 endp = &buf->b_visual.vi_end;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100398 if (((c == '<') == LT_POS(*startp, *endp) || endp->lnum == 0)
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100399 && startp->lnum != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 posp = startp;
401 else
402 posp = endp;
403 /*
404 * For Visual line mode, set mark at begin or end of line
405 */
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100406 if (buf->b_visual.vi_mode == 'V')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 {
408 pos_copy = *posp;
409 posp = &pos_copy;
410 if (c == '<')
411 pos_copy.col = 0;
412 else
413 pos_copy.col = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414 pos_copy.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 }
416 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100417 else if (ASCII_ISLOWER(c)) // normal named mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 {
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100419 posp = &(buf->b_namedm[c - 'a']);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100421 else if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c)) // named file mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 {
423 if (VIM_ISDIGIT(c))
424 c = c - '0' + NMARKS;
425 else
426 c -= 'A';
427 posp = &(namedfm[c].fmark.mark);
428
429 if (namedfm[c].fmark.fnum == 0)
430 fname2fnum(&namedfm[c]);
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000431
432 if (fnum != NULL)
433 *fnum = namedfm[c].fmark.fnum;
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100434 else if (namedfm[c].fmark.fnum != buf->b_fnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100436 // mark is in another file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 posp = &pos_copy;
438
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 if (namedfm[c].fmark.mark.lnum != 0
440 && changefile && namedfm[c].fmark.fnum)
441 {
442 if (buflist_getfile(namedfm[c].fmark.fnum,
443 (linenr_T)1, GETF_SETMARK, FALSE) == OK)
444 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100445 // Set the lnum now, autocommands could have changed it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 curwin->w_cursor = namedfm[c].fmark.mark;
447 return (pos_T *)-1;
448 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100449 pos_copy.lnum = -1; // can't get file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450 }
451 else
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100452 pos_copy.lnum = 0; // mark exists, but is not valid in
453 // current buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454 }
455 }
456
457 return posp;
458}
459
460/*
461 * Search for the next named mark in the current file.
462 *
463 * Returns pointer to pos_T of the next mark or NULL if no mark is found.
464 */
465 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100466getnextmark(
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100467 pos_T *startpos, // where to start
468 int dir, // direction for search
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100469 int begin_line)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470{
471 int i;
472 pos_T *result = NULL;
473 pos_T pos;
474
475 pos = *startpos;
476
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100477 // When searching backward and leaving the cursor on the first non-blank,
478 // position must be in a previous line.
479 // When searching forward and leaving the cursor on the first non-blank,
480 // position must be in a next line.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481 if (dir == BACKWARD && begin_line)
482 pos.col = 0;
483 else if (dir == FORWARD && begin_line)
484 pos.col = MAXCOL;
485
486 for (i = 0; i < NMARKS; i++)
487 {
488 if (curbuf->b_namedm[i].lnum > 0)
489 {
490 if (dir == FORWARD)
491 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100492 if ((result == NULL || LT_POS(curbuf->b_namedm[i], *result))
493 && LT_POS(pos, curbuf->b_namedm[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494 result = &curbuf->b_namedm[i];
495 }
496 else
497 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100498 if ((result == NULL || LT_POS(*result, curbuf->b_namedm[i]))
499 && LT_POS(curbuf->b_namedm[i], pos))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 result = &curbuf->b_namedm[i];
501 }
502 }
503 }
504
505 return result;
506}
507
508/*
509 * For an xtended filemark: set the fnum from the fname.
510 * This is used for marks obtained from the .viminfo file. It's postponed
511 * until the mark is used to avoid a long startup delay.
512 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +0200513 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100514fname2fnum(xfmark_T *fm)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515{
516 char_u *p;
517
518 if (fm->fname != NULL)
519 {
520 /*
521 * First expand "~/" in the file name to the home directory.
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000522 * Don't expand the whole name, it may contain other '~' chars.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523 */
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000524 if (fm->fname[0] == '~' && (fm->fname[1] == '/'
525#ifdef BACKSLASH_IN_FILENAME
526 || fm->fname[1] == '\\'
527#endif
528 ))
529 {
530 int len;
531
532 expand_env((char_u *)"~/", NameBuff, MAXPATHL);
Bram Moolenaarcb4cef22008-03-16 15:04:34 +0000533 len = (int)STRLEN(NameBuff);
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000534 vim_strncpy(NameBuff + len, fm->fname + 2, MAXPATHL - len - 1);
535 }
536 else
537 vim_strncpy(NameBuff, fm->fname, MAXPATHL - 1);
538
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100539 // Try to shorten the file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 mch_dirname(IObuff, IOSIZE);
541 p = shorten_fname(NameBuff, IObuff);
542
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100543 // buflist_new() will call fmarks_check_names()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 (void)buflist_new(NameBuff, p, (linenr_T)1, 0);
545 }
546}
547
548/*
549 * Check all file marks for a name that matches the file name in buf.
550 * May replace the name with an fnum.
551 * Used for marks that come from the .viminfo file.
552 */
553 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100554fmarks_check_names(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555{
556 char_u *name;
557 int i;
558#ifdef FEAT_JUMPLIST
559 win_T *wp;
560#endif
561
562 if (buf->b_ffname == NULL)
563 return;
564
565 name = home_replace_save(buf, buf->b_ffname);
566 if (name == NULL)
567 return;
568
569 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
570 fmarks_check_one(&namedfm[i], name, buf);
571
572#ifdef FEAT_JUMPLIST
573 FOR_ALL_WINDOWS(wp)
574 {
575 for (i = 0; i < wp->w_jumplistlen; ++i)
576 fmarks_check_one(&wp->w_jumplist[i], name, buf);
577 }
578#endif
579
580 vim_free(name);
581}
582
583 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100584fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585{
586 if (fm->fmark.fnum == 0
587 && fm->fname != NULL
588 && fnamecmp(name, fm->fname) == 0)
589 {
590 fm->fmark.fnum = buf->b_fnum;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100591 VIM_CLEAR(fm->fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 }
593}
594
595/*
596 * Check a if a position from a mark is valid.
597 * Give and error message and return FAIL if not.
598 */
599 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100600check_mark(pos_T *pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601{
602 if (pos == NULL)
603 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100604 emsg(_(e_umark));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 return FAIL;
606 }
607 if (pos->lnum <= 0)
608 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100609 // lnum is negative if mark is in another file can can't get that
610 // file, error message already give then.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 if (pos->lnum == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100612 emsg(_(e_marknotset));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 return FAIL;
614 }
615 if (pos->lnum > curbuf->b_ml.ml_line_count)
616 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100617 emsg(_(e_markinval));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 return FAIL;
619 }
620 return OK;
621}
622
623/*
624 * clrallmarks() - clear all marks in the buffer 'buf'
625 *
626 * Used mainly when trashing the entire buffer during ":e" type commands
627 */
628 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100629clrallmarks(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630{
631 static int i = -1;
632
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100633 if (i == -1) // first call ever: initialize
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 for (i = 0; i < NMARKS + 1; i++)
635 {
636 namedfm[i].fmark.mark.lnum = 0;
637 namedfm[i].fname = NULL;
Bram Moolenaar2d358992016-06-12 21:20:54 +0200638#ifdef FEAT_VIMINFO
639 namedfm[i].time_set = 0;
640#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 }
642
643 for (i = 0; i < NMARKS; i++)
644 buf->b_namedm[i].lnum = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100645 buf->b_op_start.lnum = 0; // start/end op mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 buf->b_op_end.lnum = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100647 buf->b_last_cursor.lnum = 1; // '" mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648 buf->b_last_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 buf->b_last_cursor.coladd = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100650 buf->b_last_insert.lnum = 0; // '^ mark cleared
651 buf->b_last_change.lnum = 0; // '. mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652#ifdef FEAT_JUMPLIST
653 buf->b_changelistlen = 0;
654#endif
655}
656
657/*
658 * Get name of file from a filemark.
659 * When it's in the current buffer, return the text at the mark.
660 * Returns an allocated string.
661 */
662 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100663fm_getname(fmark_T *fmark, int lead_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664{
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100665 if (fmark->fnum == curbuf->b_fnum) // current buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 return mark_line(&(fmark->mark), lead_len);
667 return buflist_nr2name(fmark->fnum, FALSE, TRUE);
668}
669
670/*
671 * Return the line at mark "mp". Truncate to fit in window.
672 * The returned string has been allocated.
673 */
674 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100675mark_line(pos_T *mp, int lead_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676{
677 char_u *s, *p;
678 int len;
679
680 if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count)
681 return vim_strsave((char_u *)"-invalid-");
Bram Moolenaar9d5185b2018-07-08 17:57:34 +0200682 // Allow for up to 5 bytes per character.
Bram Moolenaar71ccd032020-06-12 22:59:11 +0200683 s = vim_strnsave(skipwhite(ml_get(mp->lnum)), Columns * 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 if (s == NULL)
685 return NULL;
Bram Moolenaar9d5185b2018-07-08 17:57:34 +0200686 // Truncate the line to fit it in the window.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 len = 0;
Bram Moolenaar91acfff2017-03-12 19:22:36 +0100688 for (p = s; *p != NUL; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689 {
690 len += ptr2cells(p);
691 if (len >= Columns - lead_len)
692 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693 }
694 *p = NUL;
695 return s;
696}
697
698/*
699 * print the marks
700 */
701 void
Bram Moolenaar4bd78232019-09-19 23:21:55 +0200702ex_marks(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703{
704 char_u *arg = eap->arg;
705 int i;
706 char_u *name;
Bram Moolenaar54c3fcd2020-07-19 22:09:06 +0200707 pos_T *posp, *startp, *endp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000708
709 if (arg != NULL && *arg == NUL)
710 arg = NULL;
711
712 show_one_mark('\'', arg, &curwin->w_pcmark, NULL, TRUE);
713 for (i = 0; i < NMARKS; ++i)
714 show_one_mark(i + 'a', arg, &curbuf->b_namedm[i], NULL, TRUE);
715 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
716 {
717 if (namedfm[i].fmark.fnum != 0)
718 name = fm_getname(&namedfm[i].fmark, 15);
719 else
720 name = namedfm[i].fname;
721 if (name != NULL)
722 {
723 show_one_mark(i >= NMARKS ? i - NMARKS + '0' : i + 'A',
724 arg, &namedfm[i].fmark.mark, name,
725 namedfm[i].fmark.fnum == curbuf->b_fnum);
726 if (namedfm[i].fmark.fnum != 0)
727 vim_free(name);
728 }
729 }
730 show_one_mark('"', arg, &curbuf->b_last_cursor, NULL, TRUE);
731 show_one_mark('[', arg, &curbuf->b_op_start, NULL, TRUE);
732 show_one_mark(']', arg, &curbuf->b_op_end, NULL, TRUE);
733 show_one_mark('^', arg, &curbuf->b_last_insert, NULL, TRUE);
734 show_one_mark('.', arg, &curbuf->b_last_change, NULL, TRUE);
Bram Moolenaar54c3fcd2020-07-19 22:09:06 +0200735
736 // Show the marks as where they will jump to.
737 startp = &curbuf->b_visual.vi_start;
738 endp = &curbuf->b_visual.vi_end;
739 if ((LT_POS(*startp, *endp) || endp->lnum == 0) && startp->lnum != 0)
740 posp = startp;
741 else
742 posp = endp;
743 show_one_mark('<', arg, posp, NULL, TRUE);
744 show_one_mark('>', arg, posp == startp ? endp : startp, NULL, TRUE);
745
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 show_one_mark(-1, arg, NULL, NULL, FALSE);
747}
748
749 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100750show_one_mark(
751 int c,
752 char_u *arg,
753 pos_T *p,
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200754 char_u *name_arg,
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100755 int current) // in current file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756{
757 static int did_title = FALSE;
758 int mustfree = FALSE;
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200759 char_u *name = name_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100761 if (c == -1) // finish up
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 {
763 if (did_title)
764 did_title = FALSE;
765 else
766 {
767 if (arg == NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100768 msg(_("No marks set"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100770 semsg(_("E283: No marks matching \"%s\""), arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771 }
772 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200773 // don't output anything if 'q' typed at --more-- prompt
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 else if (!got_int
775 && (arg == NULL || vim_strchr(arg, c) != NULL)
776 && p->lnum != 0)
777 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200778 if (name == NULL && current)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200780 name = mark_line(p, 15);
781 mustfree = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200783 if (!message_filtered(name))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200785 if (!did_title)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200787 // Highlight title
788 msg_puts_title(_("\nmark line col file/text"));
789 did_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200791 msg_putchar('\n');
792 if (!got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200794 sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
795 msg_outtrans(IObuff);
796 if (name != NULL)
797 {
798 msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
799 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200801 out_flush(); // show one line at a time
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200803 if (mustfree)
804 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 }
806}
807
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000808/*
809 * ":delmarks[!] [marks]"
810 */
811 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100812ex_delmarks(exarg_T *eap)
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000813{
814 char_u *p;
815 int from, to;
816 int i;
817 int lower;
818 int digit;
819 int n;
820
821 if (*eap->arg == NUL && eap->forceit)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100822 // clear all marks
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000823 clrallmarks(curbuf);
824 else if (eap->forceit)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100825 emsg(_(e_invarg));
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000826 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100827 emsg(_(e_argreq));
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000828 else
829 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100830 // clear specified marks only
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000831 for (p = eap->arg; *p != NUL; ++p)
832 {
833 lower = ASCII_ISLOWER(*p);
834 digit = VIM_ISDIGIT(*p);
835 if (lower || digit || ASCII_ISUPPER(*p))
836 {
837 if (p[1] == '-')
838 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100839 // clear range of marks
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000840 from = *p;
841 to = p[2];
842 if (!(lower ? ASCII_ISLOWER(p[2])
843 : (digit ? VIM_ISDIGIT(p[2])
844 : ASCII_ISUPPER(p[2])))
845 || to < from)
846 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100847 semsg(_(e_invarg2), p);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000848 return;
849 }
850 p += 2;
851 }
852 else
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100853 // clear one lower case mark
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000854 from = to = *p;
855
856 for (i = from; i <= to; ++i)
857 {
858 if (lower)
859 curbuf->b_namedm[i - 'a'].lnum = 0;
860 else
861 {
862 if (digit)
863 n = i - '0' + NMARKS;
864 else
865 n = i - 'A';
866 namedfm[n].fmark.mark.lnum = 0;
Bram Moolenaar8cd6cd82019-12-27 17:33:26 +0100867 namedfm[n].fmark.fnum = 0;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100868 VIM_CLEAR(namedfm[n].fname);
Bram Moolenaar2d358992016-06-12 21:20:54 +0200869#ifdef FEAT_VIMINFO
Bram Moolenaar8cd6cd82019-12-27 17:33:26 +0100870 namedfm[n].time_set = digit ? 0 : vim_time();
Bram Moolenaar2d358992016-06-12 21:20:54 +0200871#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000872 }
873 }
874 }
875 else
876 switch (*p)
877 {
878 case '"': curbuf->b_last_cursor.lnum = 0; break;
879 case '^': curbuf->b_last_insert.lnum = 0; break;
880 case '.': curbuf->b_last_change.lnum = 0; break;
881 case '[': curbuf->b_op_start.lnum = 0; break;
882 case ']': curbuf->b_op_end.lnum = 0; break;
Bram Moolenaara226a6d2006-02-26 23:59:20 +0000883 case '<': curbuf->b_visual.vi_start.lnum = 0; break;
884 case '>': curbuf->b_visual.vi_end.lnum = 0; break;
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000885 case ' ': break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100886 default: semsg(_(e_invarg2), p);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000887 return;
888 }
889 }
890 }
891}
892
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893#if defined(FEAT_JUMPLIST) || defined(PROTO)
894/*
895 * print the jumplist
896 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100898ex_jumps(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899{
900 int i;
901 char_u *name;
902
Bram Moolenaar48679742018-02-13 13:33:29 +0100903 cleanup_jumplist(curwin, TRUE);
Bram Moolenaara7e18d22018-02-11 14:29:49 +0100904
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100905 // Highlight title
Bram Moolenaar32526b32019-01-19 17:43:09 +0100906 msg_puts_title(_("\n jump line col file/text"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i)
908 {
909 if (curwin->w_jumplist[i].fmark.mark.lnum != 0)
910 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
Bram Moolenaarf86db782018-10-25 13:31:37 +0200912
913 // apply :filter /pat/ or file name not available
914 if (name == NULL || message_filtered(name))
Bram Moolenaard93090f2019-01-27 15:07:39 +0100915 {
916 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 continue;
Bram Moolenaard93090f2019-01-27 15:07:39 +0100918 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919
920 msg_putchar('\n');
921 if (got_int)
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000922 {
923 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 break;
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000925 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926 sprintf((char *)IObuff, "%c %2d %5ld %4d ",
927 i == curwin->w_jumplistidx ? '>' : ' ',
928 i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
929 : curwin->w_jumplistidx - i,
930 curwin->w_jumplist[i].fmark.mark.lnum,
931 curwin->w_jumplist[i].fmark.mark.col);
932 msg_outtrans(IObuff);
933 msg_outtrans_attr(name,
934 curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum
Bram Moolenaar8820b482017-03-16 17:23:31 +0100935 ? HL_ATTR(HLF_D) : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 vim_free(name);
937 ui_breakcheck();
938 }
939 out_flush();
940 }
941 if (curwin->w_jumplistidx == curwin->w_jumplistlen)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100942 msg_puts("\n>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943}
944
Bram Moolenaar2d358992016-06-12 21:20:54 +0200945 void
946ex_clearjumps(exarg_T *eap UNUSED)
947{
948 free_jumplist(curwin);
949 curwin->w_jumplistlen = 0;
950 curwin->w_jumplistidx = 0;
951}
952
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953/*
954 * print the changelist
955 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100957ex_changes(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000958{
959 int i;
960 char_u *name;
961
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100962 // Highlight title
Bram Moolenaar32526b32019-01-19 17:43:09 +0100963 msg_puts_title(_("\nchange line col text"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964
965 for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i)
966 {
967 if (curbuf->b_changelist[i].lnum != 0)
968 {
969 msg_putchar('\n');
970 if (got_int)
971 break;
972 sprintf((char *)IObuff, "%c %3d %5ld %4d ",
973 i == curwin->w_changelistidx ? '>' : ' ',
974 i > curwin->w_changelistidx ? i - curwin->w_changelistidx
975 : curwin->w_changelistidx - i,
976 (long)curbuf->b_changelist[i].lnum,
977 curbuf->b_changelist[i].col);
978 msg_outtrans(IObuff);
979 name = mark_line(&curbuf->b_changelist[i], 17);
980 if (name == NULL)
981 break;
Bram Moolenaar8820b482017-03-16 17:23:31 +0100982 msg_outtrans_attr(name, HL_ATTR(HLF_D));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000983 vim_free(name);
984 ui_breakcheck();
985 }
986 out_flush();
987 }
988 if (curwin->w_changelistidx == curbuf->b_changelistlen)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100989 msg_puts("\n>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990}
991#endif
992
993#define one_adjust(add) \
994 { \
995 lp = add; \
996 if (*lp >= line1 && *lp <= line2) \
997 { \
998 if (amount == MAXLNUM) \
999 *lp = 0; \
1000 else \
1001 *lp += amount; \
1002 } \
1003 else if (amount_after && *lp > line2) \
1004 *lp += amount_after; \
1005 }
1006
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001007// don't delete the line, just put at first deleted line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008#define one_adjust_nodel(add) \
1009 { \
1010 lp = add; \
1011 if (*lp >= line1 && *lp <= line2) \
1012 { \
1013 if (amount == MAXLNUM) \
1014 *lp = line1; \
1015 else \
1016 *lp += amount; \
1017 } \
1018 else if (amount_after && *lp > line2) \
1019 *lp += amount_after; \
1020 }
1021
1022/*
1023 * Adjust marks between line1 and line2 (inclusive) to move 'amount' lines.
1024 * Must be called before changed_*(), appended_lines() or deleted_lines().
1025 * May be called before or after changing the text.
1026 * When deleting lines line1 to line2, use an 'amount' of MAXLNUM: The marks
1027 * within this range are made invalid.
1028 * If 'amount_after' is non-zero adjust marks after line2.
1029 * Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2);
1030 * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0);
1031 * or: mark_adjust(56, 55, MAXLNUM, 2);
1032 */
1033 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001034mark_adjust(
1035 linenr_T line1,
1036 linenr_T line2,
1037 long amount,
1038 long amount_after)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039{
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001040 mark_adjust_internal(line1, line2, amount, amount_after, TRUE);
1041}
1042
1043 void
1044mark_adjust_nofold(
1045 linenr_T line1,
1046 linenr_T line2,
1047 long amount,
1048 long amount_after)
1049{
1050 mark_adjust_internal(line1, line2, amount, amount_after, FALSE);
1051}
1052
1053 static void
1054mark_adjust_internal(
1055 linenr_T line1,
1056 linenr_T line2,
1057 long amount,
1058 long amount_after,
1059 int adjust_folds UNUSED)
1060{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001061 int i;
1062 int fnum = curbuf->b_fnum;
1063 linenr_T *lp;
1064 win_T *win;
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001065 tabpage_T *tab;
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001066 static pos_T initpos = {1, 0, 0};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001068 if (line2 < line1 && amount_after == 0L) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 return;
1070
1071 if (!cmdmod.lockmarks)
1072 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001073 // named marks, lower case and upper case
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 for (i = 0; i < NMARKS; i++)
1075 {
1076 one_adjust(&(curbuf->b_namedm[i].lnum));
1077 if (namedfm[i].fmark.fnum == fnum)
1078 one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
1079 }
1080 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
1081 {
1082 if (namedfm[i].fmark.fnum == fnum)
1083 one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
1084 }
1085
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001086 // last Insert position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 one_adjust(&(curbuf->b_last_insert.lnum));
1088
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001089 // last change position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 one_adjust(&(curbuf->b_last_change.lnum));
1091
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001092 // last cursor position, if it was set
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01001093 if (!EQUAL_POS(curbuf->b_last_cursor, initpos))
Bram Moolenaarb6a76ff2013-02-06 12:33:21 +01001094 one_adjust(&(curbuf->b_last_cursor.lnum));
1095
1096
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001098 // list of change positions
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 for (i = 0; i < curbuf->b_changelistlen; ++i)
1100 one_adjust_nodel(&(curbuf->b_changelist[i].lnum));
1101#endif
1102
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001103 // Visual area
Bram Moolenaara226a6d2006-02-26 23:59:20 +00001104 one_adjust_nodel(&(curbuf->b_visual.vi_start.lnum));
1105 one_adjust_nodel(&(curbuf->b_visual.vi_end.lnum));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106
1107#ifdef FEAT_QUICKFIX
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001108 // quickfix marks
Bram Moolenaar28c258f2006-01-25 22:02:51 +00001109 qf_mark_adjust(NULL, line1, line2, amount, amount_after);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001110 // location lists
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001111 FOR_ALL_TAB_WINDOWS(tab, win)
Bram Moolenaar28c258f2006-01-25 22:02:51 +00001112 qf_mark_adjust(win, line1, line2, amount, amount_after);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001113#endif
1114
1115#ifdef FEAT_SIGNS
1116 sign_mark_adjust(line1, line2, amount, amount_after);
1117#endif
1118 }
1119
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001120 // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 one_adjust(&(curwin->w_pcmark.lnum));
1122
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001123 // previous pcmark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 one_adjust(&(curwin->w_prev_pcmark.lnum));
1125
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001126 // saved cursor for formatting
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 if (saved_cursor.lnum != 0)
1128 one_adjust_nodel(&(saved_cursor.lnum));
1129
1130 /*
1131 * Adjust items in all windows related to the current buffer.
1132 */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001133 FOR_ALL_TAB_WINDOWS(tab, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134 {
1135#ifdef FEAT_JUMPLIST
1136 if (!cmdmod.lockmarks)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001137 // Marks in the jumplist. When deleting lines, this may create
1138 // duplicate marks in the jumplist, they will be removed later.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 for (i = 0; i < win->w_jumplistlen; ++i)
1140 if (win->w_jumplist[i].fmark.fnum == fnum)
1141 one_adjust_nodel(&(win->w_jumplist[i].fmark.mark.lnum));
1142#endif
1143
1144 if (win->w_buffer == curbuf)
1145 {
1146 if (!cmdmod.lockmarks)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001147 // marks in the tag stack
Bram Moolenaar071d4272004-06-13 20:20:40 +00001148 for (i = 0; i < win->w_tagstacklen; i++)
1149 if (win->w_tagstack[i].fmark.fnum == fnum)
1150 one_adjust_nodel(&(win->w_tagstack[i].fmark.mark.lnum));
1151
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001152 // the displayed Visual area
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 if (win->w_old_cursor_lnum != 0)
1154 {
1155 one_adjust_nodel(&(win->w_old_cursor_lnum));
1156 one_adjust_nodel(&(win->w_old_visual_lnum));
1157 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001159 // topline and cursor position for windows with the same buffer
1160 // other than the current window
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161 if (win != curwin)
1162 {
1163 if (win->w_topline >= line1 && win->w_topline <= line2)
1164 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001165 if (amount == MAXLNUM) // topline is deleted
Bram Moolenaar071d4272004-06-13 20:20:40 +00001166 {
1167 if (line1 <= 1)
1168 win->w_topline = 1;
1169 else
1170 win->w_topline = line1 - 1;
1171 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001172 else // keep topline on the same line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173 win->w_topline += amount;
1174#ifdef FEAT_DIFF
1175 win->w_topfill = 0;
1176#endif
1177 }
1178 else if (amount_after && win->w_topline > line2)
1179 {
1180 win->w_topline += amount_after;
1181#ifdef FEAT_DIFF
1182 win->w_topfill = 0;
1183#endif
1184 }
1185 if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
1186 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001187 if (amount == MAXLNUM) // line with cursor is deleted
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 {
1189 if (line1 <= 1)
1190 win->w_cursor.lnum = 1;
1191 else
1192 win->w_cursor.lnum = line1 - 1;
1193 win->w_cursor.col = 0;
1194 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001195 else // keep cursor on the same line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 win->w_cursor.lnum += amount;
1197 }
1198 else if (amount_after && win->w_cursor.lnum > line2)
1199 win->w_cursor.lnum += amount_after;
1200 }
1201
1202#ifdef FEAT_FOLDING
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001203 // adjust folds
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001204 if (adjust_folds)
1205 foldMarkAdjust(win, line1, line2, amount, amount_after);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206#endif
1207 }
1208 }
1209
1210#ifdef FEAT_DIFF
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001211 // adjust diffs
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212 diff_mark_adjust(line1, line2, amount, amount_after);
1213#endif
1214}
1215
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001216// This code is used often, needs to be fast.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217#define col_adjust(pp) \
1218 { \
1219 posp = pp; \
1220 if (posp->lnum == lnum && posp->col >= mincol) \
1221 { \
1222 posp->lnum += lnum_amount; \
1223 if (col_amount < 0 && posp->col <= (colnr_T)-col_amount) \
1224 posp->col = 0; \
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001225 else if (posp->col < spaces_removed) \
1226 posp->col = col_amount + spaces_removed; \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 else \
1228 posp->col += col_amount; \
1229 } \
1230 }
1231
1232/*
1233 * Adjust marks in line "lnum" at column "mincol" and further: add
1234 * "lnum_amount" to the line number and add "col_amount" to the column
1235 * position.
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001236 * "spaces_removed" is the number of spaces that were removed, matters when the
1237 * cursor is inside them.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 */
1239 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001240mark_col_adjust(
1241 linenr_T lnum,
1242 colnr_T mincol,
1243 long lnum_amount,
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001244 long col_amount,
1245 int spaces_removed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246{
1247 int i;
1248 int fnum = curbuf->b_fnum;
1249 win_T *win;
1250 pos_T *posp;
1251
1252 if ((col_amount == 0L && lnum_amount == 0L) || cmdmod.lockmarks)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001253 return; // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001255 // named marks, lower case and upper case
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 for (i = 0; i < NMARKS; i++)
1257 {
1258 col_adjust(&(curbuf->b_namedm[i]));
1259 if (namedfm[i].fmark.fnum == fnum)
1260 col_adjust(&(namedfm[i].fmark.mark));
1261 }
1262 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
1263 {
1264 if (namedfm[i].fmark.fnum == fnum)
1265 col_adjust(&(namedfm[i].fmark.mark));
1266 }
1267
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001268 // last Insert position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 col_adjust(&(curbuf->b_last_insert));
1270
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001271 // last change position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272 col_adjust(&(curbuf->b_last_change));
1273
1274#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001275 // list of change positions
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276 for (i = 0; i < curbuf->b_changelistlen; ++i)
1277 col_adjust(&(curbuf->b_changelist[i]));
1278#endif
1279
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001280 // Visual area
Bram Moolenaara226a6d2006-02-26 23:59:20 +00001281 col_adjust(&(curbuf->b_visual.vi_start));
1282 col_adjust(&(curbuf->b_visual.vi_end));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001283
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001284 // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285 col_adjust(&(curwin->w_pcmark));
1286
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001287 // previous pcmark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288 col_adjust(&(curwin->w_prev_pcmark));
1289
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001290 // saved cursor for formatting
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291 col_adjust(&saved_cursor);
1292
1293 /*
1294 * Adjust items in all windows related to the current buffer.
1295 */
1296 FOR_ALL_WINDOWS(win)
1297 {
1298#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001299 // marks in the jumplist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 for (i = 0; i < win->w_jumplistlen; ++i)
1301 if (win->w_jumplist[i].fmark.fnum == fnum)
1302 col_adjust(&(win->w_jumplist[i].fmark.mark));
1303#endif
1304
1305 if (win->w_buffer == curbuf)
1306 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001307 // marks in the tag stack
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308 for (i = 0; i < win->w_tagstacklen; i++)
1309 if (win->w_tagstack[i].fmark.fnum == fnum)
1310 col_adjust(&(win->w_tagstack[i].fmark.mark));
1311
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001312 // cursor position for other windows with the same buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 if (win != curwin)
1314 col_adjust(&win->w_cursor);
1315 }
1316 }
1317}
1318
1319#ifdef FEAT_JUMPLIST
1320/*
1321 * When deleting lines, this may create duplicate marks in the
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001322 * jumplist. They will be removed here for the specified window.
Bram Moolenaar48679742018-02-13 13:33:29 +01001323 * When "loadfiles" is TRUE first ensure entries have the "fnum" field set
1324 * (this may be a bit slow).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325 */
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001326 void
Bram Moolenaar48679742018-02-13 13:33:29 +01001327cleanup_jumplist(win_T *wp, int loadfiles)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328{
1329 int i;
1330 int from, to;
1331
Bram Moolenaar48679742018-02-13 13:33:29 +01001332 if (loadfiles)
1333 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001334 // If specified, load all the files from the jump list. This is
1335 // needed to properly clean up duplicate entries, but will take some
1336 // time.
Bram Moolenaar48679742018-02-13 13:33:29 +01001337 for (i = 0; i < wp->w_jumplistlen; ++i)
1338 {
1339 if ((wp->w_jumplist[i].fmark.fnum == 0) &&
1340 (wp->w_jumplist[i].fmark.mark.lnum != 0))
1341 fname2fnum(&wp->w_jumplist[i]);
1342 }
1343 }
1344
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345 to = 0;
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001346 for (from = 0; from < wp->w_jumplistlen; ++from)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001347 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001348 if (wp->w_jumplistidx == from)
1349 wp->w_jumplistidx = to;
1350 for (i = from + 1; i < wp->w_jumplistlen; ++i)
1351 if (wp->w_jumplist[i].fmark.fnum
1352 == wp->w_jumplist[from].fmark.fnum
1353 && wp->w_jumplist[from].fmark.fnum != 0
1354 && wp->w_jumplist[i].fmark.mark.lnum
1355 == wp->w_jumplist[from].fmark.mark.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356 break;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001357 if (i >= wp->w_jumplistlen) // no duplicate
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001358 wp->w_jumplist[to++] = wp->w_jumplist[from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 else
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001360 vim_free(wp->w_jumplist[from].fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001361 }
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001362 if (wp->w_jumplistidx == wp->w_jumplistlen)
1363 wp->w_jumplistidx = to;
1364 wp->w_jumplistlen = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001365}
1366
Bram Moolenaar071d4272004-06-13 20:20:40 +00001367/*
1368 * Copy the jumplist from window "from" to window "to".
1369 */
1370 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001371copy_jumplist(win_T *from, win_T *to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372{
1373 int i;
1374
1375 for (i = 0; i < from->w_jumplistlen; ++i)
1376 {
1377 to->w_jumplist[i] = from->w_jumplist[i];
1378 if (from->w_jumplist[i].fname != NULL)
1379 to->w_jumplist[i].fname = vim_strsave(from->w_jumplist[i].fname);
1380 }
1381 to->w_jumplistlen = from->w_jumplistlen;
1382 to->w_jumplistidx = from->w_jumplistidx;
1383}
1384
1385/*
1386 * Free items in the jumplist of window "wp".
1387 */
1388 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001389free_jumplist(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390{
1391 int i;
1392
1393 for (i = 0; i < wp->w_jumplistlen; ++i)
1394 vim_free(wp->w_jumplist[i].fname);
1395}
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001396#endif // FEAT_JUMPLIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397
1398 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001399set_last_cursor(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001400{
Bram Moolenaar9db12932013-11-03 00:20:52 +01001401 if (win->w_buffer != NULL)
1402 win->w_buffer->b_last_cursor = win->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403}
1404
Bram Moolenaarea408852005-06-25 22:49:46 +00001405#if defined(EXITFREE) || defined(PROTO)
1406 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001407free_all_marks(void)
Bram Moolenaarea408852005-06-25 22:49:46 +00001408{
1409 int i;
1410
1411 for (i = 0; i < NMARKS + EXTRA_MARKS; i++)
1412 if (namedfm[i].fmark.mark.lnum != 0)
1413 vim_free(namedfm[i].fname);
1414}
1415#endif
1416
Bram Moolenaar2d358992016-06-12 21:20:54 +02001417/*
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001418 * Return a pointer to the named file marks.
Bram Moolenaar2d358992016-06-12 21:20:54 +02001419 */
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001420 xfmark_T *
1421get_namedfm(void)
Bram Moolenaar2d358992016-06-12 21:20:54 +02001422{
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001423 return namedfm;
Bram Moolenaar2d358992016-06-12 21:20:54 +02001424}
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001425
1426#if defined(FEAT_EVAL) || defined(PROTO)
1427/*
1428 * Add information about mark 'mname' to list 'l'
1429 */
1430 static int
1431add_mark(list_T *l, char_u *mname, pos_T *pos, int bufnr, char_u *fname)
1432{
1433 dict_T *d;
1434 list_T *lpos;
1435
1436 if (pos->lnum <= 0)
1437 return OK;
1438
1439 d = dict_alloc();
1440 if (d == NULL)
1441 return FAIL;
1442
1443 if (list_append_dict(l, d) == FAIL)
1444 {
1445 dict_unref(d);
1446 return FAIL;
1447 }
1448
1449 lpos = list_alloc();
1450 if (lpos == NULL)
1451 return FAIL;
1452
1453 list_append_number(lpos, bufnr);
1454 list_append_number(lpos, pos->lnum);
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +02001455 list_append_number(lpos, pos->col + 1);
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001456 list_append_number(lpos, pos->coladd);
1457
1458 if (dict_add_string(d, "mark", mname) == FAIL
1459 || dict_add_list(d, "pos", lpos) == FAIL
1460 || (fname != NULL && dict_add_string(d, "file", fname) == FAIL))
1461 return FAIL;
1462
1463 return OK;
1464}
1465
1466/*
1467 * Get information about marks local to a buffer.
1468 */
1469 static void
1470get_buf_local_marks(buf_T *buf, list_T *l)
1471{
1472 char_u mname[3] = "' ";
1473 int i;
1474
1475 // Marks 'a' to 'z'
1476 for (i = 0; i < NMARKS; ++i)
1477 {
1478 mname[1] = 'a' + i;
1479 add_mark(l, mname, &buf->b_namedm[i], buf->b_fnum, NULL);
1480 }
1481
1482 // Mark '' is a window local mark and not a buffer local mark
1483 add_mark(l, (char_u *)"''", &curwin->w_pcmark, curbuf->b_fnum, NULL);
1484
1485 add_mark(l, (char_u *)"'\"", &buf->b_last_cursor, buf->b_fnum, NULL);
1486 add_mark(l, (char_u *)"'[", &buf->b_op_start, buf->b_fnum, NULL);
1487 add_mark(l, (char_u *)"']", &buf->b_op_end, buf->b_fnum, NULL);
1488 add_mark(l, (char_u *)"'^", &buf->b_last_insert, buf->b_fnum, NULL);
1489 add_mark(l, (char_u *)"'.", &buf->b_last_change, buf->b_fnum, NULL);
1490 add_mark(l, (char_u *)"'<", &buf->b_visual.vi_start, buf->b_fnum, NULL);
1491 add_mark(l, (char_u *)"'>", &buf->b_visual.vi_end, buf->b_fnum, NULL);
1492}
1493
1494/*
1495 * Get information about global marks ('A' to 'Z' and '0' to '9')
1496 */
1497 static void
1498get_global_marks(list_T *l)
1499{
1500 char_u mname[3] = "' ";
1501 int i;
1502 char_u *name;
1503
1504 // Marks 'A' to 'Z' and '0' to '9'
1505 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
1506 {
1507 if (namedfm[i].fmark.fnum != 0)
1508 name = buflist_nr2name(namedfm[i].fmark.fnum, TRUE, TRUE);
1509 else
1510 name = namedfm[i].fname;
1511 if (name != NULL)
1512 {
1513 mname[1] = i >= NMARKS ? i - NMARKS + '0' : i + 'A';
1514 add_mark(l, mname, &namedfm[i].fmark.mark,
1515 namedfm[i].fmark.fnum, name);
1516 if (namedfm[i].fmark.fnum != 0)
1517 vim_free(name);
1518 }
1519 }
1520}
1521
1522/*
1523 * getmarklist() function
1524 */
1525 void
1526f_getmarklist(typval_T *argvars, typval_T *rettv)
1527{
1528 buf_T *buf = NULL;
1529
1530 if (rettv_list_alloc(rettv) != OK)
1531 return;
1532
1533 if (argvars[0].v_type == VAR_UNKNOWN)
1534 {
1535 get_global_marks(rettv->vval.v_list);
1536 return;
1537 }
1538
1539 buf = tv_get_buf(&argvars[0], FALSE);
1540 if (buf == NULL)
1541 return;
1542
1543 get_buf_local_marks(buf, rettv->vval.v_list);
1544}
1545#endif