Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

possible issue with Notty.I.strf #19

Closed
cedlemo opened this issue Dec 6, 2017 · 7 comments
Closed

possible issue with Notty.I.strf #19

cedlemo opened this issue Dec 6, 2017 · 7 comments

Comments

@cedlemo
Copy link

cedlemo commented Dec 6, 2017

I wanted to add tab space in a string image like with Format.astring with :

I.(strf ~attr:A.(fg lightred ++ bg lightblack) "\t %s : %s" title artist)

but it makes my program stop without any warnings, when I remove the "\t" part, everything is fine.

If I add a backslash to try to escape,

I.(strf ~attr:A.(fg lightred ++ bg lightblack) "\\t %s : %s" title artist)

my program does not crash but it displays something like:

"\ta_title : an artist" which is not the same behavior that Format.astring as it is said in the documentation

pretty-prints like Format.asprintf format ..., but returns an image.

Regards.

@pqwy
Copy link
Owner

pqwy commented Dec 9, 2017

Interesting... what happens if you run that in the toplevel?

@cedlemo
Copy link
Author

cedlemo commented Dec 10, 2017

Notty.I.(strf ~attr:Notty.A.(fg lightred ++ bg lightblack) "\t %s : %s" "titl" "artist");;
Exception: Invalid_argument "Notty: control char: U+09, \"\\t \"".

@pqwy
Copy link
Owner

pqwy commented Dec 10, 2017

So there is a warning after all? Exciting!

What could it mean?

@cedlemo
Copy link
Author

cedlemo commented Dec 10, 2017

So there is a warning after all? Exciting!

are you sarcastic ? does this issue bother you or the way I writted it (did you find me rude, if so I sincerly apologize)?

It meens that this kind of character is not accepted by Notty.I.strf unlike Format.astring

@cedlemo cedlemo closed this as completed Dec 10, 2017
pqwy added a commit that referenced this issue Dec 10, 2017
@pqwy
Copy link
Owner

pqwy commented Dec 10, 2017

This is because images cannot contain control characters, ever, regardless of how you create them.

So every function that creates them from raw string or character material has to throw that exception. I updated the docs to mention the same thing for strf too, but that constraint was made pretty up-front and obvious.

If you are trying to simply pad on the left, you can use hpad and friends. If you are trying to right-align the title column, you need to form the columns separately.

(* maxby : ('a -> int) -> 'a list -> int *)
let maxby f xs = List.(fold_left max 0 (map f xs))
(* column : align:[`Left|`Middle|`Right] -> image list -> image *)
let column ~align images =
  let width = maxby I.width images in
  List.map (I.hsnap ~align width) images |> I.vcat

Assuming you have songs : string * string, you separate them into lists with information for different columns, create images individually, form the columns, and combine them into an overall image:

(* render_title : string -> image *)
let render_title = I.string A.(fg lightred ++ bg lightblack)
(* render_artist : string -> image *)
let render_artist = I.string A.(fg lightgreen ++ bg lightblack)

let (titles, artists) = List.split songs
let output =
  (List.map render_title titles |> column ~align:`Right)
  <|> (List.map render_artist artists |> column ~align:`Left)

Finally, you can add a column separator in various ways.

@cedlemo
Copy link
Author

cedlemo commented Dec 11, 2017

So every function that creates them from raw string or character material has to throw that exception. I updated the docs to mention the same thing for strf too, but that constraint was made pretty up-front and obvious.

Oh, ok,

now I do understand why you reacted that way, I was so focused on Format.astring that I totally forgot
the principles/goal of Notty.

again I sincerly apologize for bothering you with this, and thanks you for taking the time to help me.

@pqwy
Copy link
Owner

pqwy commented Dec 11, 2017

Heh, no need to apologize. Especially not sincerely. 😃

Here is a way to see the problem:

# print_string "\t]\n"; print_string "[\t]\n";;
        ]
[       ]
- : unit = ()

so if you remove the checks you get

# let i1, i2 = I.(string A.empty "[", string A.empty "\t]") ;;
val i1 : Notty.image = <abstr>
val i2 : Notty.image = <abstr>

# Notty_unix.(output_image (i2 <-> (i1 <|> i2) |> eol)) ;;
        ]
[       ]
- : unit = ()

so you can see that I.width i2 = I.width (i1 <|> i2). Therefore I.width i2 = I.width i1 + I.width i2, so I.width i2 = 1 + I.width i2. What is the width of i2, then? ℵ0?

It turns out the width is context-dependent, in the sense that the space i2 occupies varies dependent on the position it is printed at, as tabs align to a grid. As you can imagine, this completely destroys any calculations you can do with such images.

Every single control character will cause similar breakdown. Notty's nice API is just incompatible with allowing them in the output.

Some of them, like \n, I could parse ahead of time and turn into appropriate images (cf. #9). Others, like \t, just have no interpretation as an image at all. So I disallow them all to keep it simple and predictable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants