summaryrefslogtreecommitdiff
path: root/mnv/src/testdir/test_statuslineopt.mnv
blob: 8166b3ee6a0a453713f7346ba2d3d3b536f85b4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
" Test 'statuslineopt' with 'statusline'
"

source util/screendump.mnv

def SetUp()
  set laststatus=2
  set ch=1
enddef

def TearDown()
  set laststatus&
  set statusline&
  set statuslineopt&
  set ch&
  :only
enddef

def s:Assert_match_statusline(winid: number, stlh: number, expect: list<string>): void
  redraw!
  if has('gui_running')
    sleep 1m
  endif
  var wi = getwininfo(winid)[0]
  var winh = wi.winrow + wi.height
  # Read screen content directly after redraw! to avoid a second redraw!
  # inside g:ScreenLines() that may process GUI events and change the window
  # layout between the getwininfo() call and the screenstring() calls.
  var actual = mapnew(range(winh, winh + wi.status_height - 1),
      (_, l) => join(mapnew(range(1, &columns),
          (_, c) => screenstring(l, c)), '')[wi.wincol - 1 : wi.wincol - 1 + wi.width - 1])
  assert_equal(stlh, wi.status_height)
  for i in range(len(expect))
    assert_match(expect[i], actual[i], $'[{i}]')
  endfor
enddef

def Test_statuslineopt()
  set statuslineopt=maxheight:2
  &statusline = "AAA"
  var wid = win_getid()
  s:Assert_match_statusline(wid, 1, ['^AAA *'])
  &statusline = "AAA%@BBB"
  s:Assert_match_statusline(wid, 2, ['^AAA *', '^BBB *'])
  &statusline = "AAA%@BBB%@CCC"
  s:Assert_match_statusline(wid, 2, ['^AAA *', '^BBB *'])

  set statuslineopt=maxheight:3
  s:Assert_match_statusline(wid, 3, ['^AAA *', '^BBB *', '^CCC *'])
  &statusline = "AAA%@BBB"
  s:Assert_match_statusline(wid, 2, ['^AAA *', '^BBB *'])

  # Best effort
  &statusline = "AAA%@BBB%@CCC"
  set statuslineopt=maxheight:999
  s:Assert_match_statusline(wid, 3, ['^AAA *', '^BBB *', '^CCC *'])

  # Single line
  set statuslineopt=maxheight:1
  s:Assert_match_statusline(wid, 1, ['^AAA *'])
enddef

def Test_statuslineopt_fixedheight()
  set statuslineopt=maxheight:2,fixedheight
  &statusline = "AAA"
  var wid = win_getid()
  var stlh = 2
  s:Assert_match_statusline(wid, stlh, ['^AAA *', '^ *'])
  &statusline = "AAA%@BBB"
  s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *'])
  &statusline = "AAA%@BBB%@CCC"
  s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *'])

  set statuslineopt=maxheight:3,fixedheight
  stlh = 3
  s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *', '^CCC *'])
  &statusline = "AAA%@BBB"
  s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *', '^ *'])

  # Best effort
  &statusline = "AAA%@BBB%@CCC"
  set statuslineopt=maxheight:999,fixedheight
  stlh = &lines - &ch - 1
  s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *', '^CCC *', '^ *'])

  # Single line
  set statuslineopt=maxheight:1
  stlh = 1
  s:Assert_match_statusline(wid, stlh, ['^AAA *'])
enddef

