aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt30
-rw-r--r--src/nvim/eval.c19
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/testdir/test_window_id.vim20
-rw-r--r--src/nvim/window.c35
5 files changed, 105 insertions, 0 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 7682a1a584..32783f0851 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2377,6 +2377,7 @@ win_screenpos({nr}) List get screen position of window {nr}
winbufnr({nr}) Number buffer number of window {nr}
wincol() Number window column of the cursor
winheight({nr}) Number height of window {nr}
+winlayout([{tabnr}]) List layout of windows in tab {tabnr}
winline() Number window line of the cursor
winnr([{expr}]) Number number of current window
winrestcmd() String returns command to restore window sizes
@@ -8538,6 +8539,35 @@ winheight({nr}) *winheight()*
Examples: >
:echo "The current window has " . winheight(0) . " lines."
<
+winlayout([{tabnr}]) *winlayout()*
+ The result is a nested List containing the layout of windows
+ in a tabpage.
+
+ Without {tabnr} use the current tabpage, otherwise the tabpage
+ with number {tabnr}. If the tabpage {tabnr} is not found,
+ returns an empty list.
+
+ For a leaf window, it returns:
+ ['leaf', {winid}]
+ For horizontally split windows, which form a column, it
+ returns:
+ ['col', [{nested list of windows}]]
+ For vertically split windows, which form a row, it returns:
+ ['row', [{nested list of windows}]]
+
+ Example: >
+ " Only one window in the tab page
+ :echo winlayout()
+ ['leaf', 1000]
+ " Two horizontally split windows
+ :echo winlayout()
+ ['col', [['leaf', 1000], ['leaf', 1001]]]
+ " Three horizontally split windows, with two
+ " vertically split windows in the middle window
+ :echo winlayout(2)
+ ['col', [['leaf', 1002], ['row', ['leaf', 1003],
+ ['leaf', 1001]]], ['leaf', 1000]]
+<
*winline()*
winline() The result is a Number, which is the screen line of the cursor
in the window. This is counting screen lines from the top of
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 78a6092fa1..868305c88d 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -17872,6 +17872,25 @@ static void f_winheight(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "winlayout()" function
+static void f_winlayout(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tabpage_T *tp;
+
+ tv_list_alloc_ret(rettv, 2);
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ tp = curtab;
+ } else {
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
+ return;
+ }
+ }
+
+ get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
+}
+
/*
* "winline()" function
*/
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index aad2de5d30..dea00c3edd 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -352,6 +352,7 @@ return {
winbufnr={args=1},
wincol={},
winheight={args=1},
+ winlayout={args={0, 1}},
winline={},
winnr={args={0, 1}},
winrestcmd={},
diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim
index b3b506d04d..d10d831650 100644
--- a/src/nvim/testdir/test_window_id.vim
+++ b/src/nvim/testdir/test_window_id.vim
@@ -101,3 +101,23 @@ func Test_win_getid_curtab()
call assert_equal(win_getid(1), win_getid(1, 1))
tabclose!
endfunc
+
+func Test_winlayout()
+ let w1 = win_getid()
+ call assert_equal(['leaf', w1], winlayout())
+
+ split
+ let w2 = win_getid()
+ call assert_equal(['col', [['leaf', w2], ['leaf', w1]]], winlayout())
+
+ split
+ let w3 = win_getid()
+ call assert_equal(['col', [['leaf', w3], ['leaf', w2], ['leaf', w1]]], winlayout())
+
+ 2wincmd w
+ vsplit
+ let w4 = win_getid()
+ call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout())
+
+ only!
+endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 2ce3b7067b..e6b19cf88d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6658,6 +6658,41 @@ void win_findbuf(typval_T *argvars, list_T *list)
}
}
+// Get the layout of the given tab page for winlayout().
+void get_framelayout(const frame_T *fr, list_T *l, bool outer)
+{
+ list_T *fr_list;
+
+ if (fr == NULL) {
+ return;
+ }
+
+ if (outer) {
+ // outermost call from f_winlayout()
+ fr_list = l;
+ } else {
+ fr_list = tv_list_alloc(2);
+ tv_list_append_list(l, fr_list);
+ }
+
+ if (fr->fr_layout == FR_LEAF) {
+ if (fr->fr_win != NULL) {
+ tv_list_append_string(fr_list, "leaf", -1);
+ tv_list_append_number(fr_list, fr->fr_win->handle);
+ }
+ } else {
+ tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1);
+
+ list_T *const win_list = tv_list_alloc(kListLenUnknown);
+ tv_list_append_list(fr_list, win_list);
+ const frame_T *child = fr->fr_child;
+ while (child != NULL) {
+ get_framelayout(child, win_list, false);
+ child = child->fr_next;
+ }
+ }
+}
+
void win_ui_flush_positions(void)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {