123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124open!Coreopen!ImportincludeGrid_intftypet={data:Cell.tlistlist;heights:intlist;widths:intlist;aligns:Column.Align.tlist;spacing:int;display:Display.t}[@@derivingsexp_of]letcreatecolsraw_data~display~display_empty_rows~header_attr:h_attr~max_width~spacing~prefer_split_on_spaces=letbody=List.mapraw_data~f:(funvalue->List.mapcols~f:(Column.Private.to_cell~value))inletempty=List.foldbody~init:(List.mapcols~f:(fun_->true))~f:(List.map2_exn~f:(funis_emptyelement->is_empty&&Cell.is_emptyelement))inletkeep=List.map2_exncolsempty~f:(funcolumnis_empty->matchColumn.showcolumnwith|`Yes->true|`No->false|`If_not_empty->notis_empty)inletfilterl=List.filter_opt(List.map2_exnkeepl~f:Option.some_if)inletcols=filtercolsinletbody=List.mapbody~f:filterin(* We subtract 1 from max_width because later we're going to add a line of
'|'s to form the right wall of the table. *)letwidths=Column.Private.layoutcolsraw_data~spacing~max_width:(max_width-1)inletgrid_data=List.mapcols~f:(funcolumn->Cell.createh_attr(Column.headercolumn))::bodyinletheights=if[%compare.equal:Display.t]displayLinethenList.mapgrid_data~f:(fun_->1)elseList.mapgrid_data~f:(funrow->assert(List.lengthwidths=List.lengthrow);List.map2_exnwidthsrow~f:(funwidthelement->Cell.heightelement~display_empty_rows~width~prefer_split_on_spaces)|>list_max~f:Fn.id)inletaligns=List.mapcols~f:Column.alignin{data=grid_data;heights;widths;aligns;spacing;display};;letto_screent~prefer_split_on_spaces=assert(List.lengtht.data=List.lengtht.heights);letmid_row=if[%compare.equal:Display.t]t.displayTall_boxthen1else0in(* The total width of the table includes the '|'s to the left of elements, so we add 1
and the spacing on either side when summing. *)letcols=list_sumt.widths~f:((+)(1+(t.spacing*2)))+1inletrows=list_sumt.heights~f:((+)mid_row)+3-(2*mid_row)inletscreen=Screen.create~rows~colsinlettexel:Screen.Texel.t=if[%compare.equal:Display.t]t.displayColumn_titlesthenBlankelseLineinScreen.hlinescreentexel~row:0;Screen.hlinescreentexel~row:(rows-1);ifnot([%compare.equal:Display.t]t.displayBlank)then(Screen.vlinescreentexel~col:0;ignore(List.foldt.widths~init:0~f:(funcolwidth->letcol=col+1+width+(t.spacing*2)inScreen.vlinescreentexel~col;col):int));ignore(List.fold2_exnt.datat.heights~init:1~f:(funrowrow_elementsheight->letheader_row=row=1inignore(List.fold2_exnrow_elements(List.zip_exnt.widthst.aligns)~init:(1+t.spacing)~f:(funcolelement(width,align)->letlines=Cell.wrapelement~width~prefer_split_on_spacesinletattr=Cell.attrelementinif[%compare.equal:Display.t]t.displayLinethen(matchlineswith|[]->()|[line]->Screen.stringscreenalignattrline~row~col~width|line::_->Screen.stringscreenalignattrline~row~col~width;forcol=col+max0(width-3)tocol+width-1doScreen.charscreen[](Uchar.of_char'.')~row~coldone)elseignore(List.foldlines~init:row~f:(funrowline->Screen.stringscreenalignattrline~row~col~width;row+1):int);col+1+(t.spacing*2)+width):int);letrow=row+heightinif[%compare.equal:Display.t]t.displayTall_box||header_rowthen(ifnot([%compare.equal:Display.t]t.displayBlank)thenScreen.hlinescreenLine~row;row+1)elserow):int);screen;;