12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Hershey.mli for the font format, with an example *)typeglyph={left:int;right:int;strokes:(int*int)listlist}(*****************************************************************************)(* Decoding *)(*****************************************************************************)letcoordinate(c:char):int=Char.codec-Char.code'R'letdecode_glyph(s:string):glyph=(* the characters two by two: the left/right pair, then the points *)letpairs=List.init(String.lengths/2)(funi->(s.[2*i],s.[(2*i)+1]))inmatchpairswith|[]->failwith"empty glyph"|(l,r)::points->(* split the points into strokes at each pen up, " R" *)letfinishstrokestrokes=ifstroke=[]thenstrokeselseList.revstroke::strokesinletstroke,strokes=List.fold_left(fun(stroke,strokes)(cx,cy)->ifcx=' '&&cy='R'then([],finishstrokestrokes)else((coordinatecx,coordinatecy)::stroke,strokes))([],[])pointsin{left=coordinatel;right=coordinater;strokes=List.rev(finishstrokestrokes)}(*****************************************************************************)(* The font *)(*****************************************************************************)(* One line per glyph, for ASCII 32 (space) to 127 in order; each line
* starts with a 5-character number and a 3-character count *)letfont:glypharrayLazy.t=lazy(String.split_on_char'\n'Hershey_futural.jhf|>List.filter(funline->String.lengthline>=10)|>List.map(funline->decode_glyph(String.subline8(String.lengthline-8)))|>Array.of_list)letglyph(c:char):glyph=letfont=Lazy.forcefontinleti=Char.codec-32inifi>=0&&i<Array.lengthfontthenfont.(i)elsefont.(Char.code'?'-32)(* Capital letters go from -12 to 9, 21 units, and in usual fonts
* capitals are about 0.7 em tall: 21 / 0.7 = 30 *)letunits_per_em=30.(*****************************************************************************)(* Layout *)(*****************************************************************************)letlayout(str:string):(float*float)listlist*float=letstrokes,width=List.fold_left(fun(strokes,x)c->letg=glyphcin(* move the glyph so that its left side is at x *)letdx=x-g.leftinletmoved=List.map(List.map(fun(px,py)->(float(px+dx),floatpy)))g.strokesin(strokes@moved,x+(g.right-g.left)))([],0)(List.init(String.lengthstr)(String.getstr))in(strokes,floatwidth)