def Test_statuslineopt_multi_win()
  &statusline = "AAA%@BBB%@BB3"
  var wid1 = win_getid()
  new ccc
  &l:statusline = "CCC%@DDD%@DD3"
  var wid2 = win_getid()
  set statuslineopt=maxheight:2
  var stlh = 2
  s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *'])
  s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *'])

  vnew eee
  &l:statusline = "EEE%@FFF%@FF3"
  var wid3 = win_getid()
  s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *'])
  s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *'])
  s:Assert_match_statusline(wid3, stlh, ['^EEE *', '^FFF *'])

  quit
  new eee
  wid3 = win_getid()
  s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *'])
  s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *'])
  s:Assert_match_statusline(wid3, stlh, ['^EEE *', '^FFF *'])

  # Best effort (fixedheight fills all available space)
  # Window equalization may not give exactly equal frame heights depending on
  # the terminal size, so allow a difference of 1 relative to wid1.
  set statuslineopt=maxheight:999,fixedheight
  var h1 = getwininfo(wid1)[0].height
  assert_inrange(h1 - 1, h1 + 1, getwininfo(wid2)[0].height)
  assert_inrange(h1 - 1, h1 + 1, getwininfo(wid3)[0].height)
  s:Assert_match_statusline(wid1, getwininfo(wid1)[0].status_height,
      ['^AAA *', '^BBB *', '^BB3 *', '^ *'])
  s:Assert_match_statusline(wid2, getwininfo(wid2)[0].status_height,
      ['^CCC *', '^DDD *', '^DD3 *', '^ *'])
  s:Assert_match_statusline(wid3, getwininfo(wid3)[0].status_height,
      ['^EEE *', '^FFF *', '^FF3 *', '^ *'])

  # Single line
  set statuslineopt=maxheight:1
  stlh = 1
  s:Assert_match_statusline(wid1, stlh, ['^AAA *'])
  s:Assert_match_statusline(wid2, stlh, ['^CCC *'])
  s:Assert_match_statusline(wid3, stlh, ['^EEE *'])
enddef

def Test_statuslineopt_winlocal()
  # Test window-local 'statuslineopt':
  # wid1 uses global statuslineopt (maxheight:1)
  # wid2 uses local statuslineopt (maxheight:3), both using the global statusline
  &statusline = "AAA%@BBB%@CCC"
  set statuslineopt=maxheight:1
  var wid1 = win_getid()
  new ddd
  var wid2 = win_getid()
  setlocal statuslineopt=maxheight:3

  s:Assert_match_statusline(wid1, 1, ['^AAA *'])
  s:Assert_match_statusline(wid2, 3, ['^AAA *', '^BBB *', '^CCC *'])

  # After clearing the local statuslineopt, wid2 reverts to global (maxheight:1)
  setlocal statuslineopt<
  s:Assert_match_statusline(wid1, 1, ['^AAA *'])
  s:Assert_match_statusline(wid2, 1, ['^AAA *'])

  # Window with local statusline and local statuslineopt (fixedheight)
  &l:statusline = "DDD%@EEE"
  setlocal statuslineopt=maxheight:3,fixedheight
  s:Assert_match_statusline(wid2, 3, ['^DDD *', '^EEE *', '^ *'])

  # wid1 (global settings) is unaffected by wid2's local changes
  s:Assert_match_statusline(wid1, 1, ['^AAA *'])
enddef

def Test_statuslineopt_split_inherit()
  # setl stlo follows the same inheritance rules as setl stl:
  #   :sp  - local stlo IS inherited (new window shows same buffer)
  #   :new - local stlo is NOT inherited (cleared when entering new buffer)
  set statuslineopt=maxheight:1
  &statusline = "SEG1%@SEG2%@SEG3"
  setlocal statuslineopt=maxheight:3
  var wid1 = win_getid()
  s:Assert_match_statusline(wid1, 3, ['^SEG1 *', '^SEG2 *', '^SEG3 *'])

  # :sp splits the same buffer - local stlo is inherited
  split
  var wid2 = win_getid()
  s:Assert_match_statusline(wid2, 3, ['^SEG1 *', '^SEG2 *', '^SEG3 *'])
  quit

  # :new opens a new empty buffer - local stlo is NOT inherited, falls back to
  # global (maxheight:1)
  new
  var wid3 = win_getid()
  s:Assert_match_statusline(wid3, 1, ['^SEG1 *'])
  quit
enddef

let g:StloStatusVar = ''
def g:StloStatusLine(): string
  return g:StloStatusVar
enddef

def Test_statuslineopt_expr()
  new bbb.txt
  g:StloStatusVar = 'A001%@A002%@%t'
  set statuslineopt=maxheight:3
  &statusline = "%!StloStatusLine()"
  var wid = win_getid()
  var stlh = 3
  s:Assert_match_statusline(wid, stlh, ['^A001 *', '^A002 *', '^bbb\.txt *'])

  &statusline = "%{%StloStatusLine()%}"
  s:Assert_match_statusline(wid, stlh, ['^A001 *', '^A002 *', '^bbb\.txt *'])
  g:StloStatusVar = 'B00001%@B002'
  s:Assert_match_statusline(wid, stlh, ['^B00001 *', '^B002 *', '^ *'])
