@@ -227,11 +227,6 @@ create_nodes = function(source_items, state, level)
227
227
is_last_child = is_last_child ,
228
228
}
229
229
local indent = (state .renderers [item .type ] or {}).indent_size or 4
230
- local estimated_node_length = (# item .name or 0 ) + level * indent + 8
231
- if level == 0 then
232
- estimated_node_length = estimated_node_length + 16
233
- end
234
- state .longest_node = math.max (state .longest_node , estimated_node_length )
235
230
236
231
local node_children = nil
237
232
if item .children ~= nil then
289
284
M .render_component = function (component , item , state , remaining_width )
290
285
local component_func = state .components [component [1 ]]
291
286
if component_func then
292
- local success , component_data = pcall (component_func , component , item , state , remaining_width )
287
+ local success , component_data , wanted_width = pcall (
288
+ component_func ,
289
+ component ,
290
+ item ,
291
+ state ,
292
+ remaining_width
293
+ )
293
294
if success then
294
295
if component_data == nil then
295
296
return { {} }
@@ -302,7 +303,7 @@ M.render_component = function(component, item, state, remaining_width)
302
303
for _ , data in ipairs (component_data ) do
303
304
data .text = one_line (data .text )
304
305
end
305
- return component_data
306
+ return component_data , wanted_width
306
307
else
307
308
local name = component [1 ] or " [missing_name]"
308
309
local msg = string.format (" Error rendering component %s: %s" , name , component_data )
@@ -321,6 +322,23 @@ local prepare_node = function(item, state)
321
322
if item .skip_node then
322
323
return nil
323
324
end
325
+ -- pre_render is used to calculate the longest node width
326
+ -- without actually rendering the node.
327
+ -- We'll try to reuse that work if possible.
328
+ local pre_render = state ._in_pre_render
329
+ if item .line and not pre_render then
330
+ local line = item .line
331
+ -- Only use it once, we don't want to accidentally use stale data
332
+ item .line = nil
333
+ if
334
+ line
335
+ and item .wanted_width
336
+ and state .longest_node
337
+ and item .wanted_width <= state .longest_node
338
+ then
339
+ return line
340
+ end
341
+ end
324
342
local line = NuiLine ()
325
343
326
344
local renderer = state .renderers [item .type ]
@@ -329,24 +347,46 @@ local prepare_node = function(item, state)
329
347
line :append (item .name )
330
348
else
331
349
local remaining_cols = state .win_width
350
+ if remaining_cols == nil then
351
+ if state .winid then
352
+ remaining_cols = vim .api .nvim_win_get_width (state .winid )
353
+ else
354
+ local default_width = utils .resolve_config_option (state , " window.width" , 40 )
355
+ remaining_cols = default_width
356
+ end
357
+ end
358
+ local wanted_width = 0
332
359
if state .current_position == " current" then
333
- remaining_cols = math.min (remaining_cols , state .longest_node )
360
+ local longest = state .longest_node or 0
361
+ remaining_cols = math.min (remaining_cols , longest + 4 )
334
362
end
335
363
for _ , component in ipairs (renderer ) do
336
- local component_data = M .render_component (component , item , state , remaining_cols )
364
+ local component_data , component_wanted_width = M .render_component (
365
+ component ,
366
+ item ,
367
+ state ,
368
+ remaining_cols
369
+ )
370
+ local actual_width = 0
337
371
if component_data then
338
372
for _ , data in ipairs (component_data ) do
339
373
if data .text then
374
+ actual_width = actual_width + vim .api .nvim_strwidth (data .text )
340
375
line :append (data .text , data .highlight )
341
376
remaining_cols = remaining_cols - vim .fn .strchars (data .text )
342
377
end
343
378
end
344
379
end
380
+ component_wanted_width = component_wanted_width or actual_width
381
+ wanted_width = wanted_width + component_wanted_width
382
+ end
383
+ line .wanted_width = wanted_width
384
+ if pre_render then
385
+ item .line = line
386
+ state .longest_node = math.max (state .longest_node , line .wanted_width )
387
+ else
388
+ item .line = nil
345
389
end
346
- state .longest_width_exact = math.max (
347
- state .longest_width_exact ,
348
- vim .api .nvim_strwidth (line :content ())
349
- )
350
390
end
351
391
352
392
return line
@@ -389,7 +429,7 @@ M.focus_node = function(state, id, do_not_focus_window, relative_movement, botto
389
429
390
430
if M .window_exists (state ) then
391
431
if not linenr then
392
- M .expand_to_node (state . tree , node )
432
+ M .expand_to_node (state , node )
393
433
node , linenr = tree :get_node (id )
394
434
if not linenr then
395
435
log .debug (" focus_node cannot get linenr for node with id " , id )
@@ -511,7 +551,8 @@ M.collapse_all_nodes = function(tree)
511
551
end
512
552
end
513
553
514
- M .expand_to_node = function (tree , node )
554
+ M .expand_to_node = function (state , node )
555
+ local tree = state .tree
515
556
if type (node ) == " string" then
516
557
node = tree :get_node (node )
517
558
end
@@ -521,7 +562,7 @@ M.expand_to_node = function(tree, node)
521
562
parent :expand ()
522
563
parentId = parent :get_parent_id ()
523
564
end
524
- tree : render ( )
565
+ render_tree ( state )
525
566
end
526
567
527
568
--- Functions to save and restore the focused node.
@@ -929,23 +970,21 @@ end
929
970
--- Renders the given tree and expands window width if needed
930
971
-- @param state table The state containing tree to render. Almost same as state.tree:render()
931
972
render_tree = function (state )
932
- state .tree :render ()
933
- if state .window .auto_expand_width and state .window .position ~= " float" then
934
- state .window .last_user_width = vim .api .nvim_win_get_width (0 )
935
- if state .longest_width_exact > state .window .last_user_width then
936
- log .trace (
937
- string.format (" auto_expand_width: on. Expanding width to %s." , state .longest_width_exact )
938
- )
939
- vim .api .nvim_win_set_width (0 , state .longest_width_exact )
940
- if state .longest_width_exact > vim .api .nvim_win_get_width (0 ) then
941
- log .error (" Not enough width to expand. Aborting." )
942
- state .longest_width_exact = vim .api .nvim_win_get_width (0 )
943
- return
944
- end
945
- state .win_width = state .longest_width_exact
946
- render_tree (state )
973
+ local should_auto_expand = state .window .auto_expand_width and state .current_position ~= " float"
974
+ local should_pre_render = should_auto_expand or state .current_position == " current"
975
+ if should_pre_render then
976
+ log .trace (" pre-rendering tree" )
977
+ state ._in_pre_render = true
978
+ state .tree :render ()
979
+ state ._in_pre_render = false
980
+ state .window .last_user_width = vim .api .nvim_win_get_width (state .winid )
981
+ if should_auto_expand and state .longest_node > state .window .last_user_width then
982
+ log .trace (string.format (" auto_expand_width: on. Expanding width to %s." , state .longest_node ))
983
+ vim .api .nvim_win_set_width (state .winid , state .longest_node )
984
+ state .win_width = state .longest_node
947
985
end
948
986
end
987
+ state .tree :render ()
949
988
end
950
989
951
990
--- Draws the given nodes on the screen.
0 commit comments