12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394openCoreopenImportmoduleView_spec=structtypet={key:string->Vdom.Node.t;plain_text:string->Vdom.Node.t}letplain=letopenVdomin{key=Node.text;plain_text=Node.text};;letwith_classes~key_class~plain_text_class=lettext_spanclass_text=letopenVdominNode.span~attr:(Attr.class_class_)[Node.texttext]in{key=text_spankey_class;plain_text=text_spanplain_text_class};;endmoduleCommand=structtypet={keys:Keystroke.tlist;description:string}[@@derivingsexp,compare]moduleFormat=structtypet=[`Keysof[`Sepofstring]|`Descriptionof(string->string)option|`Textofstring]listletdefault=[`Text"Press ";`Keys(`Sep" or ");`Text" to ";`Description(SomeString.uncapitalize);`Text"."];;endletview_keyst(view_spec:View_spec.t)~sep=letkeys=t.keys|>List.map~f:Keystroke.to_string_hum(* Dedup keystrokes that map to the same string, e.g. Enter and NumpadEnter. *)|>List.dedup_and_sort~compare:String.compare|>List.map~f:view_spec.keyinList.interspersekeys~sep:(view_spec.plain_textsep);;letview_description?(f=Fn.id)t(view_spec:View_spec.t)=view_spec.plain_text(ft.description);;letviewtview_specformat=letopenVdominNode.div(List.concat_mapformat~f:(function|`Keys(`Sepsep)->view_keystview_spec~sep|`Descriptionf->[view_description?ftview_spec]|`Texttext->[view_spec.plain_texttext]));;endtypet=Command.tlist[@@derivingsexp,compare]letempty=[]letis_empty=List.is_emptyletof_command_list=Fn.idletcommands=Fn.idletadd_commandtcommand=t@[command]letview_rows?(sep=" or ")t(view_spec:View_spec.t)=letopenVdominletalignhow=Css_gen.(text_alignhow)|>Attr.styleinList.map(commandst)~f:(funcommand->Node.tr[Node.td~attr:(align`Right)(Command.view_keyscommandview_spec~sep@[view_spec.plain_text" : "]);Node.td~attr:(align`Left)[Command.view_descriptioncommandview_spec]]);;letview?septview_spec=Vdom.Node.table(view_rows?septview_spec)