jtdaugherty / word-wrap

A Haskell library for wrapping long lines of text
BSD 3-Clause "New" or "Revised" License
8 stars 3 forks source link

Wrapping with lines after the first indented? #8

Closed byorgey closed 3 years ago

byorgey commented 3 years ago

I would really like a wrapping mode where every line after the first line is indented, e.g. something like

"This is a really long line" -->  "This is a\n  really\n  long line."

Would you be open to a PR implementing this functionality? What do you think would be the best way to go about it? Perhaps adding a field to the WrapSettings of type Maybe Int (or just Int)? I'm happy to take a crack at implementing it but wanted to make sure we agree on the best approach first.

jtdaugherty commented 3 years ago

On its face this doesn't seem like a crazy thing to add to the library, but I do worry about feature creep only because I know how far this rabbit hole goes. (Have you looked at par? 😊)

This request makes me think about other things people could reasonably want, like "just indent the first line" or "indent all lines at the same level as any existing first-line indentation." I don't know of an API that would make those possible as well, and maybe we don't need to worry about those cases, but I am just trying to think ahead about how adding this feature might suggest that those others are missing.

I'm open to a PR if you would like to hack on this. It does occur to me that if WrapSettings is going to get a new field along these lines, it might be useful to generalize this "indentation strategy" notion a bit beyond just an Int or Maybe Int for this specific case, and instead add a field whose value is of a new type that has a few constructors (or maybe one, for now) to capture these different indentation behaviors.

What do you think?

jtdaugherty commented 3 years ago

(Also, another thought I just had: in Emacs-land this is called "filling", as I recall, which goes a bit beyond just wrapping long lines. So maybe it would be conventional to use the term "fill" somewhere in the name of a new settings field.)

byorgey commented 3 years ago

Hah, indeed, I know exactly what you mean about feature creep. I hope we can find a solution that is reasonably general but doesn't just open a floodgate of crazy features.

I hadn't made the connection to filling in emacs but that's a very fruitful connection. We definitely shouldn't add an "auto fill" mode like emacs has, I don't even want to think about how much convoluted code that must be. But I think your idea of adding a "fill strategy" field sounds good. How about this for a first cut?

data FillStrategy
  = NoFill             -- ^ Don't do any filling (default)
  | FillIndent Int     -- ^ Indent every line after the first by this many spaces
  | FillPrefix T.Text  -- ^ Prepend this text to every line after the first

I could also imagine a flag specifying whether the fill strategy should also be applied to the first line or not? But maybe it's simpler to just say that if you want that, you can just add the fill to the beginning manually before passing it to the text wrapping function.

jtdaugherty commented 3 years ago

It seems to me that this feature could have settings on two axes: which line(s) to affect, and how to affect them. I could read FillIndent to mean other things than "all lines after the first", and that same "all lines after the first" is implied in the FillPrefix constructor. But a user could reasonably want to affect all lines instead. That leads me to think that we could have two types: your type (which would configure the second axis I mentioned) and another type,

data FillScope = FillNone | FillFirst | FillAfterFirst

Then the combination of those two values (both new fields in WrapSettings) would govern which lines are impacted, and how.

jtdaugherty commented 3 years ago

(I now see above that you had the same thought.)

byorgey commented 3 years ago

I have made some good progress but I am now a little uncertain how filling should interact with the preserveIndentation feature. Currently I'm thinking that any indentation generated by preserveIndentation should come at the beginning of each line, followed by any additional indentation or prefix generated by the FillStrategy.