enddef

func Test_multistatusline_highlight()
  CheckScreendump

  let lines =<< trim END
    func MyStatusLine()
      return 'L1A01%=%#Search#L1A02%*%=%2*L1A03%*%@'
        \ .. '%2*L2B01%*%=L2B02%=%#Search#L2B03%*%@'
        \ .. '%#Search#L3C01%*%=%2*L3C02%*%=L3C03%@'
    endfunc

    set laststatus=2
    set statuslineopt=maxheight:3
    set statusline=%!MyStatusLine()
  END
  call writefile(lines, 'XTest_multistatusline_highlight', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_multistatusline_highlight', {'rows': 6})
  call term_sendkeys(buf, "\<C-L>")
  call VerifyScreenDump(buf, 'Test_multistatusline_highlight_01', {})
  call term_sendkeys(buf, ":hi link User2 Error\<CR>\<C-L>")
  call VerifyScreenDump(buf, 'Test_multistatusline_highlight_02', {})
  call term_sendkeys(buf, ":hi link User2 NONE\<CR>\<C-L>")
  call VerifyScreenDump(buf, 'Test_multistatusline_highlight_01', {})

  call StopMNVInTerminal(buf)
endfunc

func Test_statuslineopt_default_stl()
  CheckScreendump

  " fixedheight with no custom stl: status area is fixed at 4 rows, filled
  " with fillchar and must not bleed through buffer content.
  let lines =<< trim END
    set laststatus=2
    set statuslineopt=maxheight:4,fixedheight
  END
  call writefile(lines, 'XTest_statuslineopt_default_stl', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_statuslineopt_default_stl', {'rows': 8})
  call term_sendkeys(buf, "\<C-L>")
  call VerifyScreenDump(buf, 'Test_statuslineopt_default_stl_01', {})

  call StopMNVInTerminal(buf)
endfunc

def Test_statuslineopt_default_stl_maxheight()
  # maxheight without fixedheight: status area adapts to rendered content.
  # Default statusline is always single-line, so status area must be 1 row
  # regardless of maxheight value.
  set statuslineopt=maxheight:9
  var wid = win_getid()
  assert_equal(1, getwininfo(wid)[0].status_height)

  # After :new the new window also has stlo=maxheight:9 but w_height should
  # be equalized (both windows get roughly half the available content rows).
  new
  var wid2 = win_getid()
  var h1 = getwininfo(wid)[0].height
  var h2 = getwininfo(wid2)[0].height
  # Both status areas must be 1 row (not 9)
  assert_equal(1, getwininfo(wid)[0].status_height)
  assert_equal(1, getwininfo(wid2)[0].status_height)
  # Content heights must be nearly equal (differ by at most 1 due to p_wh)
  assert_true(abs(h1 - h2) <= 1, $'h1={h1} h2={h2} should be equal')
  only
enddef

func Test_statuslineopt_new_split()
  CheckScreendump

  " Test :new — local stlo is NOT inherited (new buffer), so the new window
  " uses global stlo (maxheight:1, single-line) while the original keeps
  " fixedheight,maxheight:5.
  let lines =<< trim END
    set laststatus=2
    set statuslineopt=maxheight:1
    set statusline=SEG1%@SEG2%@SEG3%@SEG4%@SEG5
    setlocal statuslineopt=fixedheight,maxheight:5
  END
  call writefile(lines, 'XTest_statuslineopt_new_split', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_statuslineopt_new_split', {'rows': 20})
  call term_sendkeys(buf, ":new\<CR>\<C-L>")
  call VerifyScreenDump(buf, 'Test_statuslineopt_new_split_01', {})

  call StopMNVInTerminal(buf)
endfunc

func Test_statuslineopt_sp_split()
  CheckScreendump

  " Test :sp — local stlo IS inherited (same buffer), so both windows use
  " fixedheight,maxheight:5.
  let lines =<< trim END
    set laststatus=2
    set statusline=SEG1%@SEG2%@SEG3%@SEG4%@SEG5
    setlocal statuslineopt=fixedheight,maxheight:5
  END
  call writefile(lines, 'XTest_statuslineopt_sp_split', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_statuslineopt_sp_split', {'rows': 15})
  call term_sendkeys(buf, ":sp\<CR>\<C-L>")
  call VerifyScreenDump(buf, 'Test_statuslineopt_sp_split_01', {})

  call StopMNVInTerminal(buf)
endfunc

func Test_statuslineopt_sp_foo()
  CheckScreendump

  " Test :sp foo — local stlo is NOT inherited (different file), so the new
  " window uses global stlo (maxheight:1, single-line).
  let lines =<< trim END
    set laststatus=2
    set statuslineopt=maxheight:1
    set statusline=SEG1%@SEG2%@SEG3%@SEG4%@SEG5
    setlocal statuslineopt=fixedheight,maxheight:5
  END
  call writefile(lines, 'XTest_statuslineopt_sp_foo', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_statuslineopt_sp_foo', {'rows': 20})
  call term_sendkeys(buf, ":sp Xfoo\<CR>\<C-L>")
  call VerifyScreenDump(buf, 'Test_statuslineopt_sp_foo_01', {})

  call StopMNVInTerminal(buf)
endfunc

func Test_statuslineopt_wincmd_eq()
  CheckScreendump

  " Test CTRL-W_= with mixed global stlo (maxheight:3) and local stlo
  " (fixedheight,maxheight:5); equalization assigns equal content rows to
  " both windows despite their different status-line heights.
  let lines =<< trim END
    set laststatus=2
    set statuslineopt=maxheight:3
    set statusline=GA%@GB%@GC
    new
    setlocal statuslineopt=fixedheight,maxheight:5
    setlocal statusline=LA%@LB%@LC%@LD%@LE
  END
  call writefile(lines, 'XTest_statuslineopt_wincmd_eq', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_statuslineopt_wincmd_eq', {'rows': 12})
  call term_sendkeys(buf, "\<C-W>=\<C-L>")
  call VerifyScreenDump(buf, 'Test_statuslineopt_wincmd_eq_01', {})

  call StopMNVInTerminal(buf)
endfunc

func Test_statuslineopt_wincmd_underscore()
  CheckScreendump

  " Test CTRL-W__ with global stlo maxheight:3 and multi-line statusline.
  " After maximizing, the large window should keep stlh=3, not collapse to 1
  " because the minimized other window constrained global_stlh.
  let lines =<< trim END
    set laststatus=2
    set statuslineopt=maxheight:3
    set statusline=GA%@GB%@GC
    new
  END
  call writefile(lines, 'XTest_statuslineopt_wincmd_underscore', 'D')

  let buf = g:RunMNVInTerminal('-S XTest_statuslineopt_wincmd_underscore', {'rows': 14})
  call term_sendkeys(buf, "\<C-W>_\<C-L>")
  call VerifyScreenDump(buf, 'Test_statuslineopt_wincmd_underscore_01', {})

  call StopMNVInTerminal(buf)
endfunc

def Test_statuslineopt_besteff_order()
  # Test the best-effort option update: keyword order is preserved and
  # duplicate maxheight: removed.

  # "fixedheight" before "maxheight:" - order must be preserved.
  :5split
  set statuslineopt=fixedheight,maxheight:9
  assert_equal('fixedheight,maxheight:5', &statuslineopt)
  set statuslineopt&
  only

  # "maxheight:" before "fixedheight" - order must be preserved.
  :5split
  set statuslineopt=maxheight:9,fixedheight
  assert_equal('maxheight:5,fixedheight', &statuslineopt)
  set statuslineopt&
  only

  # set stlo+=maxheight:N: last maxheight wins, earlier one is removed.
  :5split
  set statuslineopt=fixedheight,maxheight:2
  set statuslineopt+=maxheight:9
  assert_equal('fixedheight,maxheight:5', &statuslineopt)
  set statuslineopt&
  only

  # Duplicate maxheight: in one assignment: last wins, earlier removed.
  :5split
  set statuslineopt=maxheight:2,fixedheight,maxheight:9
  assert_equal('fixedheight,maxheight:5', &statuslineopt)
  only
enddef

" mnv: shiftwidth=2 sts=2 expandtab