diff options
Diffstat (limited to 'src/nvim/mark.c')
-rw-r--r-- | src/nvim/mark.c | 170 |
1 files changed, 125 insertions, 45 deletions
diff --git a/src/nvim/mark.c b/src/nvim/mark.c index fe802e48ba..05f78c76bc 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + /* * mark.c: functions for setting marks and jumping to them */ @@ -21,7 +24,6 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/misc2.h" #include "nvim/normal.h" #include "nvim/option.h" #include "nvim/path.h" @@ -63,7 +65,7 @@ int setmark(int c) /// Free fmark_T item void free_fmark(fmark_T fm) { - dict_unref(fm.additional_data); + tv_dict_unref(fm.additional_data); } /// Free xfmark_T item @@ -104,44 +106,52 @@ int setmark_pos(int c, pos_T *pos, int fnum) return OK; } + // Can't set a mark in a non-existant buffer. + buf_T *buf = buflist_findnr(fnum); + if (buf == NULL) { + return FAIL; + } + if (c == '"') { - RESET_FMARK(&curbuf->b_last_cursor, *pos, curbuf->b_fnum); + RESET_FMARK(&buf->b_last_cursor, *pos, buf->b_fnum); return OK; } /* Allow setting '[ and '] for an autocommand that simulates reading a * file. */ if (c == '[') { - curbuf->b_op_start = *pos; + buf->b_op_start = *pos; return OK; } if (c == ']') { - curbuf->b_op_end = *pos; + buf->b_op_end = *pos; return OK; } if (c == '<' || c == '>') { - if (c == '<') - curbuf->b_visual.vi_start = *pos; - else - curbuf->b_visual.vi_end = *pos; - if (curbuf->b_visual.vi_mode == NUL) - /* Visual_mode has not yet been set, use a sane default. */ - curbuf->b_visual.vi_mode = 'v'; + if (c == '<') { + buf->b_visual.vi_start = *pos; + } else { + buf->b_visual.vi_end = *pos; + } + if (buf->b_visual.vi_mode == NUL) { + // Visual_mode has not yet been set, use a sane default. + buf->b_visual.vi_mode = 'v'; + } return OK; } - if (c > 'z') /* some islower() and isupper() cannot handle - characters above 127 */ - return FAIL; - if (islower(c)) { + if (ASCII_ISLOWER(c)) { i = c - 'a'; - RESET_FMARK(curbuf->b_namedm + i, *pos, curbuf->b_fnum); + RESET_FMARK(buf->b_namedm + i, *pos, fnum); return OK; } - if (isupper(c)) { - assert(c >= 'A' && c <= 'Z'); - i = c - 'A'; + if (ASCII_ISUPPER(c) || ascii_isdigit(c)) { + if (ascii_isdigit(c)) { + i = c - '0' + NMARKS; + } else { + i = c - 'A'; + } RESET_XFMARK(namedfm + i, *pos, fnum, NULL); return OK; } @@ -163,6 +173,10 @@ void setpcmark(void) curwin->w_prev_pcmark = curwin->w_pcmark; curwin->w_pcmark = curwin->w_cursor; + if (curwin->w_pcmark.lnum == 0) { + curwin->w_pcmark.lnum = 1; + } + /* If jumplist is full: remove oldest entry */ if (++curwin->w_jumplistlen > JUMPLISTSIZE) { curwin->w_jumplistlen = JUMPLISTSIZE; @@ -346,13 +360,14 @@ pos_T *getmark_buf_fnum(buf_T *buf, int c, int changefile, int *fnum) } else if (c == '<' || c == '>') { /* start/end of visual area */ startp = &buf->b_visual.vi_start; endp = &buf->b_visual.vi_end; - if ((c == '<') == lt(*startp, *endp)) + if (((c == '<') == lt(*startp, *endp) || endp->lnum == 0) + && startp->lnum != 0) { posp = startp; - else + } else { posp = endp; - /* - * For Visual line mode, set mark at begin or end of line - */ + } + + // For Visual line mode, set mark at begin or end of line if (buf->b_visual.vi_mode == 'V') { pos_copy = *posp; posp = &pos_copy; @@ -474,7 +489,7 @@ static void fname2fnum(xfmark_T *fm) os_dirname(IObuff, IOSIZE); p = path_shorten_fname(NameBuff, IObuff); - /* buflist_new() will call fmarks_check_names() */ + // buflist_new() will call fmarks_check_names() (void)buflist_new(NameBuff, p, (linenr_T)1, 0); } } @@ -584,11 +599,12 @@ static char_u *mark_line(pos_T *mp, int lead_len) if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count) return vim_strsave((char_u *)"-invalid-"); assert(Columns >= 0 && (size_t)Columns <= SIZE_MAX); - s = vim_strnsave(skipwhite(ml_get(mp->lnum)), (size_t)Columns); + // Allow for up to 5 bytes per character. + s = vim_strnsave(skipwhite(ml_get(mp->lnum)), (size_t)Columns * 5); - /* Truncate the line to fit it in the window */ + // Truncate the line to fit it in the window len = 0; - for (p = s; *p != NUL; mb_ptr_adv(p)) { + for (p = s; *p != NUL; MB_PTR_ADV(p)) { len += ptr2cells(p); if (len >= Columns - lead_len) break; @@ -635,8 +651,8 @@ void do_marks(exarg_T *eap) show_one_mark(-1, arg, NULL, NULL, false); } -static void -show_one_mark ( +static void +show_one_mark( int c, char_u *arg, pos_T *p, @@ -675,9 +691,10 @@ show_one_mark ( mustfree = TRUE; } if (name != NULL) { - msg_outtrans_attr(name, current ? hl_attr(HLF_D) : 0); - if (mustfree) + msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0); + if (mustfree) { xfree(name); + } } } ui_flush(); /* show one line at a time */ @@ -788,8 +805,8 @@ void ex_jumps(exarg_T *eap) curwin->w_jumplist[i].fmark.mark.col); msg_outtrans(IObuff); msg_outtrans_attr(name, - curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum - ? hl_attr(HLF_D) : 0); + curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum + ? HL_ATTR(HLF_D) : 0); xfree(name); os_breakcheck(); } @@ -799,6 +816,13 @@ void ex_jumps(exarg_T *eap) MSG_PUTS("\n>"); } +void ex_clearjumps(exarg_T *eap) +{ + free_jumplist(curwin); + curwin->w_jumplistlen = 0; + curwin->w_jumplistidx = 0; +} + /* * print the changelist */ @@ -807,7 +831,7 @@ void ex_changes(exarg_T *eap) int i; char_u *name; - /* Highlight title */ + // Highlight title MSG_PUTS_TITLE(_("\nchange line col text")); for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i) { @@ -823,7 +847,7 @@ void ex_changes(exarg_T *eap) curbuf->b_changelist[i].mark.col); msg_outtrans(IObuff); name = mark_line(&curbuf->b_changelist[i].mark, 17); - msg_outtrans_attr(name, hl_attr(HLF_D)); + msg_outtrans_attr(name, HL_ATTR(HLF_D)); xfree(name); os_breakcheck(); } @@ -873,7 +897,29 @@ void ex_changes(exarg_T *eap) * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0); * or: mark_adjust(56, 55, MAXLNUM, 2); */ -void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after) +void mark_adjust(linenr_T line1, + linenr_T line2, + long amount, + long amount_after, + bool end_temp) +{ + mark_adjust_internal(line1, line2, amount, amount_after, true, end_temp); +} + +// mark_adjust_nofold() does the same as mark_adjust() but without adjusting +// folds in any way. Folds must be adjusted manually by the caller. +// This is only useful when folds need to be moved in a way different to +// calling foldMarkAdjust() with arguments line1, line2, amount, amount_after, +// for an example of why this may be necessary, see do_move(). +void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount, + long amount_after, bool end_temp) +{ + mark_adjust_internal(line1, line2, amount, amount_after, false, end_temp); +} + +static void mark_adjust_internal(linenr_T line1, linenr_T line2, + long amount, long amount_after, + bool adjust_folds, bool end_temp) { int i; int fnum = curbuf->b_fnum; @@ -914,15 +960,21 @@ void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after) one_adjust_nodel(&(curbuf->b_visual.vi_start.lnum)); one_adjust_nodel(&(curbuf->b_visual.vi_end.lnum)); - /* quickfix marks */ - qf_mark_adjust(NULL, line1, line2, amount, amount_after); - /* location lists */ + // quickfix marks + if (!qf_mark_adjust(NULL, line1, line2, amount, amount_after)) { + curbuf->b_has_qf_entry &= ~BUF_HAS_QF_ENTRY; + } + // location lists + bool found_one = false; FOR_ALL_TAB_WINDOWS(tab, win) { - qf_mark_adjust(win, line1, line2, amount, amount_after); + found_one |= qf_mark_adjust(win, line1, line2, amount, amount_after); + } + if (!found_one) { + curbuf->b_has_qf_entry &= ~BUF_HAS_LL_ENTRY; } sign_mark_adjust(line1, line2, amount, amount_after); - bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after); + bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after, end_temp); } /* previous context mark */ @@ -999,8 +1051,9 @@ void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after) } } - /* adjust folds */ - foldMarkAdjust(win, line1, line2, amount, amount_after); + if (adjust_folds) { + foldMarkAdjust(win, line1, line2, amount, amount_after); + } } } @@ -1401,3 +1454,30 @@ void free_all_marks(void) memset(&namedfm[0], 0, sizeof(namedfm)); } #endif + +/// Adjust position to point to the first byte of a multi-byte character +/// +/// If it points to a tail byte it is move backwards to the head byte. +/// +/// @param[in] buf Buffer to adjust position in. +/// @param[out] lp Position to adjust. +void mark_mb_adjustpos(buf_T *buf, pos_T *lp) + FUNC_ATTR_NONNULL_ALL +{ + if (lp->col > 0 || lp->coladd > 1) { + const char_u *const p = ml_get_buf(buf, lp->lnum, false); + if (*p == NUL || (int)STRLEN(p) < lp->col) { + lp->col = 0; + } else { + lp->col -= utf_head_off(p, p + lp->col); + } + // Reset "coladd" when the cursor would be on the right half of a + // double-wide character. + if (lp->coladd == 1 + && p[lp->col] != TAB + && vim_isprintc(utf_ptr2char(p + lp->col)) + && ptr2cells(p + lp->col) > 1) { + lp->coladd = 0; + } + } +} |