12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788openCoreopenPoly(** Look for a newline in a given substring and returns its
absolute position.
Returns None if no newlines are found.
*)letrecnl_between(get:'a->int->char)(s:'a)~(eol:char)~(pos:int)~(len:int):intoption=iflen=0thenNoneelseifgetspos=eolthenSomeposelsenl_betweengets~eol~pos:(pos+1)~len:(len-1)let%test_=nl_betweenString.get"abcd"~eol:'\n'~pos:0~len:4=Nonelet%test_=nl_betweenString.get"a\nb\ncd"~eol:'\n'~pos:0~len:6=Some1let%test_=nl_betweenString.get"a\nb\ncd"~eol:'\n'~pos:3~len:3=Some3let%test_=nl_betweenString.get"a\nb\ncd"~eol:'\n'~pos:4~len:2=None(**
Type for line buffers.
[flush] will be called back on every fully read newline or when the buffer
itself is flushed by the user.
*)typet={buffer:Buffer.t;eol:char;flush:string->unit}(* *)letcreate?(eol='\n')flush={buffer=Buffer.create0;eol;flush;}letflushb=ifBuffer.lengthb.buffer>0thenbeginb.flush(Buffer.contentsb.buffer);Buffer.resetb.bufferendletadd_charbc=ifc=b.eolthenbeginb.flush(Buffer.contentsb.buffer);Buffer.resetb.bufferendelseBuffer.add_charb.buffercletrecadd_substring'blitgetbuffer_addbs~pos~len=matchnl_betweengets~eol:b.eol~pos~lenwith|None->buffer_addb.buffers~pos~len|Somesuffix_end_pos->(* whatever is in the buffer + this suffix is our newline*)letsuffix_len=suffix_end_pos-posandprefix_len=Buffer.lengthb.bufferinletline=Bytes.create(prefix_len+suffix_len)inBuffer.blit~src:b.buffer~src_pos:0~dst:line~dst_pos:0~len:prefix_len;blit~src:s~src_pos:pos~dst:line~dst_pos:prefix_len~len:suffix_len;Buffer.resetb.buffer;b.flush(Bytes.unsafe_to_string~no_mutation_while_string_reachable:line);add_substring'blitgetbuffer_addbs~pos:(suffix_end_pos+1)~len:(len-suffix_len-1)letadd_substring=add_substring'Bytes.From_string.blitString.getBuffer.add_substringletadd_subbytes=add_substring'Bytes.blitBytes.getBuffer.add_subbytesletadd_stringbs=add_substringbs~pos:0~len:(String.lengths)(** [test_list l]: adds all the strings in [l] to a new blank buffer and
returns all the lines that the callback function was called on.*)lettest_listl=letlines=ref[]inletb=create(funs->lines:=s::!lines)inList.iter~f:(funs->add_stringbs)l;flushb;List.rev!lineslet%test_=test_list["abcd\nas\nere\n"]=["abcd";"as";"ere"]let%test_=test_list["ab";"cd";"\nas\n";"ere\n"]=["abcd";"as";"ere"]let%test_=test_list["no new\nline";" at the end"]=["no new";"line at the end"]let%test_=test_list["a new line";" at the end\n"]=["a new line at the end"]