summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-09-02 15:18:42 +0200
committerBram Moolenaar <Bram@vim.org>2018-09-02 15:18:42 +0200
commitc9cc9c78f21caba7ecb5c90403df5e19a57aa96a (patch)
tree50b8f0fe00446fec89b1ef0e5f9c9064fe7b1182
parent7ee3f15b21042cb8148980ea486137eaf1b55bcd (diff)
patch 8.1.0345: cannot get the window id associated with the location listv8.1.0345
Problem: Cannot get the window id associated with the location list. Solution: Add the "filewinid" argument to getloclist(). (Yegappan Lakshmanan, closes #3202)
-rw-r--r--runtime/doc/eval.txt4
-rw-r--r--src/quickfix.c39
-rw-r--r--src/testdir/test_quickfix.vim46
-rw-r--r--src/version.c2
4 files changed, 85 insertions, 6 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index e838395639..b8ab0f3082 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -4729,6 +4729,10 @@ getloclist({nr} [, {what}]) *getloclist()*
If the optional {what} dictionary argument is supplied, then
returns the items listed in {what} as a dictionary. Refer to
|getqflist()| for the supported items in {what}.
+ If {what} contains 'filewinid', then returns the id of the
+ window used to display files from the location list. This
+ field is applicable only when called from a location list
+ window.
getmatches() *getmatches()*
Returns a |List| with all matches previously defined by
diff --git a/src/quickfix.c b/src/quickfix.c
index fe333766df..58163196e0 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -5670,7 +5670,8 @@ enum {
QF_GETLIST_IDX = 0x40,
QF_GETLIST_SIZE = 0x80,
QF_GETLIST_TICK = 0x100,
- QF_GETLIST_ALL = 0x1FF,
+ QF_GETLIST_FILEWINID = 0x200,
+ QF_GETLIST_ALL = 0x3FF,
};
/*
@@ -5744,12 +5745,17 @@ qf_winid(qf_info_T *qi)
* Convert the keys in 'what' to quickfix list property flags.
*/
static int
-qf_getprop_keys2flags(dict_T *what)
+qf_getprop_keys2flags(dict_T *what, int loclist)
{
int flags = QF_GETLIST_NONE;
if (dict_find(what, (char_u *)"all", -1) != NULL)
+ {
flags |= QF_GETLIST_ALL;
+ if (!loclist)
+ // File window ID is applicable only to location list windows
+ flags &= ~ QF_GETLIST_FILEWINID;
+ }
if (dict_find(what, (char_u *)"title", -1) != NULL)
flags |= QF_GETLIST_TITLE;
@@ -5778,6 +5784,9 @@ qf_getprop_keys2flags(dict_T *what)
if (dict_find(what, (char_u *)"changedtick", -1) != NULL)
flags |= QF_GETLIST_TICK;
+ if (loclist && dict_find(what, (char_u *)"filewinid", -1) != NULL)
+ flags |= QF_GETLIST_FILEWINID;
+
return flags;
}
@@ -5870,6 +5879,8 @@ qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict)
status = dict_add_number(retdict, "size", 0);
if ((status == OK) && (flags & QF_GETLIST_TICK))
status = dict_add_number(retdict, "changedtick", 0);
+ if ((status == OK) && (qi != &ql_info) && (flags & QF_GETLIST_FILEWINID))
+ status = dict_add_number(retdict, "filewinid", 0);
return status;
}
@@ -5884,6 +5895,26 @@ qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict)
}
/*
+ * Returns the identifier of the window used to display files from a location
+ * list. If there is no associated window, then returns 0. Useful only when
+ * called from a location list window.
+ */
+ static int
+qf_getprop_filewinid(win_T *wp, qf_info_T *qi, dict_T *retdict)
+{
+ int winid = 0;
+
+ if (wp != NULL && IS_LL_WINDOW(wp))
+ {
+ win_T *ll_wp = qf_find_win_with_loclist(qi);
+ if (ll_wp != NULL)
+ winid = ll_wp->w_id;
+ }
+
+ return dict_add_number(retdict, "filewinid", winid);
+}
+
+/*
* Return the quickfix list items/entries as 'items' in retdict
*/
static int
@@ -5963,7 +5994,7 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
if (wp != NULL)
qi = GET_LOC_LIST(wp);
- flags = qf_getprop_keys2flags(what);
+ flags = qf_getprop_keys2flags(what, (wp != NULL));
if (qi != NULL && qi->qf_listcount != 0)
qf_idx = qf_getprop_qfidx(qi, what);
@@ -5992,6 +6023,8 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
if ((status == OK) && (flags & QF_GETLIST_TICK))
status = dict_add_number(retdict, "changedtick",
qi->qf_lists[qf_idx].qf_changedtick);
+ if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID))
+ status = qf_getprop_filewinid(wp, qi, retdict);
return status;
}
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 36982c2298..2b3c1a0ec8 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -1973,6 +1973,18 @@ func Xproperty_tests(cchar)
call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]})
call assert_equal('TestTitle', g:Xgetlist({'title' : 1}).title)
+ " Test for getting id of window associated with a location list window
+ if a:cchar == 'l'
+ only
+ call assert_equal(0, g:Xgetlist({'all' : 1}).filewinid)
+ let wid = win_getid()
+ Xopen
+ call assert_equal(wid, g:Xgetlist({'filewinid' : 1}).filewinid)
+ wincmd w
+ call assert_equal(0, g:Xgetlist({'filewinid' : 1}).filewinid)
+ only
+ endif
+
" The following used to crash Vim with address sanitizer
call g:Xsetlist([], 'f')
call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]})
@@ -3000,7 +3012,17 @@ func Xgetlist_empty_tests(cchar)
call assert_equal('', g:Xgetlist({'title' : 0}).title)
call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick)
- call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, 'changedtick': 0}, g:Xgetlist({'all' : 0}))
+ if a:cchar == 'c'
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
+ \ 'items' : [], 'nr' : 0, 'size' : 0,
+ \ 'title' : '', 'winid' : 0, 'changedtick': 0},
+ \ g:Xgetlist({'all' : 0}))
+ else
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
+ \ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '',
+ \ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0},
+ \ g:Xgetlist({'all' : 0}))
+ endif
" Quickfix window with empty stack
silent! Xopen
@@ -3033,7 +3055,16 @@ func Xgetlist_empty_tests(cchar)
call assert_equal('', g:Xgetlist({'id' : qfid, 'title' : 0}).title)
call assert_equal(0, g:Xgetlist({'id' : qfid, 'winid' : 0}).winid)
call assert_equal(0, g:Xgetlist({'id' : qfid, 'changedtick' : 0}).changedtick)
- call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
+ if a:cchar == 'c'
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
+ else
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0, 'filewinid' : 0},
+ \ g:Xgetlist({'id' : qfid, 'all' : 0}))
+ endif
" Non-existing quickfix list number
call assert_equal('', g:Xgetlist({'nr' : 5, 'context' : 0}).context)
@@ -3045,7 +3076,16 @@ func Xgetlist_empty_tests(cchar)
call assert_equal('', g:Xgetlist({'nr' : 5, 'title' : 0}).title)
call assert_equal(0, g:Xgetlist({'nr' : 5, 'winid' : 0}).winid)
call assert_equal(0, g:Xgetlist({'nr' : 5, 'changedtick' : 0}).changedtick)
- call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, 'changedtick' : 0}, g:Xgetlist({'nr' : 5, 'all' : 0}))
+ if a:cchar == 'c'
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0}, g:Xgetlist({'nr' : 5, 'all' : 0}))
+ else
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0, 'filewinid' : 0},
+ \ g:Xgetlist({'nr' : 5, 'all' : 0}))
+ endif
endfunc
func Test_getqflist()
diff --git a/src/version.c b/src/version.c
index b1e76e50a0..5d4845dfe6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -795,6 +795,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 345,
+/**/
344,
/**/
343,
class="w"> struct cmd_entry cmd_pipe_pane_entry = { .name = "pipe-pane", .alias = "pipep", .args = { "IOot:", 0, 1 }, .usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]", .target = { 't', CMD_FIND_PANE, 0 }, .flags = CMD_AFTERHOOK, .exec = cmd_pipe_pane_exec }; static enum cmd_retval cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); struct client *tc = cmdq_get_target_client(item); struct window_pane *wp = target->wp; struct session *s = target->s; struct winlink *wl = target->wl; struct window_pane_offset *wpo = &wp->pipe_offset; char *cmd; int old_fd, pipe_fd[2], null_fd, in, out; struct format_tree *ft; sigset_t set, oldset; /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; if (window_pane_destroy_ready(wp)) { server_destroy_pane(wp, 1); return (CMD_RETURN_NORMAL); } } /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') return (CMD_RETURN_NORMAL); /* * With -o, only open the new pipe if there was no previous one. This * allows a pipe to be toggled with a single key, for example: * * bind ^p pipep -o 'cat >>~/output' */ if (args_has(args, 'o') && old_fd != -1) return (CMD_RETURN_NORMAL); /* What do we want to do? Neither -I or -O is -O. */ if (args_has(args, 'I')) { in = 1; out = args_has(args, 'O'); } else { in = 0; out = 1; } /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { cmdq_error(item, "socketpair error: %s", strerror(errno)); return (CMD_RETURN_ERROR); } /* Expand the command. */ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); format_defaults(ft, tc, s, wl, wp); cmd = format_expand_time(ft, args->argv[0]); format_free(ft); /* Fork the child. */ sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); switch (fork()) { case -1: sigprocmask(SIG_SETMASK, &oldset, NULL); cmdq_error(item, "fork error: %s", strerror(errno)); free(cmd); return (CMD_RETURN_ERROR); case 0: /* Child process. */ proc_clear_signals(server_proc, 1); sigprocmask(SIG_SETMASK, &oldset, NULL); close(pipe_fd[0]); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); if (out) { if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); } else { if (dup2(null_fd, STDIN_FILENO) == -1) _exit(1); } if (in) { if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) _exit(1); if (pipe_fd[1] != STDOUT_FILENO) close(pipe_fd[1]); } else { if (dup2(null_fd, STDOUT_FILENO) == -1) _exit(1); } if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); _exit(1); default: /* Parent process. */ sigprocmask(SIG_SETMASK, &oldset, NULL); close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; memcpy(wpo, &wp->offset, sizeof *wpo); setblocking(wp->pipe_fd, 0); wp->pipe_event = bufferevent_new(wp->pipe_fd, cmd_pipe_pane_read_callback, cmd_pipe_pane_write_callback, cmd_pipe_pane_error_callback, wp); if (wp->pipe_event == NULL) fatalx("out of memory"); if (out) bufferevent_enable(wp->pipe_event, EV_WRITE); if (in) bufferevent_enable(wp->pipe_event, EV_READ); free(cmd); return (CMD_RETURN_NORMAL); } } static void cmd_pipe_pane_read_callback(__unused struct bufferevent *bufev, void *data) { struct window_pane *wp = data; struct evbuffer *evb = wp->pipe_event->input; size_t available; available = EVBUFFER_LENGTH(evb); log_debug("%%%u pipe read %zu", wp->id, available); bufferevent_write(wp->event, EVBUFFER_DATA(evb), available); evbuffer_drain(evb, available); if (window_pane_destroy_ready(wp)) server_destroy_pane(wp, 1); } static void cmd_pipe_pane_write_callback(__unused struct bufferevent *bufev, void *data) { struct window_pane *wp = data; log_debug("%%%u pipe empty", wp->id); if (window_pane_destroy_ready(wp)) server_destroy_pane(wp, 1); } static void cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev, __unused short what, void *data) { struct window_pane *wp = data; log_debug("%%%u pipe error", wp->id); bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; if (window_pane_destroy_ready(wp)) server_destroy_pane(wp, 1); }