@@ -46,9 +46,8 @@ defmodule Inspect.Opts do
4646    * `:limit` - limits the number of items that are inspected for tuples, 
4747      bitstrings, maps, lists and any other collection of items, with the exception of 
4848      printable strings and printable charlists which use the `:printable_limit` option. 
49-       If you don't want to limit the number of items to a particular number, 
50-       use `:infinity`. It accepts a positive integer or `:infinity`. 
51-       Defaults to `50`. 
49+       It accepts a positive integer or `:infinity`. It defaults to 100 since 
50+       `Elixir v1.19.0`, as it has better defaults to deal with nested collections. 
5251
5352    * `:pretty` - if set to `true` enables pretty printing. Defaults to `false`. 
5453
@@ -91,7 +90,7 @@ defmodule Inspect.Opts do
9190            charlists:  :infer , 
9291            custom_options:  [ ] , 
9392            inspect_fun:  & Inspect . inspect / 2 , 
94-             limit:  50 , 
93+             limit:  100 , 
9594            pretty:  false , 
9695            printable_limit:  4096 , 
9796            safe:  true , 
@@ -332,7 +331,6 @@ defmodule Inspect.Algebra do
332331           when  is_binary ( doc )  or  doc  in  [ :doc_nil ,  :doc_line ]  or 
333332                  ( is_tuple ( doc )  and  elem ( doc ,  0 )  in  @ docs ) 
334333
335-   defguardp  is_limit ( limit )  when  limit  ==  :infinity  or  ( is_integer ( limit )  and  limit  >=  0 ) 
336334  defguardp  is_width ( width )  when  width  ==  :infinity  or  ( is_integer ( width )  and  width  >=  0 ) 
337335
338336  # Elixir + Inspect.Opts conveniences 
@@ -341,11 +339,28 @@ defmodule Inspect.Algebra do
341339  @ doc  """ 
342340  Converts an Elixir term to an algebra document 
343341  according to the `Inspect` protocol. 
342+ 
343+   In practice, one must prefer to use `to_doc_with_opts/2` 
344+   over this function, as `to_doc_with_opts/2` returns the 
345+   updated options from inspection. 
344346  """ 
345347  @ spec  to_doc ( any ,  Inspect.Opts . t ( ) )  ::  t 
346-   def  to_doc ( term ,  opts ) 
348+   def  to_doc ( term ,  opts )  do 
349+     to_doc_with_opts ( term ,  opts )  |>  elem ( 0 ) 
350+   end 
351+ 
352+   @ doc  """ 
353+   Converts an Elixir term to an algebra document 
354+   according to the `Inspect` protocol, alongside the updated options. 
355+ 
356+   This function is used when implementing the inspect protocol for 
357+   a given type and you must convert nested terms to documents too. 
358+   """ 
359+   @ doc  since:  "1.19.0" 
360+   @ spec  to_doc_with_opts ( any ,  Inspect.Opts . t ( ) )  ::  { t ,  Inspect.Opts . t ( ) } 
361+   def  to_doc_with_opts ( term ,  opts ) 
347362
348-   def  to_doc ( % _ { }  =  struct ,  % Inspect.Opts { inspect_fun:  fun }  =  opts )  do 
363+   def  to_doc_with_opts ( % _ { }  =  struct ,  % Inspect.Opts { inspect_fun:  fun }  =  opts )  do 
349364    if  opts . structs  do 
350365      try  do 
351366        fun . ( struct ,  opts ) 
@@ -363,13 +378,15 @@ defmodule Inspect.Algebra do
363378            try  do 
364379              Process . put ( :inspect_trap ,  true ) 
365380
366-               inspected_struct  = 
367-                 struct 
368-                 |>  Inspect.Map . inspect_as_map ( % { 
381+               { doc_struct ,  _opts }  = 
382+                 Inspect.Map . inspect_as_map ( struct ,  % { 
369383                  opts 
370384                  |  syntax_colors:  [ ] , 
371385                    inspect_fun:  Inspect.Opts . default_inspect_fun ( ) 
372386                } ) 
387+ 
388+               inspected_struct  = 
389+                 doc_struct 
373390                |>  format ( opts . width ) 
374391                |>  IO . iodata_to_binary ( ) 
375392
@@ -394,10 +411,29 @@ defmodule Inspect.Algebra do
394411    else 
395412      Inspect.Map . inspect_as_map ( struct ,  opts ) 
396413    end 
414+     |>  pack_opts ( opts ) 
415+   end 
416+ 
417+   def  to_doc_with_opts ( arg ,  % Inspect.Opts { inspect_fun:  fun }  =  opts )  do 
418+     fun . ( arg ,  opts )  |>  pack_opts ( opts ) 
397419  end 
398420
399-   def  to_doc ( arg ,  % Inspect.Opts { inspect_fun:  fun }  =  opts )  do 
400-     fun . ( arg ,  opts ) 
421+   defp  pack_opts ( { _doc ,  % Inspect.Opts { } }  =  doc_opts ,  _opts ) ,  do:  doc_opts 
422+   defp  pack_opts ( doc ,  opts ) ,  do:  { doc ,  opts } 
423+ 
424+   @ doc  ~S"""  
425+   Wraps `collection` in `left` and `right` according to limit and contents 
426+   and returns only the container document. 
427+ 
428+   In practice, one must prefer to use `container_doc_with_opts/6` 
429+   over this function, as `container_doc_with_opts/6` returns the 
430+   updated options from inspection. 
431+   """  
432+   @ doc  since:  "1.6.0" 
433+   @ spec  container_doc ( t ,  [ term ] ,  t ,  Inspect.Opts . t ( ) ,  ( term ,  Inspect.Opts . t ( )  ->  t ) ,  keyword ( ) )  :: 
434+           t 
435+   def  container_doc ( left ,  collection ,  right ,  inspect_opts ,  fun ,  opts  \\  [ ] )  do 
436+     container_doc_with_opts ( left ,  collection ,  right ,  inspect_opts ,  fun ,  opts )  |>  elem ( 0 ) 
401437  end 
402438
403439  @ doc  ~S"""  
@@ -412,6 +448,8 @@ defmodule Inspect.Algebra do
412448  The limit in the given `inspect_opts` is respected and when reached this 
413449  function stops processing and outputs `"..."` instead. 
414450
451+   It returns a tuple with the algebra document and the updated options. 
452+ 
415453  ## Options 
416454
417455    * `:separator` - the separator used between each doc 
@@ -423,79 +461,99 @@ defmodule Inspect.Algebra do
423461
424462      iex> inspect_opts = %Inspect.Opts{limit: :infinity} 
425463      iex> fun = fn i, _opts -> to_string(i) end 
426-       iex> doc  = Inspect.Algebra.container_doc ("[", Enum.to_list(1..5), "]", inspect_opts, fun) 
464+       iex> { doc, _opts}  = Inspect.Algebra.container_doc_with_opts ("[", Enum.to_list(1..5), "]", inspect_opts, fun) 
427465      iex> Inspect.Algebra.format(doc, 5) |> IO.iodata_to_binary() 
428466      "[1,\n 2,\n 3,\n 4,\n 5]" 
429467
430468      iex> inspect_opts = %Inspect.Opts{limit: 3} 
431469      iex> fun = fn i, _opts -> to_string(i) end 
432-       iex> doc  = Inspect.Algebra.container_doc ("[", Enum.to_list(1..5), "]", inspect_opts, fun) 
470+       iex> { doc, _opts}  = Inspect.Algebra.container_doc_with_opts ("[", Enum.to_list(1..5), "]", inspect_opts, fun) 
433471      iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary() 
434472      "[1, 2, 3, ...]" 
435473
436474      iex> inspect_opts = %Inspect.Opts{limit: 3} 
437475      iex> fun = fn i, _opts -> to_string(i) end 
438476      iex> opts = [separator: "!"] 
439-       iex> doc  = Inspect.Algebra.container_doc ("[", Enum.to_list(1..5), "]", inspect_opts, fun, opts) 
477+       iex> { doc, _opts}  = Inspect.Algebra.container_doc_with_opts ("[", Enum.to_list(1..5), "]", inspect_opts, fun, opts) 
440478      iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary() 
441479      "[1! 2! 3! ...]" 
442480
443481  """  
444-   @ doc  since:  "1.6.0" 
445-   @ spec  container_doc ( t ,  [ term ] ,  t ,  Inspect.Opts . t ( ) ,  ( term ,  Inspect.Opts . t ( )  ->  t ) ,  keyword ( ) )  :: 
446-           t 
447-   def  container_doc ( left ,  collection ,  right ,  inspect_opts ,  fun ,  opts  \\  [ ] ) 
482+   @ doc  since:  "1.19.0" 
483+   @ spec  container_doc_with_opts ( 
484+           t , 
485+           [ term ] , 
486+           t , 
487+           Inspect.Opts . t ( ) , 
488+           ( term ,  Inspect.Opts . t ( )  ->  t ) , 
489+           keyword ( ) 
490+         )  :: 
491+           { t ,  Inspect.Opts . t ( ) } 
492+   def  container_doc_with_opts ( left ,  collection ,  right ,  inspect_opts ,  fun ,  opts  \\  [ ] ) 
448493      when  is_doc ( left )  and  is_list ( collection )  and  is_doc ( right )  and  is_function ( fun ,  2 )  and 
449494             is_list ( opts )  do 
450495    case  collection  do 
451496      [ ]  -> 
452-         concat ( left ,  right ) 
497+         { concat ( left ,  right ) ,   inspect_opts } 
453498
454499      _  -> 
455500        break  =  Keyword . get ( opts ,  :break ,  :maybe ) 
456501        separator  =  Keyword . get ( opts ,  :separator ,  @ container_separator ) 
457502
458-         { docs ,  simple? }  = 
459-           container_each ( collection ,  inspect_opts . limit ,   inspect_opts ,  fun ,  [ ] ,  break  ==  :maybe ) 
503+         { docs ,  simple? ,   inspect_opts }  = 
504+           container_each ( collection ,  inspect_opts ,  fun ,  [ ] ,  break  ==  :maybe ) 
460505
461506        flex?  =  simple?  or  break  ==  :flex 
462507        docs  =  fold ( docs ,  & join ( & 1 ,  & 2 ,  flex? ,  separator ) ) 
463508
464-         case  flex?  do 
465-           true  ->  group ( concat ( concat ( left ,  nest ( docs ,  1 ) ) ,  right ) ) 
466-           false  ->  group ( glue ( nest ( glue ( left ,  "" ,  docs ) ,  2 ) ,  "" ,  right ) ) 
467-         end 
509+         group  = 
510+           case  flex?  do 
511+             true  ->  group ( concat ( concat ( left ,  nest ( docs ,  1 ) ) ,  right ) ) 
512+             false  ->  group ( glue ( nest ( glue ( left ,  "" ,  docs ) ,  2 ) ,  "" ,  right ) ) 
513+           end 
514+ 
515+         { group ,  inspect_opts } 
468516    end 
469517  end 
470518
471-   defp  container_each ( [ ] ,  _limit ,   _opts ,  _fun ,  acc ,  simple? )  do 
472-     { :lists . reverse ( acc ) ,  simple? } 
519+   defp  container_each ( [ ] ,  opts ,  _fun ,  acc ,  simple? )  do 
520+     { :lists . reverse ( acc ) ,  simple? ,   opts } 
473521  end 
474522
475-   defp  container_each ( _ ,  0 ,   _opts ,   _fun ,  acc ,  simple? )  do 
476-     { :lists . reverse ( [ "..."  |  acc ] ) ,  simple? } 
523+   defp  container_each ( _ ,  opts ,   _fun ,  acc ,  simple? )   when   opts . limit   <=   0  do 
524+     { :lists . reverse ( [ "..."  |  acc ] ) ,  simple? ,   opts } 
477525  end 
478526
479-   defp  container_each ( [ term  |  terms ] ,  limit ,  opts ,  fun ,  acc ,  simple? ) 
480-        when  is_list ( terms )  and  is_limit ( limit )  do 
481-     new_limit  =  decrement ( limit ) 
482-     doc  =  fun . ( term ,  % { opts  |  limit:  new_limit } ) 
483-     limit  =  if  doc  ==  :doc_nil ,  do:  limit ,  else:  new_limit 
484-     container_each ( terms ,  limit ,  opts ,  fun ,  [ doc  |  acc ] ,  simple?  and  simple? ( doc ) ) 
527+   defp  container_each ( [ term  |  terms ] ,  opts ,  fun ,  acc ,  simple? )  when  is_list ( terms )  do 
528+     { doc ,  opts }  =  call_container_fun ( fun ,  term ,  opts ) 
529+     container_each ( terms ,  opts ,  fun ,  [ doc  |  acc ] ,  simple?  and  simple? ( doc ) ) 
485530  end 
486531
487-   defp  container_each ( [ left  |  right ] ,  limit ,  opts ,  fun ,  acc ,  simple? )  when  is_limit ( limit )  do 
488-     limit  =  decrement ( limit ) 
489-     left  =  fun . ( left ,  % { opts  |  limit:  limit } ) 
490-     right  =  fun . ( right ,  % { opts  |  limit:  limit } ) 
532+   defp  container_each ( [ left  |  right ] ,  opts ,  fun ,  acc ,  simple? )  do 
533+     { left ,  opts }  =  call_container_fun ( fun ,  left ,  opts ) 
534+     { right ,  _opts }  =  call_container_fun ( fun ,  right ,  opts ) 
491535    simple?  =  simple?  and  simple? ( left )  and  simple? ( right ) 
492- 
493536    doc  =  join ( left ,  right ,  simple? ,  @ tail_separator ) 
494-     { :lists . reverse ( [ doc  |  acc ] ) ,  simple? } 
537+     { :lists . reverse ( [ doc  |  acc ] ) ,  simple? ,  opts } 
538+   end 
539+ 
540+   defp  call_container_fun ( fun ,  term ,  % { limit:  bounded }  =  opts ) 
541+        when  bounded  <=  0  or  bounded  ==  :infinity  do 
542+     case  fun . ( term ,  opts )  do 
543+       { doc ,  % Inspect.Opts { }  =  opts }  ->  { doc ,  opts } 
544+       doc  ->  { doc ,  opts } 
545+     end 
495546  end 
496547
497-   defp  decrement ( :infinity ) ,  do:  :infinity 
498-   defp  decrement ( counter ) ,  do:  counter  -  1 
548+   defp  call_container_fun ( fun ,  term ,  % { limit:  limit }  =  opts )  do 
549+     changed_opts  =  % { opts  |  limit:  limit  -  1 } 
550+ 
551+     case  fun . ( term ,  changed_opts )  do 
552+       { doc ,  % Inspect.Opts { }  =  opts }  ->  { doc ,  opts } 
553+       :doc_nil  ->  { :doc_nil ,  opts } 
554+       doc  ->  { doc ,  changed_opts } 
555+     end 
556+   end 
499557
500558  defp  join ( :doc_nil ,  :doc_nil ,  _ ,  _ ) ,  do:  :doc_nil 
501559  defp  join ( left ,  :doc_nil ,  _ ,  _ ) ,  do:  left 
0 commit comments