let pp_concr ?(escape_dblquotes=false) tabsize h c =
  let b = Buffer.create 0 in
  let col = ref 0 in
  let prkspace k = for i = 1 to k do Buffer.add_char b ' ' done; col := !col + k in
  let prspace_till c =
    while !col < c do
      Buffer.add_char b ' ';
      incr col;
    done
  in
  let pristr k s =
    for i = 0 to String.length s - 1 do
      if s.[i] = '\t' then
        prkspace tabsize
      else (
        Buffer.add_char b s.[i];
        incr col;
        if s.[i] = '\n' then ( col := 0; prkspace k );
      )
    done
  in
  let prrawstr ?(force_noescape=false) s =
    let s =
      if escape_dblquotes && not force_noescape then
        escape_dbl_quotes s
      else s
    in
    Buffer.add_string b s; col := !col + String.length s
  in
  let getvar v = match h with None -> ":" ^ v | Some h -> Hashtbl.find h v in
  let rec pr k = function
    | RawStr s -> prrawstr s
    | IStr s -> pristr k s
    | Var i -> prrawstr ~force_noescape:true (getvar i)
    | Block l -> List.iter (fun c -> pr k c; pristr k "\n") l
    | Halign l ->
        ignore (List.fold_left (fun isfirst c -> if not isfirst then prkspace 1; pr !col c; falsetrue l)
    | Valign l ->
        List.iter (fun c -> pr k c; pristr k "\n") l
    | Indent c -> prspace_till (k + tabsize); pr (k + tabsize) c
  in
  pr 0 c;
  Buffer.contents b