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

[Feature] Create default Styler for attributed string rendering #177

Merged
merged 198 commits into from Oct 6, 2019

Conversation

johnxnguyen
Copy link
Owner

@johnxnguyen johnxnguyen commented Sep 11, 2019

What’s in this PR?

It’s finally here! This PR contains a base implementation of the Styler protocol introduce in #132. With this default implementation, it will quick and easy to render attributed strings via the AST. My hope is that the implementation is flexible and broad enough to cover the majority of styling needs.

Overview

I did my best to ensure that all block elements preserved the styling of inline elements, which themselves also preserve other inline elements.

List formatting was particularly tricky, but I managed to support right aligned item markers up to a specified width as well as indentation for nested lists.

As a bonus, code blocks are rendered in colored background container, just like in Github (more on that below).

Configurability

The Styler supports three main axes of configurable attributes: fonts, text color and paragraph styling. These different types of attributes are grouped together into collections: FontCollection, ColorCollection, ParagraphStyleCollection. This allows the user to easily specify related attributes in a single place. For example, one font collection could be for static fonts, another for dynamic fonts. Or separate color collections for light and dark mode.

These collections are further grouped together into the DownStylerConfiguration struct, so that different configurations can be swapped for different rendering styles. The configuration also contains a group of other options, used to configure the appearance of the custom attributes.

Custom Attributes

Unfortunately, not all markdown elements can be visually represented using an NSAttributedString. These include the stripes for block quotes, the horizontal rule for thematic breaks, and the inset background container for code blocks. In order to render these elements, I defined some custom attributes.

In order to render these attributes, a custom layout manager is required. The DownLayoutManager can be wired up to an existing text view subclass to support custom attributes, or alternatively one could use the DownTextView, which is a preconfigured TextKit stack that will automatically render markdown content (with custom attributes) whenever the text property is set.

Down Text View & Debug Text View

While working on the implementation I used a variation of DownLayoutManager that draws the boundaries of line fragments. Line fragments are the bounding rectangles in which lines are laid out. The DownDebugLayoutManager will indicate the line rect fragments (the rect containing the line) in red. The used line rect fragments (the rect enclosing the text within a line fragment) are drawn in blue.

I’ve exposed DownDebugLayoutManager and DownDebugTextView because they’re useful tools to help specify the properties affecting paragraph styling.

API Breaking Changes

Some of the API declared in #132 needed to be adjusted to grant the Styler more information to work with. These include adding arguments for the nest depth for lists and quotes, the prefix length for list items, and a new style method for the list item prefix.

Note

Images aren’t yet supported (they appear just like links), but I’d like to add the support next.

Inline code elements don’t have colored backgrounds yet, but I may add support for that too at a later date.

Finally, having mostly worked with iOS, I developed this primarily from an iOS point of view. Nonetheless, the default styler works across the other platforms too.

@coveralls
Copy link

coveralls commented Oct 3, 2019

Coverage Status

Coverage decreased (-42.2%) to 51.181% when pulling 7975752 on feature/default-styler into 3f5dfe3 on master.

@johnxnguyen
Copy link
Owner Author

@iwasrobbed I'm not familiar with slather but it appears that you can't generate and merge multiple coverage reports. I believe it is possible with Codecov. What do you want to do here?

@johnxnguyen johnxnguyen marked this pull request as ready for review October 3, 2019 13:12
@iwasrobbed
Copy link
Collaborator

Hey @johnxnguyen 👋 I'll take a swing at the code coverage merging. This looks good to merge otherwise!

🙇Thanks for the monumental amount of work and thought that went into this. It's a well thought out implementation and will act as a great foundation for people to continue building upon

@johnxnguyen
Copy link
Owner Author

@iwasrobbed thanks! Sorry it took so long, lately I could only work on it in the mornings before work. I'm just glad it's done and people can start using it.

@codecov-io
Copy link

codecov-io commented Oct 4, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@3f5dfe3). Click here to learn what that means.
The diff coverage is 81.48%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master     #177   +/-   ##
=========================================
  Coverage          ?   70.23%           
=========================================
  Files             ?       53           
  Lines             ?     1038           
  Branches          ?        0           
=========================================
  Hits              ?      729           
  Misses            ?      309           
  Partials          ?        0
Impacted Files Coverage Δ
Source/Extensions/NSAttributedString+HTML.swift 0% <ø> (ø)
Source/Renderers/DownHTMLRenderable.swift 0% <ø> (ø)
Source/AST/Nodes/LineBreak.swift 100% <ø> (ø)
Source/AST/Nodes/ThematicBreak.swift 100% <ø> (ø)
Source/AST/Nodes/Link.swift 100% <ø> (ø)
Source/AST/Nodes/Code.swift 100% <ø> (ø)
Source/Renderers/DownCommonMarkRenderable.swift 0% <ø> (ø)
Source/AST/Nodes/Strong.swift 100% <ø> (ø)
Source/AST/Nodes/Heading.swift 100% <ø> (ø)
Source/Down.swift 100% <ø> (ø)
... and 42 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3f5dfe3...a580178. Read the comment docs.

@iwasrobbed
Copy link
Collaborator

Looks like that last commit finally did the trick (~70% coverage) 😅 CI test reporting is always a maze to get right.

Feel free to merge whenever you're ready and thank you again!

@thepost
Copy link

thepost commented Sep 2, 2020

Could you guys document this a little bit more please? There's some convenient API's here, but I have to dig right into the interface and the PRs to try to piece them together.

Actually if you're ok with it I can make the PR on the readme?

@iwasrobbed-ks
Copy link
Collaborator

Hi @thepost 👋 There's an open ticket to address this, just not much time to actually do so: #137

Always open to community help.

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