aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/quickfix.c
diff options
context:
space:
mode:
authorFlorian Walch <florian@fwalch.com>2015-12-03 20:14:51 +0100
committerFlorian Walch <florian@fwalch.com>2015-12-24 08:08:50 +0100
commit7f99d210fd6bf92619f295a439ee4ac7e1a8f353 (patch)
tree9e40030f51d4d157e3b01825dfd645d2c500ba6e /src/nvim/quickfix.c
parent25eaacd10fea833c1f915a9ae69678d3d1dc7501 (diff)
downloadrneovim-7f99d210fd6bf92619f295a439ee4ac7e1a8f353.tar.gz
rneovim-7f99d210fd6bf92619f295a439ee4ac7e1a8f353.tar.bz2
rneovim-7f99d210fd6bf92619f295a439ee4ac7e1a8f353.zip
vim-patch:7.4.858
Problem: It's a bit clumsy to execute a command on a list of matches. Solution: Add the ":ldo", ":lfdo", ":cdo" and ":cfdo" commands. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/aa23b379421aa214e6543b06c974594a25799b09
Diffstat (limited to 'src/nvim/quickfix.c')
-rw-r--r--src/nvim/quickfix.c220
1 files changed, 204 insertions, 16 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 8e6ae46a3b..3abf43cb8c 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1202,7 +1202,7 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
/*
* Check in which directory of the directory stack the given file can be
* found.
- * Returns a pointer to the directory name or NULL if not found
+ * Returns a pointer to the directory name or NULL if not found.
* Cleans up intermediate directory entries.
*
* TODO: How to solve the following problem?
@@ -2571,9 +2571,159 @@ static char_u *get_mef_name(void)
return name;
}
+/// Returns the number of valid entries in the current quickfix/location list.
+size_t qf_get_size(exarg_T *eap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ qf_info_T *qi = &ql_info;
+ if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) {
+ // Location list.
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL) {
+ return 0;
+ }
+ }
+
+ int prev_fnum = 0;
+ size_t sz = 0;
+ qfline_T *qfp;
+ size_t i;
+ assert(qi->qf_lists[qi->qf_curlist].qf_count >= 0);
+ for (i = 0, qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+ i < (size_t)qi->qf_lists[qi->qf_curlist].qf_count && qfp != NULL;
+ i++, qfp = qfp->qf_next) {
+ if (!qfp->qf_valid) {
+ continue;
+ }
+
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo) {
+ // Count all valid entries.
+ sz++;
+ } else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) {
+ // Count the number of files.
+ sz++;
+ prev_fnum = qfp->qf_fnum;
+ }
+ }
+
+ return sz;
+}
+
+/// Returns the current index of the quickfix/location list.
+/// Returns 0 if there is an error.
+size_t qf_get_cur_idx(exarg_T *eap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ qf_info_T *qi = &ql_info;
+
+ if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) {
+ // Location list.
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL) {
+ return 0;
+ }
+ }
+
+ assert(qi->qf_lists[qi->qf_curlist].qf_index >= 0);
+ return (size_t)qi->qf_lists[qi->qf_curlist].qf_index;
+}
+
+/// Returns the current index in the quickfix/location list,
+/// counting only valid entries.
+/// Returns 1 if there are no valid entries.
+int qf_get_cur_valid_idx(exarg_T *eap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ qf_info_T *qi = &ql_info;
+
+ if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) {
+ // Location list.
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL) {
+ return 1;
+ }
+ }
+
+ qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
+
+ // Check if the list has valid errors.
+ if (qfl->qf_count <= 0 || qfl->qf_nonevalid) {
+ return 1;
+ }
+
+ int prev_fnum = 0;
+ int eidx = 0;
+ qfline_T *qfp;
+ size_t i;
+ assert(qfl->qf_index >= 0);
+ for (i = 1, qfp = qfl->qf_start;
+ i <= (size_t)qfl->qf_index && qfp != NULL;
+ i++, qfp = qfp->qf_next) {
+ if (!qfp->qf_valid) {
+ continue;
+ }
+
+ if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
+ if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) {
+ // Count the number of files.
+ eidx++;
+ prev_fnum = qfp->qf_fnum;
+ }
+ } else {
+ eidx++;
+ }
+ }
+
+ return eidx != 0 ? eidx : 1;
+}
+
+/// Get the 'n'th valid error entry in the quickfix or location list.
+///
+/// Used by :cdo, :ldo, :cfdo and :lfdo commands.
+/// For :cdo and :ldo, returns the 'n'th valid error entry.
+/// For :cfdo and :lfdo, returns the 'n'th valid file entry.
+static size_t qf_get_nth_valid_entry(qf_info_T *qi, size_t n, bool fdo)
+ FUNC_ATTR_NONNULL_ALL
+{
+ qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
+
+ // Check if the list has valid errors.
+ if (qfl->qf_count <= 0 || qfl->qf_nonevalid) {
+ return 1;
+ }
+
+ int prev_fnum = 0;
+ size_t eidx = 0;
+ size_t i;
+ qfline_T *qfp;
+ assert(qfl->qf_count >= 0);
+ for (i = 1, qfp = qfl->qf_start;
+ i <= (size_t)qfl->qf_count && qfp != NULL;
+ i++, qfp = qfp->qf_next) {
+ if (qfp->qf_valid) {
+ if (fdo) {
+ if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) {
+ // Count the number of files.
+ eidx++;
+ prev_fnum = qfp->qf_fnum;
+ }
+ } else {
+ eidx++;
+ }
+ }
+
+ if (eidx == n) {
+ break;
+ }
+ }
+
+ return i <= (size_t)qfl->qf_count ? i : 1;
+}
+
/*
* ":cc", ":crewind", ":cfirst" and ":clast".
* ":ll", ":lrewind", ":lfirst" and ":llast".
+ * ":cdo", ":ldo", ":cfdo" and ":lfdo".
*/
void ex_cc(exarg_T *eap)
{
@@ -2582,7 +2732,10 @@ void ex_cc(exarg_T *eap)
if (eap->cmdidx == CMD_ll
|| eap->cmdidx == CMD_lrewind
|| eap->cmdidx == CMD_lfirst
- || eap->cmdidx == CMD_llast) {
+ || eap->cmdidx == CMD_llast
+ || eap->cmdidx == CMD_llast
+ || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_lfdo) {
qi = GET_LOC_LIST(curwin);
if (qi == NULL) {
EMSG(_(e_loclist));
@@ -2590,21 +2743,42 @@ void ex_cc(exarg_T *eap)
}
}
- qf_jump(qi, 0,
- eap->addr_count > 0
- ? (int)eap->line2
- : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)
- ? 0
- : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
- || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)
- ? 1
- : 32767,
- eap->forceit);
+ int errornr;
+ if (eap->addr_count > 0) {
+ errornr = (int)eap->line2;
+ } else if (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) {
+ errornr = 0;
+ } else if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
+ || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) {
+ errornr = 1;
+ } else {
+ errornr = 32767;
+ }
+
+ // For cdo and ldo commands, jump to the nth valid error.
+ // For cfdo and lfdo commands, jump to the nth valid file entry.
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
+ eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
+ size_t n;
+ if (eap->addr_count > 0) {
+ assert(eap->line1 >= 0);
+ n = (size_t)eap->line1;
+ } else {
+ n = 1;
+ }
+ size_t valid_entry = qf_get_nth_valid_entry(qi, n,
+ eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
+ assert(valid_entry <= INT_MAX);
+ errornr = (int)valid_entry;
+ }
+
+ qf_jump(qi, 0, errornr, eap->forceit);
}
/*
* ":cnext", ":cnfile", ":cNext" and ":cprevious".
* ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
+ * ":cdo", ":ldo", ":cfdo" and ":lfdo".
*/
void ex_cnext(exarg_T *eap)
{
@@ -2615,7 +2789,10 @@ void ex_cnext(exarg_T *eap)
|| eap->cmdidx == CMD_lprevious
|| eap->cmdidx == CMD_lnfile
|| eap->cmdidx == CMD_lNfile
- || eap->cmdidx == CMD_lpfile) {
+ || eap->cmdidx == CMD_lpfile
+ || eap->cmdidx == CMD_lpfile
+ || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_lfdo) {
qi = GET_LOC_LIST(curwin);
if (qi == NULL) {
EMSG(_(e_loclist));
@@ -2623,15 +2800,26 @@ void ex_cnext(exarg_T *eap)
}
}
- qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext)
+ int errornr;
+ if (eap->addr_count > 0 &&
+ (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo &&
+ eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) {
+ errornr = (int)eap->line2;
+ } else {
+ errornr = 1;
+ }
+
+ qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext
+ || eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
? FORWARD
- : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile)
+ : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
? FORWARD_FILE
: (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile
|| eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile)
? BACKWARD_FILE
: BACKWARD,
- eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit);
+ errornr, eap->forceit);
}
/*