Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e754ab1c80 | |||
| 3b07bb52cf | |||
| 055f818ed7 | |||
| 9997dc00cb | |||
| e2b597d469 | |||
| bf24fcbb2d | |||
| f34b166be1 | |||
| 0586cec03b | |||
| 2524b62470 | |||
| f83e9a2566 | |||
| 3ac921e3a9 | |||
| d127a624d3 | |||
| 0bcd20dc56 | |||
| 4fb13c2fac | |||
| 4c1c888152 | |||
| 5abcbcca06 | |||
| 69c7029e1f | |||
| 21d522d876 | |||
| f2e4658f79 | |||
| 277507d0af | |||
| cbe21adfdc | |||
| 5a0b527000 | |||
| 731f6bbab2 | |||
| 8f380a5558 | |||
| 6689a8fb6b | |||
| 968ef0d4ba | |||
| fdfa661aa7 | |||
| ff68cfec88 | |||
| 296ad5409a | |||
| a23efb1527 | |||
| 427aec0a0a | |||
| 6638a36b26 | |||
| c389ca6624 | |||
| dd2a448eb4 | |||
| de6c58760f | |||
| 2aada56e6a | |||
| 69a006cd1b | |||
| 79c3d29f13 | |||
| 907d67cb59 | |||
| cd1a3f6565 | |||
| b99cbca24f | |||
| 0095468027 | |||
| c20e8e2d4c | |||
| 5aa5a55193 | |||
| 940b173fc1 | |||
| 02d90cc5ff | |||
| 3f5dfe3ed8 | |||
| cea0e2df5a | |||
| 4c72856a5c | |||
| 2e2a8f2f0c | |||
| 7c5d45ac9e | |||
| dcf86dcce5 | |||
| 805e537949 | |||
| 0e383bc1bb | |||
| 4e4ddcef85 | |||
| 5f54bc0168 | |||
| 6d63c13cc1 | |||
| 589545794f | |||
| 0afc8c18d9 | |||
| d94b270cff | |||
| 80d8b2d50d | |||
| 5396a85265 | |||
| 2b25ee0a0c | |||
| 7b25a10457 | |||
| f7dacd7d2c | |||
| 2d64aae0d0 | |||
| cb9ee72196 | |||
| 4a1ad245e0 | |||
| ae031a3668 | |||
| d32bc14333 | |||
| f82b61ff8e | |||
| 606c1e14dd |
@@ -0,0 +1,17 @@
|
||||
name: SwiftLint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/swiftlint.yml'
|
||||
- '.swiftlint.yml'
|
||||
- '**/*.swift'
|
||||
|
||||
jobs:
|
||||
SwiftLint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: GitHub Action for SwiftLint
|
||||
uses: norio-nomura/action-swiftlint@3.2.1
|
||||
|
||||
+1
-1
@@ -1,9 +1,9 @@
|
||||
Pods/
|
||||
.build/
|
||||
.DS_Store
|
||||
xcuserdata
|
||||
|
||||
# additional ignores that will save us time
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
coverage_service: coveralls
|
||||
xcodeproj: Down.xcodeproj
|
||||
source_directory: Source
|
||||
ignore:
|
||||
- Source/cmark/*
|
||||
@@ -1 +0,0 @@
|
||||
5.0
|
||||
@@ -0,0 +1,10 @@
|
||||
included:
|
||||
- Sources/Down
|
||||
- Tests
|
||||
|
||||
large_tuple:
|
||||
warning: 3
|
||||
error: 4
|
||||
|
||||
cyclomatic_complexity:
|
||||
ignores_case_statements: true
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
+8
-8
@@ -1,12 +1,12 @@
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode12.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- set -o pipefail
|
||||
- gem install xcpretty slather -N
|
||||
- xcrun simctl boot "iPhone 7" || echo "(Pre)Launched the simulator."
|
||||
- xcrun simctl boot "iPhone 12" || echo "(Pre)Launched the simulator."
|
||||
script:
|
||||
- travis_retry xcodebuild -project Down.xcodeproj -scheme "Down" -destination "platform=iOS Simulator,name=iPhone 7" -enableCodeCoverage YES ONLY_ACTIVE_ARCH=YES test | xcpretty -c
|
||||
- travis_retry xcodebuild -project Down.xcodeproj -scheme "Down" -sdk macosx -destination 'platform=OS X,arch=x86_64' -enableCodeCoverage YES test | xcpretty -c
|
||||
- travis_retry xcodebuild -project Down.xcodeproj -scheme "Down" -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV' -enableCodeCoverage YES test | xcpretty -c
|
||||
after_success:
|
||||
- slather coverage --ignore "../**/*/Xcode*" --ignore "Source/cmark/*" --scheme "Down" Down.xcodeproj
|
||||
- travis_retry xcodebuild -project Down.xcodeproj -scheme "Down" -sdk iphonesimulator -destination "platform=iOS Simulator,OS=14.2,name=iPhone 12" -enableCodeCoverage YES ONLY_ACTIVE_ARCH=YES -quiet test
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- travis_retry xcodebuild -project Down.xcodeproj -scheme "Down" -sdk macosx -destination 'platform=OS X,arch=x86_64' -enableCodeCoverage YES -quiet test
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- travis_retry xcodebuild -project Down.xcodeproj -scheme "Down" -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV' -enableCodeCoverage YES -quiet test
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
+491
-238
@@ -1,358 +1,611 @@
|
||||
# Change Log
|
||||
# Changelog
|
||||
|
||||
## [v0.8.0](https://github.com/iwasrobbed/Down/tree/v0.8.0) (2019-04-24)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.7.0...v0.8.0)
|
||||
## [v0.11.0](https://github.com/johnxnguyen/Down/tree/v0.11.0) (2021-05-04)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 0.7.0 problems with NSAttributedString.Key [\#139](https://github.com/iwasrobbed/Down/issues/139)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Down\] Add new `unsafe` option [\#143](https://github.com/iwasrobbed/Down/pull/143) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Bump cmark to 0.29.0 [\#142](https://github.com/iwasrobbed/Down/pull/142) ([larryonoff](https://github.com/larryonoff))
|
||||
|
||||
## [v0.7.0](https://github.com/iwasrobbed/Down/tree/v0.7.0) (2019-04-24)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.6...v0.7.0)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.10.0...v0.11.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[Documentation\] AST API [\#134](https://github.com/iwasrobbed/Down/issues/134)
|
||||
- \[Attributed Strings\] Line spacing more than expected [\#121](https://github.com/iwasrobbed/Down/issues/121)
|
||||
- \[Down\] Rendering to attributed string is really slow, requires main thread [\#100](https://github.com/iwasrobbed/Down/issues/100)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Set Swift version 4.0 in podspec [\#140](https://github.com/iwasrobbed/Down/pull/140) ([larryonoff](https://github.com/larryonoff))
|
||||
- \[Cleanup\] Comment docs, example apps, and whitespace [\#136](https://github.com/iwasrobbed/Down/pull/136) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- \[Feature\] Create API for parsing to AST and NSAttributedString [\#132](https://github.com/iwasrobbed/Down/pull/132) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
|
||||
## [v0.6.6](https://github.com/iwasrobbed/Down/tree/v0.6.6) (2019-04-11)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.5...v0.6.6)
|
||||
- \[CodeCoverage\] Improve accuracy for combined code coverage reporting [\#205](https://github.com/johnxnguyen/Down/issues/205)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Swift 4/5 compatibility [\#131](https://github.com/iwasrobbed/Down/issues/131)
|
||||
- DownStyler not included when installed via CocoaPods [\#254](https://github.com/johnxnguyen/Down/issues/254)
|
||||
- \[Commonmark\] Strikethrough not working / not supported [\#253](https://github.com/johnxnguyen/Down/issues/253)
|
||||
- \[Attributed Strings\] Unordered list items with a single line appear further indented than those with multiple lines when using a custom font [\#246](https://github.com/johnxnguyen/Down/issues/246)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Wrap openURL so that Down compiles in app extensions [\#133](https://github.com/iwasrobbed/Down/pull/133) ([nheagy](https://github.com/nheagy))
|
||||
- \[Feature\] Custom list prefixes for AttributedStringVisitor [\#255](https://github.com/johnxnguyen/Down/pull/255) ([dloic](https://github.com/dloic))
|
||||
- \[Chore\] Add SwiftLint [\#252](https://github.com/johnxnguyen/Down/pull/252) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
- \[Chore\] Fix codecov report [\#251](https://github.com/johnxnguyen/Down/pull/251) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
|
||||
## [v0.6.5](https://github.com/iwasrobbed/Down/tree/v0.6.5) (2019-04-02)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.4...v0.6.5)
|
||||
## [v0.10.0](https://github.com/johnxnguyen/Down/tree/v0.10.0) (2021-02-28)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix Xcode 10.2 warnings [\#130](https://github.com/iwasrobbed/Down/pull/130) ([mdiep](https://github.com/mdiep))
|
||||
|
||||
## [v0.6.4](https://github.com/iwasrobbed/Down/tree/v0.6.4) (2019-03-30)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.3...v0.6.4)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.5...v0.10.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Support SwiftPM [\#128](https://github.com/iwasrobbed/Down/issues/128)
|
||||
- \[DownView\] Load multiple .md files \(link support\) [\#68](https://github.com/iwasrobbed/Down/issues/68)
|
||||
- Does not build in 12.5 [\#244](https://github.com/johnxnguyen/Down/issues/244)
|
||||
- \[Crash\] Missing resource bundle when using SPM [\#243](https://github.com/johnxnguyen/Down/issues/243)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix Swift module errors when used alongside Firestore [\#125](https://github.com/iwasrobbed/Down/pull/125) ([vzsg](https://github.com/vzsg))
|
||||
- \[Improvement\] Expose DownTextView's designated initializer [\#250](https://github.com/johnxnguyen/Down/pull/250) ([max-potapov](https://github.com/max-potapov))
|
||||
- \[Chore\] Add arm64 as valid arch when building for simulator on M1 macs [\#249](https://github.com/johnxnguyen/Down/pull/249) ([michaelknoch](https://github.com/michaelknoch))
|
||||
- \[Chore\] Reorganize project structure for SPM [\#248](https://github.com/johnxnguyen/Down/pull/248) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
- \[Chore\] Use SPM to manage snapshot testing dependency [\#247](https://github.com/johnxnguyen/Down/pull/247) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
|
||||
## [v0.6.3](https://github.com/iwasrobbed/Down/tree/v0.6.3) (2019-03-27)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.2...v0.6.3)
|
||||
## [v0.9.5](https://github.com/johnxnguyen/Down/tree/v0.9.5) (2021-02-12)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.4...v0.9.5)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Namespacing issues with Down "Node" type [\#242](https://github.com/johnxnguyen/Down/issues/242)
|
||||
- GitHub actions build failure: `small method list` [\#238](https://github.com/johnxnguyen/Down/issues/238)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Fix\] Compilation failure with Xcode 12.5 and SPM [\#245](https://github.com/johnxnguyen/Down/pull/245) ([claurel](https://github.com/claurel))
|
||||
- \[Chore\] Update readme [\#237](https://github.com/johnxnguyen/Down/pull/237) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
|
||||
## [v0.9.4](https://github.com/johnxnguyen/Down/tree/v0.9.4) (2020-10-21)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.3...v0.9.4)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[DownView\] Doesn't reflow text on orientation change [\#111](https://github.com/iwasrobbed/Down/issues/111)
|
||||
- Create custom sequence to access child nodes [\#228](https://github.com/johnxnguyen/Down/pull/228) ([5sw](https://github.com/5sw))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- DownStylerConfiguration Link Color Not Working [\#232](https://github.com/johnxnguyen/Down/issues/232)
|
||||
- SwiftUI support [\#231](https://github.com/johnxnguyen/Down/issues/231)
|
||||
- How to pre-calculate height needed for attributed string when using DownLayoutManager [\#226](https://github.com/johnxnguyen/Down/issues/226)
|
||||
- How i can render both markdown and Latex ? [\#221](https://github.com/johnxnguyen/Down/issues/221)
|
||||
- Emphasis + Strong [\#220](https://github.com/johnxnguyen/Down/issues/220)
|
||||
- \[StackOverflow\] Creating a new Visitor leads to wrapping value error [\#218](https://github.com/johnxnguyen/Down/issues/218)
|
||||
- 0.9.0/0.9.1 don't build with Swift 5.0.x [\#217](https://github.com/johnxnguyen/Down/issues/217)
|
||||
- Unable to build Swift package in Xcode 11.4.1 [\#209](https://github.com/johnxnguyen/Down/issues/209)
|
||||
- \[Feature\] Add support for Mac Catalyst [\#208](https://github.com/johnxnguyen/Down/issues/208)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Fix\] DownTextView renders incorrect link color [\#233](https://github.com/johnxnguyen/Down/pull/233) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
- Added instructions for using the Swift Package Manager [\#230](https://github.com/johnxnguyen/Down/pull/230) ([klm1](https://github.com/klm1))
|
||||
- Use case let as instead of case is and force casting later. [\#227](https://github.com/johnxnguyen/Down/pull/227) ([5sw](https://github.com/5sw))
|
||||
- Add macOS arm64 platform [\#224](https://github.com/johnxnguyen/Down/pull/224) ([jasminlapalme](https://github.com/jasminlapalme))
|
||||
|
||||
## [v0.9.3](https://github.com/johnxnguyen/Down/tree/v0.9.3) (2020-06-12)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.2...v0.9.3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Line breaks between list items are not parsed correctly [\#214](https://github.com/johnxnguyen/Down/issues/214)
|
||||
- Can't build with copied sources [\#211](https://github.com/johnxnguyen/Down/issues/211)
|
||||
- hard blank line insertion after list [\#210](https://github.com/johnxnguyen/Down/issues/210)
|
||||
- Cocoapod version 0.9.2 not available. [\#206](https://github.com/johnxnguyen/Down/issues/206)
|
||||
- \[Feature\] Local images not accessible from WKWebView [\#198](https://github.com/johnxnguyen/Down/issues/198)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Chore\] Bump swift snapshot testing to 1.7.2 [\#216](https://github.com/johnxnguyen/Down/pull/216) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
- Add tightness property to List node [\#215](https://github.com/johnxnguyen/Down/pull/215) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
- Add styling options for level 4 to 6 headings [\#207](https://github.com/johnxnguyen/Down/pull/207) ([mathebox](https://github.com/mathebox))
|
||||
- \[DownView\] Add parameter so bundle is writable [\#200](https://github.com/johnxnguyen/Down/pull/200) ([brunnobga](https://github.com/brunnobga))
|
||||
|
||||
## [v0.9.2](https://github.com/johnxnguyen/Down/tree/v0.9.2) (2020-03-03)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.1...v0.9.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Update Framework with Swift 5.1 [\#178](https://github.com/johnxnguyen/Down/issues/178)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Swift 5.1 Support [\#204](https://github.com/johnxnguyen/Down/pull/204) ([ghost](https://github.com/ghost))
|
||||
- Resolves Swift Package Manager issue related to swift-snapshot-testing [\#203](https://github.com/johnxnguyen/Down/pull/203) ([ghost](https://github.com/ghost))
|
||||
|
||||
## [v0.9.1](https://github.com/johnxnguyen/Down/tree/v0.9.1) (2020-02-28)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.0...v0.9.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Added Linux support. [\#172](https://github.com/johnxnguyen/Down/pull/172) ([vgorloff](https://github.com/vgorloff))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- SwiftPM : Resolve apparent version incompatibility with swift-snapshot-testing [\#202](https://github.com/johnxnguyen/Down/issues/202)
|
||||
- Release fixes made after 0.9.0 [\#201](https://github.com/johnxnguyen/Down/issues/201)
|
||||
- Swift UI Support [\#199](https://github.com/johnxnguyen/Down/issues/199)
|
||||
- 'BaseNode' initializer is inaccessible due to 'internal' protection level [\#196](https://github.com/johnxnguyen/Down/issues/196)
|
||||
- Any emoji support? [\#195](https://github.com/johnxnguyen/Down/issues/195)
|
||||
- Swift Packege maneger? [\#194](https://github.com/johnxnguyen/Down/issues/194)
|
||||
- Regression: single newline syntax not working \(any variety\) [\#191](https://github.com/johnxnguyen/Down/issues/191)
|
||||
- Down cannot convert this markdown string to html [\#190](https://github.com/johnxnguyen/Down/issues/190)
|
||||
- App using xcframework with Down pod dependency causes crash [\#187](https://github.com/johnxnguyen/Down/issues/187)
|
||||
- Is the text supposed to be rendering this large? [\#186](https://github.com/johnxnguyen/Down/issues/186)
|
||||
- Issue with markdown render/convert to attribute string on macOS latest version [\#185](https://github.com/johnxnguyen/Down/issues/185)
|
||||
- Table are not render [\#183](https://github.com/johnxnguyen/Down/issues/183)
|
||||
- How to change text color? [\#182](https://github.com/johnxnguyen/Down/issues/182)
|
||||
- incorrect parse for string that is a mixture of markdown and html [\#180](https://github.com/johnxnguyen/Down/issues/180)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Improve configurability of DownStyler [\#188](https://github.com/johnxnguyen/Down/pull/188) ([mgacy](https://github.com/mgacy))
|
||||
- Make color & font collection initializers public [\#184](https://github.com/johnxnguyen/Down/pull/184) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
|
||||
## [v0.9.0](https://github.com/johnxnguyen/Down/tree/v0.9.0) (2019-10-06)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.6...v0.9.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Please add Styler example in the documentation [\#179](https://github.com/johnxnguyen/Down/issues/179)
|
||||
- \[Attributed Strings\] Can the `Styler` know which list item marker was parsed? [\#176](https://github.com/johnxnguyen/Down/issues/176)
|
||||
- Error: 'cmark\_export.h' file not found with \<angled\> include; use "quotes" instead [\#175](https://github.com/johnxnguyen/Down/issues/175)
|
||||
- GIFF Support [\#174](https://github.com/johnxnguyen/Down/issues/174)
|
||||
- Help: Set Default Font [\#168](https://github.com/johnxnguyen/Down/issues/168)
|
||||
- \[Testing\] Adding a snapshot testing framework [\#165](https://github.com/johnxnguyen/Down/issues/165)
|
||||
- Adding a snapshot test framework [\#164](https://github.com/johnxnguyen/Down/issues/164)
|
||||
- XCode Beta 4 Build Error [\#162](https://github.com/johnxnguyen/Down/issues/162)
|
||||
- \[Attributed Strings\] Create default `Styler` for attributed string rendering [\#138](https://github.com/johnxnguyen/Down/issues/138)
|
||||
- \[Help out\] Collaborators wanted! Help us improve Down [\#105](https://github.com/johnxnguyen/Down/issues/105)
|
||||
- \[DownView\] Support for internal links? [\#93](https://github.com/johnxnguyen/Down/issues/93)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Feature\] Create default `Styler` for attributed string rendering [\#177](https://github.com/johnxnguyen/Down/pull/177) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
- Resolve xcode11beta4 issue. [\#170](https://github.com/johnxnguyen/Down/pull/170) ([ykphuah](https://github.com/ykphuah))
|
||||
- Minor documentation fix [\#169](https://github.com/johnxnguyen/Down/pull/169) ([nighthawk](https://github.com/nighthawk))
|
||||
|
||||
## [v0.8.6](https://github.com/johnxnguyen/Down/tree/v0.8.6) (2019-07-11)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.5...v0.8.6)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Update Options to support Unsafe Rendering [\#159](https://github.com/johnxnguyen/Down/issues/159)
|
||||
- .toAttributedString stylesheet parameter [\#158](https://github.com/johnxnguyen/Down/issues/158)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Updates for unsafe option [\#160](https://github.com/johnxnguyen/Down/pull/160) ([hbowie](https://github.com/hbowie))
|
||||
- Fix permissions error on Catalina beta 2 [\#156](https://github.com/johnxnguyen/Down/pull/156) ([mdiep](https://github.com/mdiep))
|
||||
|
||||
## [v0.8.5](https://github.com/johnxnguyen/Down/tree/v0.8.5) (2019-06-13)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.4...v0.8.5)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- DebugVisitor is missing a public initializer [\#152](https://github.com/johnxnguyen/Down/issues/152)
|
||||
- Can't build with Swift 5.1 with SwiftPM [\#151](https://github.com/johnxnguyen/Down/issues/151)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[SPM\] Fixes error with missing headers [\#154](https://github.com/johnxnguyen/Down/pull/154) ([aasimk2000](https://github.com/aasimk2000))
|
||||
- Create Public Initializer for DebugVisitor [\#153](https://github.com/johnxnguyen/Down/pull/153) ([mfcollins3](https://github.com/mfcollins3))
|
||||
|
||||
## [v0.8.4](https://github.com/johnxnguyen/Down/tree/v0.8.4) (2019-06-04)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.3...v0.8.4)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- \[Carthage\] Missing required module 'libcmark' [\#120](https://github.com/johnxnguyen/Down/issues/120)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add Swift Package Manager support [\#150](https://github.com/johnxnguyen/Down/pull/150) ([aasimk2000](https://github.com/aasimk2000))
|
||||
- \[AST\] Replace line separator with paragraph separator. [\#149](https://github.com/johnxnguyen/Down/pull/149) ([fgulan](https://github.com/fgulan))
|
||||
|
||||
## [v0.8.3](https://github.com/johnxnguyen/Down/tree/v0.8.3) (2019-05-15)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.2...v0.8.3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Pass DownOptions to DownView [\#147](https://github.com/johnxnguyen/Down/issues/147)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Feature - pass DownOptions to init and update [\#148](https://github.com/johnxnguyen/Down/pull/148) ([ladislas](https://github.com/ladislas))
|
||||
|
||||
## [v0.8.2](https://github.com/johnxnguyen/Down/tree/v0.8.2) (2019-05-10)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.1...v0.8.2)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Mark as safe for app extension use. [\#146](https://github.com/johnxnguyen/Down/pull/146) ([sgoodwin](https://github.com/sgoodwin))
|
||||
|
||||
## [v0.8.1](https://github.com/johnxnguyen/Down/tree/v0.8.1) (2019-04-26)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.8.0...v0.8.1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Swift\] Update to Swift 5.0 [\#145](https://github.com/johnxnguyen/Down/pull/145) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.8.0](https://github.com/johnxnguyen/Down/tree/v0.8.0) (2019-04-24)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.7.0...v0.8.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 0.7.0 problems with NSAttributedString.Key [\#139](https://github.com/johnxnguyen/Down/issues/139)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Down\] Add new `unsafe` option [\#143](https://github.com/johnxnguyen/Down/pull/143) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Bump cmark to 0.29.0 [\#142](https://github.com/johnxnguyen/Down/pull/142) ([larryonoff](https://github.com/larryonoff))
|
||||
|
||||
## [v0.7.0](https://github.com/johnxnguyen/Down/tree/v0.7.0) (2019-04-24)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.6...v0.7.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[Documentation\] AST API [\#134](https://github.com/johnxnguyen/Down/issues/134)
|
||||
- \[Attributed Strings\] Line spacing more than expected [\#121](https://github.com/johnxnguyen/Down/issues/121)
|
||||
- \[Down\] Rendering to attributed string is really slow, requires main thread [\#100](https://github.com/johnxnguyen/Down/issues/100)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Set Swift version 4.0 in podspec [\#140](https://github.com/johnxnguyen/Down/pull/140) ([larryonoff](https://github.com/larryonoff))
|
||||
- \[Cleanup\] Comment docs, example apps, and whitespace [\#136](https://github.com/johnxnguyen/Down/pull/136) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- \[Feature\] Create API for parsing to AST and NSAttributedString [\#132](https://github.com/johnxnguyen/Down/pull/132) ([johnxnguyen](https://github.com/johnxnguyen))
|
||||
|
||||
## [v0.6.6](https://github.com/johnxnguyen/Down/tree/v0.6.6) (2019-04-11)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.5...v0.6.6)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Swift 4/5 compatibility [\#131](https://github.com/johnxnguyen/Down/issues/131)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Wrap openURL so that Down compiles in app extensions [\#133](https://github.com/johnxnguyen/Down/pull/133) ([nheagy](https://github.com/nheagy))
|
||||
|
||||
## [v0.6.5](https://github.com/johnxnguyen/Down/tree/v0.6.5) (2019-04-02)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.4...v0.6.5)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix Xcode 10.2 warnings [\#130](https://github.com/johnxnguyen/Down/pull/130) ([mdiep](https://github.com/mdiep))
|
||||
|
||||
## [v0.6.4](https://github.com/johnxnguyen/Down/tree/v0.6.4) (2019-03-30)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.3...v0.6.4)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Support SwiftPM [\#128](https://github.com/johnxnguyen/Down/issues/128)
|
||||
- \[DownView\] Load multiple .md files \(link support\) [\#68](https://github.com/johnxnguyen/Down/issues/68)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix Swift module errors when used alongside Firestore [\#125](https://github.com/johnxnguyen/Down/pull/125) ([vzsg](https://github.com/vzsg))
|
||||
|
||||
## [v0.6.3](https://github.com/johnxnguyen/Down/tree/v0.6.3) (2019-03-27)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.2...v0.6.3)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[DownView\] Doesn't reflow text on orientation change [\#111](https://github.com/johnxnguyen/Down/issues/111)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Crash rendering markdown [\#126](https://github.com/iwasrobbed/Down/issues/126)
|
||||
- Crash rendering markdown [\#126](https://github.com/johnxnguyen/Down/issues/126)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Cocoapods: libcmark [\#124](https://github.com/iwasrobbed/Down/issues/124)
|
||||
- Use with storyboards [\#123](https://github.com/iwasrobbed/Down/issues/123)
|
||||
- support for audio markdown? [\#122](https://github.com/iwasrobbed/Down/issues/122)
|
||||
- \[Down\] Can't render toAttributedString while app is in background [\#116](https://github.com/iwasrobbed/Down/issues/116)
|
||||
- Cocoapods: libcmark [\#124](https://github.com/johnxnguyen/Down/issues/124)
|
||||
- Use with storyboards [\#123](https://github.com/johnxnguyen/Down/issues/123)
|
||||
- support for audio markdown? [\#122](https://github.com/johnxnguyen/Down/issues/122)
|
||||
- \[Down\] Can't render toAttributedString while app is in background [\#116](https://github.com/johnxnguyen/Down/issues/116)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix crash from missing parser.h include [\#129](https://github.com/iwasrobbed/Down/pull/129) ([phoney](https://github.com/phoney))
|
||||
- Make the DownView reflow text on device rotation [\#127](https://github.com/iwasrobbed/Down/pull/127) ([phoney](https://github.com/phoney))
|
||||
- Fix crash from missing parser.h include [\#129](https://github.com/johnxnguyen/Down/pull/129) ([phoney](https://github.com/phoney))
|
||||
- Make the DownView reflow text on device rotation [\#127](https://github.com/johnxnguyen/Down/pull/127) ([phoney](https://github.com/phoney))
|
||||
|
||||
## [v0.6.2](https://github.com/iwasrobbed/Down/tree/v0.6.2) (2018-11-28)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.1...v0.6.2)
|
||||
## [v0.6.2](https://github.com/johnxnguyen/Down/tree/v0.6.2) (2018-11-28)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.1...v0.6.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[cmark\] Some characters are escaped twice [\#99](https://github.com/iwasrobbed/Down/issues/99)
|
||||
- \[cmark\] Some characters are escaped twice [\#99](https://github.com/johnxnguyen/Down/issues/99)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add compiler flag to suppress implicit conversion warnings [\#118](https://github.com/johnxnguyen/Down/pull/118) ([phoney](https://github.com/phoney))
|
||||
|
||||
## [v0.6.1](https://github.com/johnxnguyen/Down/tree/v0.6.1) (2018-11-23)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.6.0...v0.6.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 2 Swift Compiler Errors when installing Down on iOS [\#117](https://github.com/johnxnguyen/Down/issues/117)
|
||||
- How to update to the latest version of the cmark library [\#115](https://github.com/johnxnguyen/Down/issues/115)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[travis\] Update to retry [\#114](https://github.com/johnxnguyen/Down/pull/114) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Fix macOS Platform, Custom URL Scheme Handler, Polish Demos. [\#110](https://github.com/johnxnguyen/Down/pull/110) ([chriszielinski](https://github.com/chriszielinski))
|
||||
|
||||
## [v0.6.0](https://github.com/johnxnguyen/Down/tree/v0.6.0) (2018-11-10)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.5.3...v0.6.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[iOS 10+\] Warnings for WebKit signal service and latex.c [\#94](https://github.com/johnxnguyen/Down/issues/94)
|
||||
- Update cmark version to latest stable release [\#84](https://github.com/johnxnguyen/Down/issues/84)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- HTML to Markdowndow? [\#107](https://github.com/johnxnguyen/Down/issues/107)
|
||||
- Blockquote does not work in NSAttributedString [\#106](https://github.com/johnxnguyen/Down/issues/106)
|
||||
- Support for Dynamic Type [\#90](https://github.com/johnxnguyen/Down/issues/90)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Down\] Bump to v0.6.0 [\#113](https://github.com/johnxnguyen/Down/pull/113) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- \[cmark\] Update lib to v0.28.3 [\#112](https://github.com/johnxnguyen/Down/pull/112) ([phoney](https://github.com/phoney))
|
||||
- Update project to Xcode 10 [\#109](https://github.com/johnxnguyen/Down/pull/109) ([funkyboy](https://github.com/funkyboy))
|
||||
|
||||
## [v0.5.3](https://github.com/johnxnguyen/Down/tree/v0.5.3) (2018-09-19)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.5.2...v0.5.3)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- ” not being rendered [\#95](https://github.com/johnxnguyen/Down/issues/95)
|
||||
- Update issue templates [\#101](https://github.com/johnxnguyen/Down/pull/101) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \\[cmark\\] Some characters are escaped twice [\#99](https://github.com/iwasrobbed/Down/issues/99)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add compiler flag to suppress implicit conversion warnings [\#118](https://github.com/iwasrobbed/Down/pull/118) ([phoney](https://github.com/phoney))
|
||||
|
||||
## [v0.6.1](https://github.com/iwasrobbed/Down/tree/v0.6.1) (2018-11-23)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.6.0...v0.6.1)
|
||||
- \[Xcode 10\] Crash in XCBuildService; need to use old build system [\#91](https://github.com/johnxnguyen/Down/issues/91)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 2 Swift Compiler Errors when installing Down on iOS [\#117](https://github.com/iwasrobbed/Down/issues/117)
|
||||
- How to update to the latest version of the cmark library [\#115](https://github.com/iwasrobbed/Down/issues/115)
|
||||
- DownView font size on iPad is huge [\#102](https://github.com/johnxnguyen/Down/issues/102)
|
||||
- Is there a way to convert NSAttributedString back to markdown? [\#98](https://github.com/johnxnguyen/Down/issues/98)
|
||||
- Back Gesture [\#96](https://github.com/johnxnguyen/Down/issues/96)
|
||||
- Access for [\#92](https://github.com/johnxnguyen/Down/issues/92)
|
||||
- Image size NSAttributedString [\#89](https://github.com/johnxnguyen/Down/issues/89)
|
||||
- Dependency analysis warnings with Cocoapods [\#88](https://github.com/johnxnguyen/Down/issues/88)
|
||||
- WatchKit Support [\#71](https://github.com/johnxnguyen/Down/issues/71)
|
||||
- Installation via Swift Package Manager [\#61](https://github.com/johnxnguyen/Down/issues/61)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[travis\] Update to retry [\#114](https://github.com/iwasrobbed/Down/pull/114) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Fix macOS Platform, Custom URL Scheme Handler, Polish Demos. [\#110](https://github.com/iwasrobbed/Down/pull/110) ([chriszielinski](https://github.com/chriszielinski))
|
||||
- \[Xcode 10\]\[Carthage\] Use new build system [\#104](https://github.com/johnxnguyen/Down/pull/104) ([torokzsolt](https://github.com/torokzsolt))
|
||||
- Updates the project settings to use the Legacy Build System. [\#97](https://github.com/johnxnguyen/Down/pull/97) ([pieromattos](https://github.com/pieromattos))
|
||||
- \[Release\] v0.5.2 [\#87](https://github.com/johnxnguyen/Down/pull/87) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.6.0](https://github.com/iwasrobbed/Down/tree/v0.6.0) (2018-11-10)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.5.3...v0.6.0)
|
||||
## [v0.5.2](https://github.com/johnxnguyen/Down/tree/v0.5.2) (2018-05-05)
|
||||
|
||||
**Implemented enhancements:**
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.5.1...v0.5.2)
|
||||
|
||||
- \[iOS 10+\] Warnings for WebKit signal service and latex.c [\#94](https://github.com/iwasrobbed/Down/issues/94)
|
||||
- Update cmark version to latest stable release [\#84](https://github.com/iwasrobbed/Down/issues/84)
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Pods\] Only include files in source\_files that can be compiled [\#86](https://github.com/johnxnguyen/Down/pull/86) ([njdehoog](https://github.com/njdehoog))
|
||||
|
||||
## [v0.5.1](https://github.com/johnxnguyen/Down/tree/v0.5.1) (2018-03-03)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.5.0...v0.5.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- HTML to Markdowndow? [\#107](https://github.com/iwasrobbed/Down/issues/107)
|
||||
- Blockquote does not work in NSAttributedString [\#106](https://github.com/iwasrobbed/Down/issues/106)
|
||||
- Support for Dynamic Type [\#90](https://github.com/iwasrobbed/Down/issues/90)
|
||||
- `DocumentReadingOptionKey` Error via pod [\#80](https://github.com/johnxnguyen/Down/issues/80)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Down\] Bump to v0.6.0 [\#113](https://github.com/iwasrobbed/Down/pull/113) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- \[cmark\] Update lib to v0.28.3 [\#112](https://github.com/iwasrobbed/Down/pull/112) ([phoney](https://github.com/phoney))
|
||||
- Update project to Xcode 10 [\#109](https://github.com/iwasrobbed/Down/pull/109) ([funkyboy](https://github.com/funkyboy))
|
||||
- Add optional stylesheet argument for NSAttributedString renderer [\#79](https://github.com/johnxnguyen/Down/pull/79) ([kengruven](https://github.com/kengruven))
|
||||
- Roll up cmark's COPYING sections into the top-level LICENSE file [\#78](https://github.com/johnxnguyen/Down/pull/78) ([kengruven](https://github.com/kengruven))
|
||||
- Update supported versions in README [\#77](https://github.com/johnxnguyen/Down/pull/77) ([kengruven](https://github.com/kengruven))
|
||||
|
||||
## [v0.5.3](https://github.com/iwasrobbed/Down/tree/v0.5.3) (2018-09-19)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.5.2...v0.5.3)
|
||||
## [v0.5.0](https://github.com/johnxnguyen/Down/tree/v0.5.0) (2018-02-24)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.4.2...v0.5.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- ” not being rendered [\#95](https://github.com/iwasrobbed/Down/issues/95)
|
||||
- Update issue templates [\#101](https://github.com/iwasrobbed/Down/pull/101) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Fix/update example app [\#58](https://github.com/johnxnguyen/Down/pull/58) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[Xcode 10\] Crash in XCBuildService; need to use old build system [\#91](https://github.com/iwasrobbed/Down/issues/91)
|
||||
- Building for tvOS fails [\#49](https://github.com/johnxnguyen/Down/issues/49)
|
||||
- Fix Carthage builds [\#72](https://github.com/johnxnguyen/Down/pull/72) ([tonyarnold](https://github.com/tonyarnold))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- DownView font size on iPad is huge [\#102](https://github.com/iwasrobbed/Down/issues/102)
|
||||
- Is there a way to convert NSAttributedString back to markdown? [\#98](https://github.com/iwasrobbed/Down/issues/98)
|
||||
- Back Gesture [\#96](https://github.com/iwasrobbed/Down/issues/96)
|
||||
- Access for [\#92](https://github.com/iwasrobbed/Down/issues/92)
|
||||
- Image size NSAttributedString [\#89](https://github.com/iwasrobbed/Down/issues/89)
|
||||
- Dependency analysis warnings with Cocoapods [\#88](https://github.com/iwasrobbed/Down/issues/88)
|
||||
- WatchKit Support [\#71](https://github.com/iwasrobbed/Down/issues/71)
|
||||
- Installation via Swift Package Manager [\#61](https://github.com/iwasrobbed/Down/issues/61)
|
||||
- Swift 3+ convention for capitalization [\#74](https://github.com/johnxnguyen/Down/issues/74)
|
||||
- macOS 10.11 support? [\#73](https://github.com/johnxnguyen/Down/issues/73)
|
||||
- Installing with Carthage for Mac fails [\#70](https://github.com/johnxnguyen/Down/issues/70)
|
||||
- Error building/installing Down [\#69](https://github.com/johnxnguyen/Down/issues/69)
|
||||
- get heigth when add downview to other view? [\#67](https://github.com/johnxnguyen/Down/issues/67)
|
||||
- iOS8 crash [\#66](https://github.com/johnxnguyen/Down/issues/66)
|
||||
- Image caching [\#65](https://github.com/johnxnguyen/Down/issues/65)
|
||||
- Some warnings to fix [\#64](https://github.com/johnxnguyen/Down/issues/64)
|
||||
- build error [\#63](https://github.com/johnxnguyen/Down/issues/63)
|
||||
- Lists and paragraph spacing [\#62](https://github.com/johnxnguyen/Down/issues/62)
|
||||
- Converting Markdown string to HTML with emojis [\#60](https://github.com/johnxnguyen/Down/issues/60)
|
||||
- Syntax highlighting themes [\#59](https://github.com/johnxnguyen/Down/issues/59)
|
||||
- Compiling error on example project [\#57](https://github.com/johnxnguyen/Down/issues/57)
|
||||
- Compilation error using Carthage [\#54](https://github.com/johnxnguyen/Down/issues/54)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Xcode 10\]\[Carthage\] Use new build system [\#104](https://github.com/iwasrobbed/Down/pull/104) ([torokzsolt](https://github.com/torokzsolt))
|
||||
- Updates the project settings to use the Legacy Build System. [\#97](https://github.com/iwasrobbed/Down/pull/97) ([pieromattos](https://github.com/pieromattos))
|
||||
- \[Release\] v0.5.2 [\#87](https://github.com/iwasrobbed/Down/pull/87) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Use lower-case Swift 3 convention for DownOptions [\#76](https://github.com/johnxnguyen/Down/pull/76) ([kengruven](https://github.com/kengruven))
|
||||
- Lower MACOSX\_DEPLOYMENT\_TARGET to include El Capitan [\#75](https://github.com/johnxnguyen/Down/pull/75) ([kengruven](https://github.com/kengruven))
|
||||
- WebKit not available on watchOS. [\#56](https://github.com/johnxnguyen/Down/pull/56) ([128keaton](https://github.com/128keaton))
|
||||
- Update README.md [\#55](https://github.com/johnxnguyen/Down/pull/55) ([128keaton](https://github.com/128keaton))
|
||||
- Updated Copyright year in ReadMe file [\#53](https://github.com/johnxnguyen/Down/pull/53) ([jobinsjohn](https://github.com/jobinsjohn))
|
||||
|
||||
## [v0.5.2](https://github.com/iwasrobbed/Down/tree/v0.5.2) (2018-05-05)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.5.1...v0.5.2)
|
||||
## [v0.4.2](https://github.com/johnxnguyen/Down/tree/v0.4.2) (2017-10-21)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[Pods\] Only include files in source\_files that can be compiled [\#86](https://github.com/iwasrobbed/Down/pull/86) ([njdehoog](https://github.com/njdehoog))
|
||||
|
||||
## [v0.5.1](https://github.com/iwasrobbed/Down/tree/v0.5.1) (2018-03-03)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.5.0...v0.5.1)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.4.1...v0.4.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- `DocumentReadingOptionKey` Error via pod [\#80](https://github.com/iwasrobbed/Down/issues/80)
|
||||
- Push v0.4.1 to cocoapods [\#51](https://github.com/johnxnguyen/Down/issues/51)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add optional stylesheet argument for NSAttributedString renderer [\#79](https://github.com/iwasrobbed/Down/pull/79) ([kengruven](https://github.com/kengruven))
|
||||
- Roll up cmark's COPYING sections into the top-level LICENSE file [\#78](https://github.com/iwasrobbed/Down/pull/78) ([kengruven](https://github.com/kengruven))
|
||||
- Update supported versions in README [\#77](https://github.com/iwasrobbed/Down/pull/77) ([kengruven](https://github.com/kengruven))
|
||||
- \[tvOS\] Conditionally compile DownView [\#52](https://github.com/johnxnguyen/Down/pull/52) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.5.0](https://github.com/iwasrobbed/Down/tree/v0.5.0) (2018-02-24)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.4.2...v0.5.0)
|
||||
## [v0.4.1](https://github.com/johnxnguyen/Down/tree/v0.4.1) (2017-10-04)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.4.0...v0.4.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Carthage install fails: no such module 'libcmark' [\#43](https://github.com/johnxnguyen/Down/issues/43)
|
||||
- Xcode 8.3 warnings [\#26](https://github.com/johnxnguyen/Down/issues/26)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Adds filters to remove Xcode-specific warnings [\#48](https://github.com/johnxnguyen/Down/pull/48) ([128keaton](https://github.com/128keaton))
|
||||
- Fixes issue \#43 [\#47](https://github.com/johnxnguyen/Down/pull/47) ([128keaton](https://github.com/128keaton))
|
||||
- Update to Swift 4 [\#46](https://github.com/johnxnguyen/Down/pull/46) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.4.0](https://github.com/johnxnguyen/Down/tree/v0.4.0) (2017-08-31)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.3.5...v0.4.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Fix/update example app [\#58](https://github.com/iwasrobbed/Down/pull/58) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Building for tvOS fails [\#49](https://github.com/iwasrobbed/Down/issues/49)
|
||||
- Fix Carthage builds [\#72](https://github.com/iwasrobbed/Down/pull/72) ([tonyarnold](https://github.com/tonyarnold))
|
||||
- Fix/update example app [\#58](https://github.com/iwasrobbed/Down/pull/58) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Example project [\#37](https://github.com/johnxnguyen/Down/issues/37)
|
||||
- Markdown tables support [\#36](https://github.com/johnxnguyen/Down/issues/36)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Swift 3+ convention for capitalization [\#74](https://github.com/iwasrobbed/Down/issues/74)
|
||||
- macOS 10.11 support? [\#73](https://github.com/iwasrobbed/Down/issues/73)
|
||||
- Installing with Carthage for Mac fails [\#70](https://github.com/iwasrobbed/Down/issues/70)
|
||||
- Error building/installing Down [\#69](https://github.com/iwasrobbed/Down/issues/69)
|
||||
- get heigth when add downview to other view? [\#67](https://github.com/iwasrobbed/Down/issues/67)
|
||||
- iOS8 crash [\#66](https://github.com/iwasrobbed/Down/issues/66)
|
||||
- Image caching [\#65](https://github.com/iwasrobbed/Down/issues/65)
|
||||
- Some warnings to fix [\#64](https://github.com/iwasrobbed/Down/issues/64)
|
||||
- build error [\#63](https://github.com/iwasrobbed/Down/issues/63)
|
||||
- Lists and paragraph spacing [\#62](https://github.com/iwasrobbed/Down/issues/62)
|
||||
- Converting Markdown string to HTML with emojis [\#60](https://github.com/iwasrobbed/Down/issues/60)
|
||||
- Syntax highlighting themes [\#59](https://github.com/iwasrobbed/Down/issues/59)
|
||||
- Compiling error on example project [\#57](https://github.com/iwasrobbed/Down/issues/57)
|
||||
- Compilation error using Carthage [\#54](https://github.com/iwasrobbed/Down/issues/54)
|
||||
- Unable to build with Xcode 9 [\#41](https://github.com/johnxnguyen/Down/issues/41)
|
||||
- Can not load local image and link to local .md file [\#40](https://github.com/johnxnguyen/Down/issues/40)
|
||||
- Fenced code syntax highlighting [\#35](https://github.com/johnxnguyen/Down/issues/35)
|
||||
- down.toAttributedString\(\) custom text font and image size [\#33](https://github.com/johnxnguyen/Down/issues/33)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Use lower-case Swift 3 convention for DownOptions [\#76](https://github.com/iwasrobbed/Down/pull/76) ([kengruven](https://github.com/kengruven))
|
||||
- Lower MACOSX\_DEPLOYMENT\_TARGET to include El Capitan [\#75](https://github.com/iwasrobbed/Down/pull/75) ([kengruven](https://github.com/kengruven))
|
||||
- WebKit not available on watchOS. [\#56](https://github.com/iwasrobbed/Down/pull/56) ([128keaton](https://github.com/128keaton))
|
||||
- Update README.md [\#55](https://github.com/iwasrobbed/Down/pull/55) ([128keaton](https://github.com/128keaton))
|
||||
- Updated Copyright year in ReadMe file [\#53](https://github.com/iwasrobbed/Down/pull/53) ([jobinsjohn](https://github.com/jobinsjohn))
|
||||
- Closes “Example” Issue [\#38](https://github.com/johnxnguyen/Down/pull/38) ([128keaton](https://github.com/128keaton))
|
||||
- Prevent zoom documentation [\#34](https://github.com/johnxnguyen/Down/pull/34) ([Kumuluzz](https://github.com/Kumuluzz))
|
||||
|
||||
## [v0.4.2](https://github.com/iwasrobbed/Down/tree/v0.4.2) (2017-10-21)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.4.1...v0.4.2)
|
||||
## [v0.3.5](https://github.com/johnxnguyen/Down/tree/v0.3.5) (2017-05-25)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.3.4...v0.3.5)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Disable analysis of cmark source code [\#31](https://github.com/johnxnguyen/Down/pull/31) ([tonyarnold](https://github.com/tonyarnold))
|
||||
|
||||
## [v0.3.4](https://github.com/johnxnguyen/Down/tree/v0.3.4) (2017-05-13)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.3.3...v0.3.4)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Suggested project fixes/changes [\#28](https://github.com/johnxnguyen/Down/pull/28) ([tonyarnold](https://github.com/tonyarnold))
|
||||
- Add the ability to initialise a DownView using a custom template bundle [\#27](https://github.com/johnxnguyen/Down/pull/27) ([tonyarnold](https://github.com/tonyarnold))
|
||||
|
||||
## [v0.3.3](https://github.com/johnxnguyen/Down/tree/v0.3.3) (2017-03-09)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.3.2...v0.3.3)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add OS X support [\#6](https://github.com/johnxnguyen/Down/issues/6)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \#6 macOS Support [\#25](https://github.com/johnxnguyen/Down/pull/25) ([128keaton](https://github.com/128keaton))
|
||||
|
||||
## [v0.3.2](https://github.com/johnxnguyen/Down/tree/v0.3.2) (2017-02-26)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.3.1...v0.3.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Create changelog [\#20](https://github.com/johnxnguyen/Down/issues/20)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Push v0.4.1 to cocoapods [\#51](https://github.com/iwasrobbed/Down/issues/51)
|
||||
- A faster substitute to NSHTMLTextDocumentType? [\#23](https://github.com/johnxnguyen/Down/issues/23)
|
||||
- How to update DownView content and keep the style? [\#19](https://github.com/johnxnguyen/Down/issues/19)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[tvOS\] Conditionally compile DownView [\#52](https://github.com/iwasrobbed/Down/pull/52) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Add tvOS support [\#24](https://github.com/johnxnguyen/Down/pull/24) ([invliD](https://github.com/invliD))
|
||||
- v0.3.1: Add the ability to update DownView content [\#22](https://github.com/johnxnguyen/Down/pull/22) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.4.1](https://github.com/iwasrobbed/Down/tree/v0.4.1) (2017-10-04)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.4.0...v0.4.1)
|
||||
## [v0.3.1](https://github.com/johnxnguyen/Down/tree/v0.3.1) (2017-02-09)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.3...v0.3.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Carthage install fails: no such module 'libcmark' [\#43](https://github.com/iwasrobbed/Down/issues/43)
|
||||
- Xcode 8.3 warnings [\#26](https://github.com/iwasrobbed/Down/issues/26)
|
||||
- How to keep UITextView font style [\#21](https://github.com/johnxnguyen/Down/issues/21)
|
||||
- Define custom fonts [\#18](https://github.com/johnxnguyen/Down/issues/18)
|
||||
- Render progress [\#17](https://github.com/johnxnguyen/Down/issues/17)
|
||||
- Disable zoom WebView [\#16](https://github.com/johnxnguyen/Down/issues/16)
|
||||
- Text Size of DownView too small [\#15](https://github.com/johnxnguyen/Down/issues/15)
|
||||
- How to customize the Font? [\#14](https://github.com/johnxnguyen/Down/issues/14)
|
||||
- Support Images [\#13](https://github.com/johnxnguyen/Down/issues/13)
|
||||
- How to manually install \(w/o Carthage or CocoaPods\) [\#12](https://github.com/johnxnguyen/Down/issues/12)
|
||||
- Add support for Carthage [\#8](https://github.com/johnxnguyen/Down/issues/8)
|
||||
|
||||
**Merged pull requests:**
|
||||
## [v0.3](https://github.com/johnxnguyen/Down/tree/v0.3) (2016-10-12)
|
||||
|
||||
- Adds filters to remove Xcode-specific warnings [\#48](https://github.com/iwasrobbed/Down/pull/48) ([128keaton](https://github.com/128keaton))
|
||||
- Fixes issue \#43 [\#47](https://github.com/iwasrobbed/Down/pull/47) ([128keaton](https://github.com/128keaton))
|
||||
- Update to Swift 4 [\#46](https://github.com/iwasrobbed/Down/pull/46) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Fixed error with accessing shared workspace. [\#44](https://github.com/iwasrobbed/Down/pull/44) ([mjzac](https://github.com/mjzac))
|
||||
|
||||
## [v0.4.0](https://github.com/iwasrobbed/Down/tree/v0.4.0) (2017-08-31)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.3.5...v0.4.0)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.2...v0.3)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Example project [\#37](https://github.com/iwasrobbed/Down/issues/37)
|
||||
- Markdown tables support [\#36](https://github.com/iwasrobbed/Down/issues/36)
|
||||
- Swift 3.0 support [\#10](https://github.com/johnxnguyen/Down/issues/10)
|
||||
- Add web view for rendering output [\#3](https://github.com/johnxnguyen/Down/issues/3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Unable to build with Xcode 9 [\#41](https://github.com/iwasrobbed/Down/issues/41)
|
||||
- Can not load local image and link to local .md file [\#40](https://github.com/iwasrobbed/Down/issues/40)
|
||||
- Fenced code syntax highlighting [\#35](https://github.com/iwasrobbed/Down/issues/35)
|
||||
- down.toAttributedString\(\) custom text font and image size [\#33](https://github.com/iwasrobbed/Down/issues/33)
|
||||
- Can you give an example how to custom the parser? [\#9](https://github.com/johnxnguyen/Down/issues/9)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Closes “Example” Issue [\#38](https://github.com/iwasrobbed/Down/pull/38) ([128keaton](https://github.com/128keaton))
|
||||
- Prevent zoom documentation [\#34](https://github.com/iwasrobbed/Down/pull/34) ([Kumuluzz](https://github.com/Kumuluzz))
|
||||
- Swift 3 [\#11](https://github.com/johnxnguyen/Down/pull/11) ([azeff](https://github.com/azeff))
|
||||
- Adds a few extra tests where possible [\#7](https://github.com/johnxnguyen/Down/pull/7) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- DownView rendering to close \#3 [\#5](https://github.com/johnxnguyen/Down/pull/5) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.3.5](https://github.com/iwasrobbed/Down/tree/v0.3.5) (2017-05-25)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.3.4...v0.3.5)
|
||||
## [v0.2](https://github.com/johnxnguyen/Down/tree/v0.2) (2016-06-02)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.1.1...v0.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Disable analysis of cmark source code [\#31](https://github.com/iwasrobbed/Down/pull/31) ([tonyarnold](https://github.com/tonyarnold))
|
||||
- Add attributed string support [\#2](https://github.com/johnxnguyen/Down/issues/2)
|
||||
- Adds attributed string rendering [\#4](https://github.com/johnxnguyen/Down/pull/4) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.3.4](https://github.com/iwasrobbed/Down/tree/v0.3.4) (2017-05-13)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.3.3...v0.3.4)
|
||||
## [v0.1.1](https://github.com/johnxnguyen/Down/tree/v0.1.1) (2016-06-01)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Suggested project fixes/changes [\#28](https://github.com/iwasrobbed/Down/pull/28) ([tonyarnold](https://github.com/tonyarnold))
|
||||
- Add the ability to initialise a DownView using a custom template bundle [\#27](https://github.com/iwasrobbed/Down/pull/27) ([tonyarnold](https://github.com/tonyarnold))
|
||||
|
||||
## [v0.3.3](https://github.com/iwasrobbed/Down/tree/v0.3.3) (2017-03-09)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.3.2...v0.3.3)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.1...v0.1.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add OS X support [\#6](https://github.com/iwasrobbed/Down/issues/6)
|
||||
- Add CocoaPods support & cmark license [\#1](https://github.com/johnxnguyen/Down/pull/1) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
**Merged pull requests:**
|
||||
## [v0.1](https://github.com/johnxnguyen/Down/tree/v0.1) (2016-06-01)
|
||||
|
||||
- \#6 macOS Support [\#25](https://github.com/iwasrobbed/Down/pull/25) ([128keaton](https://github.com/128keaton))
|
||||
|
||||
## [v0.3.2](https://github.com/iwasrobbed/Down/tree/v0.3.2) (2017-02-26)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.3.1...v0.3.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Create changelog [\#20](https://github.com/iwasrobbed/Down/issues/20)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- A faster substitute to NSHTMLTextDocumentType? [\#23](https://github.com/iwasrobbed/Down/issues/23)
|
||||
- How to update DownView content and keep the style? [\#19](https://github.com/iwasrobbed/Down/issues/19)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add tvOS support [\#24](https://github.com/iwasrobbed/Down/pull/24) ([invliD](https://github.com/invliD))
|
||||
- v0.3.1: Add the ability to update DownView content [\#22](https://github.com/iwasrobbed/Down/pull/22) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.3.1](https://github.com/iwasrobbed/Down/tree/v0.3.1) (2017-02-09)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.3...v0.3.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- How to keep UITextView font style [\#21](https://github.com/iwasrobbed/Down/issues/21)
|
||||
- Define custom fonts [\#18](https://github.com/iwasrobbed/Down/issues/18)
|
||||
- Render progress [\#17](https://github.com/iwasrobbed/Down/issues/17)
|
||||
- Disable zoom WebView [\#16](https://github.com/iwasrobbed/Down/issues/16)
|
||||
- Text Size of DownView too small [\#15](https://github.com/iwasrobbed/Down/issues/15)
|
||||
- How to customize the Font? [\#14](https://github.com/iwasrobbed/Down/issues/14)
|
||||
- Support Images [\#13](https://github.com/iwasrobbed/Down/issues/13)
|
||||
- How to manually install \(w/o Carthage or CocoaPods\) [\#12](https://github.com/iwasrobbed/Down/issues/12)
|
||||
- Add support for Carthage [\#8](https://github.com/iwasrobbed/Down/issues/8)
|
||||
|
||||
## [v0.3](https://github.com/iwasrobbed/Down/tree/v0.3) (2016-10-12)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.2...v0.3)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Swift 3.0 support [\#10](https://github.com/iwasrobbed/Down/issues/10)
|
||||
- Add web view for rendering output [\#3](https://github.com/iwasrobbed/Down/issues/3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Can you give an example how to custom the parser? [\#9](https://github.com/iwasrobbed/Down/issues/9)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Swift 3 [\#11](https://github.com/iwasrobbed/Down/pull/11) ([azeff](https://github.com/azeff))
|
||||
- Adds a few extra tests where possible [\#7](https://github.com/iwasrobbed/Down/pull/7) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- DownView rendering to close \#3 [\#5](https://github.com/iwasrobbed/Down/pull/5) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.2](https://github.com/iwasrobbed/Down/tree/v0.2) (2016-06-02)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.1.1...v0.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add attributed string support [\#2](https://github.com/iwasrobbed/Down/issues/2)
|
||||
- Adds attributed string rendering [\#4](https://github.com/iwasrobbed/Down/pull/4) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.1.1](https://github.com/iwasrobbed/Down/tree/v0.1.1) (2016-06-01)
|
||||
[Full Changelog](https://github.com/iwasrobbed/Down/compare/v0.1...v0.1.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add CocoaPods support & cmark license [\#1](https://github.com/iwasrobbed/Down/pull/1) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.1](https://github.com/iwasrobbed/Down/tree/v0.1) (2016-06-01)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/69fba2a97e45a07360054a811cac018bec10e17d...v0.1)
|
||||
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
|
||||
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
||||
|
||||
@@ -53,6 +53,13 @@
|
||||
remoteGlobalIDString = 8AFAEAFB1E6E32E900E09B68;
|
||||
remoteInfo = DownTests;
|
||||
};
|
||||
D4C77E06240EEB64004675B3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D49980AF1FA560F8004EE42E /* Down.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = EEBA153A2344845500B54ECB;
|
||||
remoteInfo = DownSnapshotTests;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -186,6 +193,7 @@
|
||||
children = (
|
||||
D49980B51FA560F8004EE42E /* Down.framework */,
|
||||
D49980B71FA560F8004EE42E /* DownTests.xctest */,
|
||||
D4C77E07240EEB64004675B3 /* DownSnapshotTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -238,12 +246,12 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1000;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = down;
|
||||
LastUpgradeCheck = 1130;
|
||||
ORGANIZATIONNAME = Down;
|
||||
TargetAttributes = {
|
||||
14090A482185411800503C06 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
DevelopmentTeam = NWN7H36NTR;
|
||||
DevelopmentTeam = 7V68668DJN;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
@@ -298,6 +306,13 @@
|
||||
remoteRef = D49980B61FA560F8004EE42E /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
D4C77E07240EEB64004675B3 /* DownSnapshotTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = DownSnapshotTests.xctest;
|
||||
remoteRef = D4C77E06240EEB64004675B3 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
@@ -398,14 +413,15 @@
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = NWN7H36NTR;
|
||||
DEVELOPMENT_TEAM = 7V68668DJN;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "macOS Demo/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.glazeddonut.macOS-Demo";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.macOS-Demo";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -424,13 +440,14 @@
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = NWN7H36NTR;
|
||||
DEVELOPMENT_TEAM = 7V68668DJN;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "macOS Demo/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.glazeddonut.macOS-Demo";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.macOS-Demo";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -565,7 +582,7 @@
|
||||
INFOPLIST_FILE = "Down-Example/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.glazeddonut.Down-Example";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.Down-Example";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -585,7 +602,7 @@
|
||||
INFOPLIST_FILE = "Down-Example/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.glazeddonut.Down-Example";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.Down-Example";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "SnapshotTesting",
|
||||
"repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c466812aa2e22898f27557e2e780d3aad7a27203",
|
||||
"version": "1.8.2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,8 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -38,8 +36,8 @@
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -61,8 +59,6 @@
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,8 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -38,8 +36,8 @@
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -61,8 +59,6 @@
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -3,7 +3,7 @@
|
||||
// Down-Example
|
||||
//
|
||||
// Created by Keaton Burleson on 7/1/17.
|
||||
// Copyright © 2017 down. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Down-Example
|
||||
//
|
||||
// Created by Keaton Burleson on 7/1/17.
|
||||
// Copyright © 2017 down. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// macOS Demo
|
||||
//
|
||||
// Created by Chris Zielinski on 10/27/18.
|
||||
// Copyright © 2018 down. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2018 down. All rights reserved.</string>
|
||||
<string>Copyright © 2016-2019 Down. All rights reserved.</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// macOS Demo
|
||||
//
|
||||
// Created by Chris Zielinski on 10/27/18.
|
||||
// Copyright © 2018 down. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
+13
-14
@@ -1,24 +1,23 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Down"
|
||||
spec.summary = "Blazing fast Markdown rendering in Swift, built upon cmark."
|
||||
spec.version = "0.8.1"
|
||||
spec.homepage = "https://github.com/iwasrobbed/Down"
|
||||
spec.version = "0.11.0"
|
||||
spec.homepage = "https://github.com/johnxnguyen/Down"
|
||||
spec.license = { :type => "MIT", :file => "LICENSE" }
|
||||
spec.authors = { "Rob Phillips" => "rob@robphillips.me" }
|
||||
spec.source = { :git => "https://github.com/iwasrobbed/Down.git", :tag => "v" + spec.version.to_s }
|
||||
spec.source_files = "Source/{AST,cmark,Enums & Options,Extensions,Renderers}/**/*.{h,c,swift}", "Source/*"
|
||||
spec.ios.source_files = "Source/Views/**"
|
||||
spec.osx.source_files = "Source/Views/**"
|
||||
spec.public_header_files = "Source/*.h"
|
||||
spec.authors = { "John Nguyen" => "polyxo@protonmail.com" }
|
||||
spec.source = { :git => "https://github.com/johnxnguyen/Down.git", :tag => "v" + spec.version.to_s }
|
||||
spec.source_files = "Sources/Down/{AST,Enums & Options,Extensions,Renderers}/**/*.swift", "Sources/cmark/*.{h,c}", "Sources/Down/*"
|
||||
spec.ios.source_files = "Sources/Down/Views/**"
|
||||
spec.osx.source_files = "Sources/Down/Views/**"
|
||||
spec.public_header_files = "Sources/Down/*.h"
|
||||
spec.ios.deployment_target = "9.0"
|
||||
spec.tvos.deployment_target = "9.0"
|
||||
spec.osx.deployment_target = "10.11"
|
||||
spec.requires_arc = true
|
||||
spec.module_name = "Down"
|
||||
spec.preserve_paths = "Source/cmark/module.modulemap", "Source/cmark/*.inc", "Source/cmark/COPYING"
|
||||
spec.pod_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(SRCROOT)/Down/Source/cmark/**' }
|
||||
spec.compiler_flags = '-Wno-shorten-64-to-32'
|
||||
spec.ios.resource = 'Resources/DownView.bundle'
|
||||
spec.osx.resource = 'Resources/DownView.bundle'
|
||||
spec.swift_version = "5.0"
|
||||
spec.preserve_paths = "Sources/cmark/include/module.modulemap", "Sources/cmark/*.inc", "Sources/cmark/COPYING"
|
||||
spec.pod_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(SRCROOT)/Down/Sources/cmark/**' }
|
||||
spec.ios.resource = 'Sources/Down/Resources/DownView.bundle'
|
||||
spec.osx.resource = 'Sources/Down/Resources/DownView.bundle'
|
||||
spec.swift_versions = ['5.0', '5.1']
|
||||
end
|
||||
|
||||
+415
-52
@@ -3,11 +3,12 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
14C5E33521877CE900D5380C /* DownView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D41689B51CFFE6BB00E5802B /* DownView.bundle */; };
|
||||
26CABB93252B4D490032183C /* ChildSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26CABB92252B4D490032183C /* ChildSequence.swift */; };
|
||||
8A569F481E6B3ED2008BE2AC /* DownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5D91CFFD0D0006E1522 /* DownView.swift */; };
|
||||
8A569F491E6B3ED9008BE2AC /* blocks.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF71CFA5D63008EEC6E /* blocks.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
|
||||
8A569F4A1E6B3ED9008BE2AC /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF81CFA5D63008EEC6E /* buffer.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
|
||||
@@ -64,9 +65,46 @@
|
||||
8AFAEB091E6E331700E09B68 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D438696B1D00D27700E95A1F /* StringTests.swift */; };
|
||||
907C64651EC133780095FEE1 /* TestDownView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 907C64621EC120530095FEE1 /* TestDownView.bundle */; };
|
||||
90A40A9C1EC03292004F2E91 /* Down.framework in Copy Bundled Frameworks */ = {isa = PBXBuildFile; fileRef = 8A569F401E6B3E50008BE2AC /* Down.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
EE0E54F82300800E0070C83F /* BlockBackgroundColorAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0E54F72300800E0070C83F /* BlockBackgroundColorAttribute.swift */; };
|
||||
EE3E7E38260400E800170A52 /* DownDebugLayoutManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE5D2DF822FC9E89009EC13E /* DownDebugLayoutManagerTests.swift */; };
|
||||
EE3E7E3F260400EE00170A52 /* LinkStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE5D2DF522FC99A6009EC13E /* LinkStyleTests.swift */; };
|
||||
EE3E7E46260400F100170A52 /* CodeBlockStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE64722A22F8BB0B00C5F0BA /* CodeBlockStyleTests.swift */; };
|
||||
EE3E7E4D260400F500170A52 /* BlockQuoteStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA2BDC722F705B900D0C72C /* BlockQuoteStyleTests.swift */; };
|
||||
EE3E7E54260400F900170A52 /* ThematicBreakSyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA5C02A22F58B8000B91D60 /* ThematicBreakSyleTests.swift */; };
|
||||
EE3E7E5B260400FC00170A52 /* HeadingStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE99E3DD22F0C83F00BCE15B /* HeadingStyleTests.swift */; };
|
||||
EE3E7E622604010000170A52 /* InlineStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9E886222EF76040005948C /* InlineStyleTests.swift */; };
|
||||
EE3E7E692604010300170A52 /* ListItemStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE335C4922EDC85900648842 /* ListItemStyleTests.swift */; };
|
||||
EE3E7E702604010700170A52 /* StylerTestSuite.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE59C30122ECF0BD006EE8A8 /* StylerTestSuite.swift */; };
|
||||
EE3E7E812604019300170A52 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = EE3E7E802604019300170A52 /* SnapshotTesting */; };
|
||||
EE3E7E88260401F000170A52 /* VisitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE64FEEF225BEB3900A35B34 /* VisitorTests.swift */; };
|
||||
EE408A39230338B600E5278A /* CGPointTranslateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE408A38230338B600E5278A /* CGPointTranslateTests.swift */; };
|
||||
EE408A3B2303399B00E5278A /* CGRectHelpersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE408A3A2303399B00E5278A /* CGRectHelpersTests.swift */; };
|
||||
EE408A3D23033B6B00E5278A /* ListItemPrefixGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE408A3C23033B6B00E5278A /* ListItemPrefixGeneratorTests.swift */; };
|
||||
EE44848B2301E51C0065C836 /* CodeBlockOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE44848A2301E51C0065C836 /* CodeBlockOptions.swift */; };
|
||||
EE4484912301F2920065C836 /* CGPoint+Translate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE4484902301F2920065C836 /* CGPoint+Translate.swift */; };
|
||||
EE4484932301F2DB0065C836 /* CGRect+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE4484922301F2DB0065C836 /* CGRect+Helpers.swift */; };
|
||||
EE469B11226CF3B500C0655D /* BaseNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE469B10226CF3B500C0655D /* BaseNode.swift */; };
|
||||
EE48C7D922EC9250004815ED /* ParagraphStyleCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE48C7D822EC9250004815ED /* ParagraphStyleCollection.swift */; };
|
||||
EE48C7DB22EC946F004815ED /* ColorCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE48C7DA22EC946F004815ED /* ColorCollection.swift */; };
|
||||
EE4F77C322FF3F170026A983 /* DownStylerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE4F77C222FF3F170026A983 /* DownStylerConfiguration.swift */; };
|
||||
EE5F2BA42262564A00B7C0F3 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE5F2BA32262564A00B7C0F3 /* Styler.swift */; };
|
||||
EE64FEF0225BEB3900A35B34 /* VisitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE64FEEF225BEB3900A35B34 /* VisitorTests.swift */; };
|
||||
EE8F38CC22BFB2420056270E /* NodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE8F38CB22BFB2420056270E /* NodeTests.swift */; };
|
||||
EE8F38CE22BFEDE50056270E /* ListItemPrefixGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE8F38CD22BFEDE50056270E /* ListItemPrefixGenerator.swift */; };
|
||||
EE97253E22C130D8004D3B3A /* NSMutableAttributedString+AttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE97253D22C130D8004D3B3A /* NSMutableAttributedString+AttributesTests.swift */; };
|
||||
EE97254322C14B79004D3B3A /* NSAttributedString+HelpersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE97254222C14B79004D3B3A /* NSAttributedString+HelpersTests.swift */; };
|
||||
EEA2BDC422F704F200D0C72C /* QuoteStripeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA2BDC322F704F200D0C72C /* QuoteStripeOptions.swift */; };
|
||||
EEA2BDC622F7057600D0C72C /* ListItemOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA2BDC522F7057600D0C72C /* ListItemOptions.swift */; };
|
||||
EEA2BDCA22F7152B00D0C72C /* ThematicBreakOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA2BDC922F7152B00D0C72C /* ThematicBreakOptions.swift */; };
|
||||
EEA5C02922F58A0900B91D60 /* DownTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA5C02822F58A0900B91D60 /* DownTextView.swift */; };
|
||||
EEA5C02D22F5C96B00B91D60 /* QuoteStripeAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA5C02C22F5C96B00B91D60 /* QuoteStripeAttribute.swift */; };
|
||||
EEBE62F025E28F3D005CCAD6 /* BundleHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBE62EF25E28F3D005CCAD6 /* BundleHelper.swift */; };
|
||||
EED7FED825E3133C0033E33A /* DownView (macOS).bundle in Resources */ = {isa = PBXBuildFile; fileRef = 14C5E33621877FCD00D5380C /* DownView (macOS).bundle */; };
|
||||
EED8DA8E22BE404F00E54492 /* DownStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED8DA8D22BE404F00E54492 /* DownStyler.swift */; };
|
||||
EED8DA9022BECBAE00E54492 /* NSAttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED8DA8F22BECBAE00E54492 /* NSAttributedString+Helpers.swift */; };
|
||||
EED8DA9222BECBF200E54492 /* NSMutableAttributedString+Attributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED8DA9122BECBF200E54492 /* NSMutableAttributedString+Attributes.swift */; };
|
||||
EED8DA9422BECC2100E54492 /* UIFont+Traits.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED8DA9322BECC2100E54492 /* UIFont+Traits.swift */; };
|
||||
EED8DA9722BECD7500E54492 /* FontCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED8DA9622BECD7500E54492 /* FontCollection.swift */; };
|
||||
EEE2C7F122C2AFEF001B7054 /* ListItemParagraphStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE2C7F022C2AFEF001B7054 /* ListItemParagraphStyler.swift */; };
|
||||
EEEBEE47225D298D00AE438D /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEBEE46225D298D00AE438D /* Document.swift */; };
|
||||
EEEBEE49225D29C200AE438D /* BlockQuote.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEBEE48225D29C200AE438D /* BlockQuote.swift */; };
|
||||
EEEBEE4B225D29D800AE438D /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEBEE4A225D29D800AE438D /* List.swift */; };
|
||||
@@ -90,7 +128,11 @@
|
||||
EEEBEE70225D2B9D00AE438D /* DebugVisitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEBEE6F225D2B9D00AE438D /* DebugVisitor.swift */; };
|
||||
EEEBEE72225D2F9200AE438D /* AttributedStringVisitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEBEE71225D2F9200AE438D /* AttributedStringVisitor.swift */; };
|
||||
EEF1376F2259E53400D7DDE0 /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF1376E2259E53400D7DDE0 /* Node.swift */; };
|
||||
EEF137712259E7E700D7DDE0 /* Vistor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF137702259E7E700D7DDE0 /* Vistor.swift */; };
|
||||
EEF137712259E7E700D7DDE0 /* Visitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF137702259E7E700D7DDE0 /* Visitor.swift */; };
|
||||
EEF8580F22FA101C0025370B /* DownDebugLayoutManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF8580E22FA101C0025370B /* DownDebugLayoutManager.swift */; };
|
||||
EEF8581122FA11690025370B /* DownDebugTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF8581022FA11690025370B /* DownDebugTextView.swift */; };
|
||||
EEFFFDDB22F4C36800036FD5 /* ThematicBreakAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEFFFDDA22F4C36800036FD5 /* ThematicBreakAttribute.swift */; };
|
||||
EEFFFDDD22F4C8AB00036FD5 /* DownLayoutManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEFFFDDC22F4C8AB00036FD5 /* DownLayoutManager.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXBuildRule section */
|
||||
@@ -99,6 +141,8 @@
|
||||
compilerSpec = com.apple.compilers.pbxcp;
|
||||
filePatterns = "*.inc";
|
||||
fileType = pattern.proxy;
|
||||
inputFiles = (
|
||||
);
|
||||
isEditable = 1;
|
||||
outputFiles = (
|
||||
);
|
||||
@@ -109,6 +153,8 @@
|
||||
compilerSpec = com.apple.compilers.pbxcp;
|
||||
filePatterns = "*COPYING";
|
||||
fileType = pattern.proxy;
|
||||
inputFiles = (
|
||||
);
|
||||
isEditable = 1;
|
||||
outputFiles = (
|
||||
);
|
||||
@@ -119,6 +165,8 @@
|
||||
compilerSpec = com.apple.compilers.pbxcp;
|
||||
filePatterns = "*.modulemap";
|
||||
fileType = pattern.proxy;
|
||||
inputFiles = (
|
||||
);
|
||||
isEditable = 1;
|
||||
outputFiles = (
|
||||
);
|
||||
@@ -152,8 +200,10 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
14C5E33621877FCD00D5380C /* DownView (macOS).bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = "DownView (macOS).bundle"; sourceTree = "<group>"; };
|
||||
26CABB92252B4D490032183C /* ChildSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChildSequence.swift; sourceTree = "<group>"; };
|
||||
8A569F401E6B3E50008BE2AC /* Down.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Down.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8AFAEAFB1E6E32E900E09B68 /* DownTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DownTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8C73B9B522A687C400C8E60F /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||
907C64621EC120530095FEE1 /* TestDownView.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestDownView.bundle; sourceTree = "<group>"; };
|
||||
90A40A951EC02FF6004F2E91 /* Down-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Down-Info.plist"; sourceTree = "<group>"; };
|
||||
90A40A961EC02FF6004F2E91 /* DownTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DownTests-Info.plist"; sourceTree = "<group>"; };
|
||||
@@ -199,7 +249,6 @@
|
||||
D4201F1C1CFA5D63008EEC6E /* utf8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utf8.c; sourceTree = "<group>"; };
|
||||
D4201F1D1CFA5D63008EEC6E /* utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf8.h; sourceTree = "<group>"; };
|
||||
D4201F1E1CFA5D63008EEC6E /* xml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xml.c; sourceTree = "<group>"; };
|
||||
D42869501CFF501200FACB4C /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||
D438696B1D00D27700E95A1F /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = "<group>"; };
|
||||
D43AE5C91CFFAE4D006E1522 /* NSAttributedString+HTML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+HTML.swift"; sourceTree = "<group>"; };
|
||||
D43AE5D91CFFD0D0006E1522 /* DownView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownView.swift; sourceTree = "<group>"; };
|
||||
@@ -216,9 +265,46 @@
|
||||
D4CF88971CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownAttributedStringRenderable.swift; sourceTree = "<group>"; };
|
||||
D4DC91131CFDED4B0091CE09 /* DownCommonMarkRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownCommonMarkRenderable.swift; sourceTree = "<group>"; };
|
||||
D4F948DB1D00A4A800C9C0F6 /* NSAttributedStringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSAttributedStringTests.swift; sourceTree = "<group>"; };
|
||||
EE0E54F72300800E0070C83F /* BlockBackgroundColorAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockBackgroundColorAttribute.swift; sourceTree = "<group>"; };
|
||||
EE335C4922EDC85900648842 /* ListItemStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemStyleTests.swift; sourceTree = "<group>"; };
|
||||
EE39B28026063E0D002C4F8D /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = "<group>"; };
|
||||
EE408A38230338B600E5278A /* CGPointTranslateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGPointTranslateTests.swift; sourceTree = "<group>"; };
|
||||
EE408A3A2303399B00E5278A /* CGRectHelpersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGRectHelpersTests.swift; sourceTree = "<group>"; };
|
||||
EE408A3C23033B6B00E5278A /* ListItemPrefixGeneratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemPrefixGeneratorTests.swift; sourceTree = "<group>"; };
|
||||
EE44848A2301E51C0065C836 /* CodeBlockOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeBlockOptions.swift; sourceTree = "<group>"; };
|
||||
EE4484902301F2920065C836 /* CGPoint+Translate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGPoint+Translate.swift"; sourceTree = "<group>"; };
|
||||
EE4484922301F2DB0065C836 /* CGRect+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGRect+Helpers.swift"; sourceTree = "<group>"; };
|
||||
EE469B10226CF3B500C0655D /* BaseNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNode.swift; sourceTree = "<group>"; };
|
||||
EE48C7D822EC9250004815ED /* ParagraphStyleCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParagraphStyleCollection.swift; sourceTree = "<group>"; };
|
||||
EE48C7DA22EC946F004815ED /* ColorCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorCollection.swift; sourceTree = "<group>"; };
|
||||
EE4F77C222FF3F170026A983 /* DownStylerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownStylerConfiguration.swift; sourceTree = "<group>"; };
|
||||
EE54F96E22EB9CE500628683 /* SnapshotTesting.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SnapshotTesting.framework; path = Carthage/Build/iOS/SnapshotTesting.framework; sourceTree = "<group>"; };
|
||||
EE59C30122ECF0BD006EE8A8 /* StylerTestSuite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StylerTestSuite.swift; sourceTree = "<group>"; };
|
||||
EE5D2DF522FC99A6009EC13E /* LinkStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkStyleTests.swift; sourceTree = "<group>"; };
|
||||
EE5D2DF822FC9E89009EC13E /* DownDebugLayoutManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownDebugLayoutManagerTests.swift; sourceTree = "<group>"; };
|
||||
EE5F2BA32262564A00B7C0F3 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = "<group>"; };
|
||||
EE64722A22F8BB0B00C5F0BA /* CodeBlockStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeBlockStyleTests.swift; sourceTree = "<group>"; };
|
||||
EE64FEEF225BEB3900A35B34 /* VisitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorTests.swift; sourceTree = "<group>"; };
|
||||
EE8F38CB22BFB2420056270E /* NodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeTests.swift; sourceTree = "<group>"; };
|
||||
EE8F38CD22BFEDE50056270E /* ListItemPrefixGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemPrefixGenerator.swift; sourceTree = "<group>"; };
|
||||
EE97253D22C130D8004D3B3A /* NSMutableAttributedString+AttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+AttributesTests.swift"; sourceTree = "<group>"; };
|
||||
EE97254222C14B79004D3B3A /* NSAttributedString+HelpersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+HelpersTests.swift"; sourceTree = "<group>"; };
|
||||
EE99E3DD22F0C83F00BCE15B /* HeadingStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingStyleTests.swift; sourceTree = "<group>"; };
|
||||
EE9E886222EF76040005948C /* InlineStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineStyleTests.swift; sourceTree = "<group>"; };
|
||||
EEA2BDC322F704F200D0C72C /* QuoteStripeOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteStripeOptions.swift; sourceTree = "<group>"; };
|
||||
EEA2BDC522F7057600D0C72C /* ListItemOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemOptions.swift; sourceTree = "<group>"; };
|
||||
EEA2BDC722F705B900D0C72C /* BlockQuoteStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockQuoteStyleTests.swift; sourceTree = "<group>"; };
|
||||
EEA2BDC922F7152B00D0C72C /* ThematicBreakOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThematicBreakOptions.swift; sourceTree = "<group>"; };
|
||||
EEA5C02822F58A0900B91D60 /* DownTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownTextView.swift; sourceTree = "<group>"; };
|
||||
EEA5C02A22F58B8000B91D60 /* ThematicBreakSyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThematicBreakSyleTests.swift; sourceTree = "<group>"; };
|
||||
EEA5C02C22F5C96B00B91D60 /* QuoteStripeAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteStripeAttribute.swift; sourceTree = "<group>"; };
|
||||
EEBE62EF25E28F3D005CCAD6 /* BundleHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BundleHelper.swift; sourceTree = "<group>"; };
|
||||
EED8DA8D22BE404F00E54492 /* DownStyler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownStyler.swift; sourceTree = "<group>"; };
|
||||
EED8DA8F22BECBAE00E54492 /* NSAttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Helpers.swift"; sourceTree = "<group>"; };
|
||||
EED8DA9122BECBF200E54492 /* NSMutableAttributedString+Attributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+Attributes.swift"; sourceTree = "<group>"; };
|
||||
EED8DA9322BECC2100E54492 /* UIFont+Traits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Traits.swift"; sourceTree = "<group>"; };
|
||||
EED8DA9622BECD7500E54492 /* FontCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontCollection.swift; sourceTree = "<group>"; };
|
||||
EEE2C7F022C2AFEF001B7054 /* ListItemParagraphStyler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemParagraphStyler.swift; sourceTree = "<group>"; };
|
||||
EEEBEE46225D298D00AE438D /* Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Document.swift; sourceTree = "<group>"; };
|
||||
EEEBEE48225D29C200AE438D /* BlockQuote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockQuote.swift; sourceTree = "<group>"; };
|
||||
EEEBEE4A225D29D800AE438D /* List.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = List.swift; sourceTree = "<group>"; };
|
||||
@@ -242,7 +328,11 @@
|
||||
EEEBEE6F225D2B9D00AE438D /* DebugVisitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugVisitor.swift; sourceTree = "<group>"; };
|
||||
EEEBEE71225D2F9200AE438D /* AttributedStringVisitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringVisitor.swift; sourceTree = "<group>"; };
|
||||
EEF1376E2259E53400D7DDE0 /* Node.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Node.swift; sourceTree = "<group>"; };
|
||||
EEF137702259E7E700D7DDE0 /* Vistor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vistor.swift; sourceTree = "<group>"; };
|
||||
EEF137702259E7E700D7DDE0 /* Visitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Visitor.swift; sourceTree = "<group>"; };
|
||||
EEF8580E22FA101C0025370B /* DownDebugLayoutManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownDebugLayoutManager.swift; sourceTree = "<group>"; };
|
||||
EEF8581022FA11690025370B /* DownDebugTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownDebugTextView.swift; sourceTree = "<group>"; };
|
||||
EEFFFDDA22F4C36800036FD5 /* ThematicBreakAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThematicBreakAttribute.swift; sourceTree = "<group>"; };
|
||||
EEFFFDDC22F4C8AB00036FD5 /* DownLayoutManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownLayoutManager.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -251,12 +341,21 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8AFAEB001E6E32E900E09B68 /* Down.framework in Frameworks */,
|
||||
EE3E7E812604019300170A52 /* SnapshotTesting in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
8C73B9B422A687C400C8E60F /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C73B9B522A687C400C8E60F /* module.modulemap */,
|
||||
);
|
||||
path = include;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
907C64611EC120530095FEE1 /* Fixtures */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -275,25 +374,25 @@
|
||||
path = Configurations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D41689B41CFFE6BB00E5802B /* Resources */ = {
|
||||
D41689B41CFFE6BB00E5802B /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90A40A971EC0309A004F2E91 /* Configurations */,
|
||||
90A40A951EC02FF6004F2E91 /* Down-Info.plist */,
|
||||
90A40A961EC02FF6004F2E91 /* DownTests-Info.plist */,
|
||||
D41689B51CFFE6BB00E5802B /* DownView.bundle */,
|
||||
14C5E33621877FCD00D5380C /* DownView (macOS).bundle */,
|
||||
);
|
||||
path = Resources;
|
||||
path = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D4201E761CFA5151008EEC6E = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D4201E9B1CFA59A5008EEC6E /* Source */,
|
||||
D41689B41CFFE6BB00E5802B /* Resources */,
|
||||
EE39B28026063E0D002C4F8D /* .swiftlint.yml */,
|
||||
D4201E9B1CFA59A5008EEC6E /* Sources */,
|
||||
D41689B41CFFE6BB00E5802B /* Supporting Files */,
|
||||
D4201EC41CFA59A5008EEC6E /* Tests */,
|
||||
D4201E811CFA5151008EEC6E /* Products */,
|
||||
EE54F96D22EB9CE400628683 /* Frameworks */,
|
||||
);
|
||||
indentWidth = 4;
|
||||
sourceTree = "<group>";
|
||||
@@ -308,30 +407,19 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D4201E9B1CFA59A5008EEC6E /* Source */ = {
|
||||
D4201E9B1CFA59A5008EEC6E /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D4CF88961CFF94B300F07FD1 /* Down.h */,
|
||||
D4201EF01CFA59F2008EEC6E /* Down.swift */,
|
||||
EEF1376D2259E4BA00D7DDE0 /* AST */,
|
||||
D44875E71CFA6CF30037A624 /* Enums & Options */,
|
||||
D43AE5C81CFFAE39006E1522 /* Extensions */,
|
||||
D44875E21CFA6B120037A624 /* Renderers */,
|
||||
D43AE5CB1CFFD068006E1522 /* Views */,
|
||||
EED7D92025C6DA4300E52D18 /* Down */,
|
||||
D4201EF61CFA5D63008EEC6E /* cmark */,
|
||||
);
|
||||
path = Source;
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D4201EC41CFA59A5008EEC6E /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
907C64611EC120530095FEE1 /* Fixtures */,
|
||||
D4201EC51CFA59A5008EEC6E /* BindingTests.swift */,
|
||||
D41689B21CFFE28200E5802B /* DownViewTests.swift */,
|
||||
D4F948DB1D00A4A800C9C0F6 /* NSAttributedStringTests.swift */,
|
||||
D438696B1D00D27700E95A1F /* StringTests.swift */,
|
||||
EE64FEEF225BEB3900A35B34 /* VisitorTests.swift */,
|
||||
EED7D92725C6DB9100E52D18 /* DownTests */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
@@ -339,6 +427,7 @@
|
||||
D4201EF61CFA5D63008EEC6E /* cmark */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C73B9B422A687C400C8E60F /* include */,
|
||||
D4201EF71CFA5D63008EEC6E /* blocks.c */,
|
||||
D4201EF81CFA5D63008EEC6E /* buffer.c */,
|
||||
D4201EF91CFA5D63008EEC6E /* buffer.h */,
|
||||
@@ -362,7 +451,6 @@
|
||||
D4201F0F1CFA5D63008EEC6E /* iterator.h */,
|
||||
D4201F101CFA5D63008EEC6E /* latex.c */,
|
||||
D4201F111CFA5D63008EEC6E /* man.c */,
|
||||
D42869501CFF501200FACB4C /* module.modulemap */,
|
||||
D4201F131CFA5D63008EEC6E /* node.c */,
|
||||
D4201F141CFA5D63008EEC6E /* node.h */,
|
||||
D4201F151CFA5D63008EEC6E /* parser.h */,
|
||||
@@ -392,6 +480,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D43AE5D91CFFD0D0006E1522 /* DownView.swift */,
|
||||
EEBE62EF25E28F3D005CCAD6 /* BundleHelper.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@@ -420,14 +509,174 @@
|
||||
path = "Enums & Options";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE5F2BA22262562F00B7C0F3 /* Stylers */ = {
|
||||
EE408A3E23033DFE00E5278A /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE408A3A2303399B00E5278A /* CGRectHelpersTests.swift */,
|
||||
EE408A38230338B600E5278A /* CGPointTranslateTests.swift */,
|
||||
EE97254222C14B79004D3B3A /* NSAttributedString+HelpersTests.swift */,
|
||||
EE97253D22C130D8004D3B3A /* NSMutableAttributedString+AttributesTests.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE48C7DE22EC99F3004815ED /* Attribute Collections */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EED8DA9622BECD7500E54492 /* FontCollection.swift */,
|
||||
EE48C7DA22EC946F004815ED /* ColorCollection.swift */,
|
||||
EE48C7D822EC9250004815ED /* ParagraphStyleCollection.swift */,
|
||||
);
|
||||
path = "Attribute Collections";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE48C7DF22EC9A4D004815ED /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EED8DA9322BECC2100E54492 /* UIFont+Traits.swift */,
|
||||
EED8DA8F22BECBAE00E54492 /* NSAttributedString+Helpers.swift */,
|
||||
EED8DA9122BECBF200E54492 /* NSMutableAttributedString+Attributes.swift */,
|
||||
EE4484902301F2920065C836 /* CGPoint+Translate.swift */,
|
||||
EE4484922301F2DB0065C836 /* CGRect+Helpers.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE54F96D22EB9CE400628683 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE54F96E22EB9CE500628683 /* SnapshotTesting.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE59C30022ECF08E006EE8A8 /* Styler */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE408A3E23033DFE00E5278A /* Helpers */,
|
||||
EE5D2DF822FC9E89009EC13E /* DownDebugLayoutManagerTests.swift */,
|
||||
EE5D2DF522FC99A6009EC13E /* LinkStyleTests.swift */,
|
||||
EE64722A22F8BB0B00C5F0BA /* CodeBlockStyleTests.swift */,
|
||||
EEA2BDC722F705B900D0C72C /* BlockQuoteStyleTests.swift */,
|
||||
EEA5C02A22F58B8000B91D60 /* ThematicBreakSyleTests.swift */,
|
||||
EE99E3DD22F0C83F00BCE15B /* HeadingStyleTests.swift */,
|
||||
EE9E886222EF76040005948C /* InlineStyleTests.swift */,
|
||||
EE335C4922EDC85900648842 /* ListItemStyleTests.swift */,
|
||||
EE59C30122ECF0BD006EE8A8 /* StylerTestSuite.swift */,
|
||||
);
|
||||
path = Styler;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE5D2DF722FC9D98009EC13E /* Options */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EEA2BDC922F7152B00D0C72C /* ThematicBreakOptions.swift */,
|
||||
EEA2BDC322F704F200D0C72C /* QuoteStripeOptions.swift */,
|
||||
EEA2BDC522F7057600D0C72C /* ListItemOptions.swift */,
|
||||
EE44848A2301E51C0065C836 /* CodeBlockOptions.swift */,
|
||||
);
|
||||
path = Options;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE5D2DFA22FCA92F009EC13E /* Stylers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE5F2BA32262564A00B7C0F3 /* Styler.swift */,
|
||||
EED8DA8D22BE404F00E54492 /* DownStyler.swift */,
|
||||
EE4F77C222FF3F170026A983 /* DownStylerConfiguration.swift */,
|
||||
);
|
||||
path = Stylers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE5D2DFB22FCA946009EC13E /* Layout Managers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EEFFFDDC22F4C8AB00036FD5 /* DownLayoutManager.swift */,
|
||||
EEF8580E22FA101C0025370B /* DownDebugLayoutManager.swift */,
|
||||
);
|
||||
path = "Layout Managers";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE5D2DFC22FCA953009EC13E /* Text Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EEA5C02822F58A0900B91D60 /* DownTextView.swift */,
|
||||
EEF8581022FA11690025370B /* DownDebugTextView.swift */,
|
||||
);
|
||||
path = "Text Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE5F2BA22262562F00B7C0F3 /* Styling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE5D2DFA22FCA92F009EC13E /* Stylers */,
|
||||
EEFFFDD922F4C35000036FD5 /* Custom Attributes */,
|
||||
EE5D2DFB22FCA946009EC13E /* Layout Managers */,
|
||||
EE5D2DFC22FCA953009EC13E /* Text Views */,
|
||||
EE48C7DE22EC99F3004815ED /* Attribute Collections */,
|
||||
EE5D2DF722FC9D98009EC13E /* Options */,
|
||||
EED8DA9522BECCF000E54492 /* Helpers */,
|
||||
);
|
||||
path = Styling;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEC752BE22C4AE1300EC729C /* AST */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE8F38CB22BFB2420056270E /* NodeTests.swift */,
|
||||
EE64FEEF225BEB3900A35B34 /* VisitorTests.swift */,
|
||||
EE408A3C23033B6B00E5278A /* ListItemPrefixGeneratorTests.swift */,
|
||||
);
|
||||
path = AST;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EED7D92025C6DA4300E52D18 /* Down */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EED7D94425C6DF2D00E52D18 /* Resources */,
|
||||
D4CF88961CFF94B300F07FD1 /* Down.h */,
|
||||
D4201EF01CFA59F2008EEC6E /* Down.swift */,
|
||||
EEF1376D2259E4BA00D7DDE0 /* AST */,
|
||||
D44875E71CFA6CF30037A624 /* Enums & Options */,
|
||||
D43AE5C81CFFAE39006E1522 /* Extensions */,
|
||||
D44875E21CFA6B120037A624 /* Renderers */,
|
||||
D43AE5CB1CFFD068006E1522 /* Views */,
|
||||
);
|
||||
path = Down;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EED7D92725C6DB9100E52D18 /* DownTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE59C30022ECF08E006EE8A8 /* Styler */,
|
||||
907C64611EC120530095FEE1 /* Fixtures */,
|
||||
D4201EC51CFA59A5008EEC6E /* BindingTests.swift */,
|
||||
D41689B21CFFE28200E5802B /* DownViewTests.swift */,
|
||||
D4F948DB1D00A4A800C9C0F6 /* NSAttributedStringTests.swift */,
|
||||
D438696B1D00D27700E95A1F /* StringTests.swift */,
|
||||
EEC752BE22C4AE1300EC729C /* AST */,
|
||||
);
|
||||
path = DownTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EED7D94425C6DF2D00E52D18 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D41689B51CFFE6BB00E5802B /* DownView.bundle */,
|
||||
14C5E33621877FCD00D5380C /* DownView (macOS).bundle */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EED8DA9522BECCF000E54492 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EEE2C7F022C2AFEF001B7054 /* ListItemParagraphStyler.swift */,
|
||||
EE48C7DF22EC9A4D004815ED /* Extensions */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEEBEE45225D297700AE438D /* Nodes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -453,6 +702,7 @@
|
||||
EEEBEE68225D2B1200AE438D /* Strong.swift */,
|
||||
EEEBEE5A225D2A7E00AE438D /* Text.swift */,
|
||||
EEEBEE58225D2A7000AE438D /* ThematicBreak.swift */,
|
||||
26CABB92252B4D490032183C /* ChildSequence.swift */,
|
||||
);
|
||||
path = Nodes;
|
||||
sourceTree = "<group>";
|
||||
@@ -461,8 +711,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EEEBEE71225D2F9200AE438D /* AttributedStringVisitor.swift */,
|
||||
EE8F38CD22BFEDE50056270E /* ListItemPrefixGenerator.swift */,
|
||||
EEEBEE6F225D2B9D00AE438D /* DebugVisitor.swift */,
|
||||
EEF137702259E7E700D7DDE0 /* Vistor.swift */,
|
||||
EEF137702259E7E700D7DDE0 /* Visitor.swift */,
|
||||
);
|
||||
path = Visitors;
|
||||
sourceTree = "<group>";
|
||||
@@ -472,11 +723,21 @@
|
||||
children = (
|
||||
EEEBEE45225D297700AE438D /* Nodes */,
|
||||
EEEBEE6E225D2B8200AE438D /* Visitors */,
|
||||
EE5F2BA22262562F00B7C0F3 /* Stylers */,
|
||||
EE5F2BA22262562F00B7C0F3 /* Styling */,
|
||||
);
|
||||
path = AST;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEFFFDD922F4C35000036FD5 /* Custom Attributes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EEFFFDDA22F4C36800036FD5 /* ThematicBreakAttribute.swift */,
|
||||
EEA5C02C22F5C96B00B91D60 /* QuoteStripeAttribute.swift */,
|
||||
EE0E54F72300800E0070C83F /* BlockBackgroundColorAttribute.swift */,
|
||||
);
|
||||
path = "Custom Attributes";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -514,6 +775,7 @@
|
||||
8A569F3D1E6B3E50008BE2AC /* Headers */,
|
||||
14C5E33421877CDC00D5380C /* Resources */,
|
||||
14CEAC38218774BC00039EDF /* Replace Bundle for macOS Platform */,
|
||||
EED185ED26054F800051E616 /* Swiftlint */,
|
||||
);
|
||||
buildRules = (
|
||||
8AE66BE41F848C3900ED4C98 /* PBXBuildRule */,
|
||||
@@ -542,6 +804,9 @@
|
||||
8AFAEB021E6E32E900E09B68 /* PBXTargetDependency */,
|
||||
);
|
||||
name = DownTests;
|
||||
packageProductDependencies = (
|
||||
EE3E7E802604019300170A52 /* SnapshotTesting */,
|
||||
);
|
||||
productName = "DownTests-macOS";
|
||||
productReference = 8AFAEAFB1E6E32E900E09B68 /* DownTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
@@ -552,9 +817,9 @@
|
||||
D4201E771CFA5151008EEC6E /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0820;
|
||||
LastSwiftUpdateCheck = 1100;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = "Glazed Donut, LLC.";
|
||||
ORGANIZATIONNAME = Down;
|
||||
TargetAttributes = {
|
||||
8A569F3F1E6B3E50008BE2AC = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
@@ -577,6 +842,9 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = D4201E761CFA5151008EEC6E;
|
||||
packageReferences = (
|
||||
EED7FED525E303000033E33A /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
|
||||
);
|
||||
productRefGroup = D4201E811CFA5151008EEC6E /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -592,6 +860,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EED7FED825E3133C0033E33A /* DownView (macOS).bundle in Resources */,
|
||||
14C5E33521877CE900D5380C /* DownView.bundle in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -623,9 +892,27 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\nRESOURCE_PATH=$SRCROOT/Resources\n\nFILENAME_IN_BUNDLE=DownView.bundle\n\nBUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Resources\n\necho \"$RESOURCE_PATH\"\necho \"$BUILD_APP_DIR\"\n\nif [ \"$PLATFORM_NAME\" == \"macosx\" ]; then\n echo $BUILD_APP_DIR\n rm -r \"$BUILD_APP_DIR/$FILENAME_IN_BUNDLE/\"\n cp -R \"$RESOURCE_PATH/DownView (macOS).bundle\" \"$BUILD_APP_DIR/$FILENAME_IN_BUNDLE/\"\nfi\n";
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\nRESOURCE_PATH=$SRCROOT/Sources/Down/Resources\n\nFILENAME_IN_BUNDLE=DownView.bundle\n\nBUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Resources\n\necho \"$RESOURCE_PATH\"\necho \"$BUILD_APP_DIR\"\n\nif [ \"$PLATFORM_NAME\" == \"macosx\" ]; then\n echo $BUILD_APP_DIR\n rm -r \"$BUILD_APP_DIR/$FILENAME_IN_BUNDLE/\"\n cp -R \"$RESOURCE_PATH/DownView (macOS).bundle\" \"$BUILD_APP_DIR/$FILENAME_IN_BUNDLE/\"\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
EED185ED26054F800051E616 /* Swiftlint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = Swiftlint;
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -640,21 +927,39 @@
|
||||
EEEBEE70225D2B9D00AE438D /* DebugVisitor.swift in Sources */,
|
||||
EEEBEE59225D2A7000AE438D /* ThematicBreak.swift in Sources */,
|
||||
8A569F481E6B3ED2008BE2AC /* DownView.swift in Sources */,
|
||||
EE4F77C322FF3F170026A983 /* DownStylerConfiguration.swift in Sources */,
|
||||
8A569F591E6B3ED9008BE2AC /* houdini_html_u.c in Sources */,
|
||||
EEEBEE63225D2AD400AE438D /* HtmlInline.swift in Sources */,
|
||||
8A569F621E6B3ED9008BE2AC /* node.c in Sources */,
|
||||
EE4484932301F2DB0065C836 /* CGRect+Helpers.swift in Sources */,
|
||||
26CABB93252B4D490032183C /* ChildSequence.swift in Sources */,
|
||||
EEEBEE6D225D2B3200AE438D /* Image.swift in Sources */,
|
||||
EED8DA9722BECD7500E54492 /* FontCollection.swift in Sources */,
|
||||
EEEBEE4D225D2A0200AE438D /* Item.swift in Sources */,
|
||||
EEF8580F22FA101C0025370B /* DownDebugLayoutManager.swift in Sources */,
|
||||
8A569F6F1E6B3EDE008BE2AC /* DownAttributedStringRenderable.swift in Sources */,
|
||||
EEEBEE55225D2A4E00AE438D /* Paragraph.swift in Sources */,
|
||||
EEBE62F025E28F3D005CCAD6 /* BundleHelper.swift in Sources */,
|
||||
8A569F721E6B3EDE008BE2AC /* DownHTMLRenderable.swift in Sources */,
|
||||
EED8DA9422BECC2100E54492 /* UIFont+Traits.swift in Sources */,
|
||||
EE44848B2301E51C0065C836 /* CodeBlockOptions.swift in Sources */,
|
||||
EE4484912301F2920065C836 /* CGPoint+Translate.swift in Sources */,
|
||||
EEFFFDDB22F4C36800036FD5 /* ThematicBreakAttribute.swift in Sources */,
|
||||
EEE2C7F122C2AFEF001B7054 /* ListItemParagraphStyler.swift in Sources */,
|
||||
8A569F581E6B3ED9008BE2AC /* houdini_html_e.c in Sources */,
|
||||
EEEBEE5D225D2A8F00AE438D /* SoftBreak.swift in Sources */,
|
||||
EE48C7D922EC9250004815ED /* ParagraphStyleCollection.swift in Sources */,
|
||||
EEEBEE6B225D2B2200AE438D /* Link.swift in Sources */,
|
||||
8A569F531E6B3ED9008BE2AC /* commonmark.c in Sources */,
|
||||
EEA2BDC422F704F200D0C72C /* QuoteStripeOptions.swift in Sources */,
|
||||
8A569F4A1E6B3ED9008BE2AC /* buffer.c in Sources */,
|
||||
EED8DA9222BECBF200E54492 /* NSMutableAttributedString+Attributes.swift in Sources */,
|
||||
EED8DA9022BECBAE00E54492 /* NSAttributedString+Helpers.swift in Sources */,
|
||||
EEFFFDDD22F4C8AB00036FD5 /* DownLayoutManager.swift in Sources */,
|
||||
8A569F771E6B3EE3008BE2AC /* String+ToHTML.swift in Sources */,
|
||||
8A569F751E6B3EDE008BE2AC /* DownRenderable.swift in Sources */,
|
||||
EEA2BDC622F7057600D0C72C /* ListItemOptions.swift in Sources */,
|
||||
EE8F38CE22BFEDE50056270E /* ListItemPrefixGenerator.swift in Sources */,
|
||||
8A569F741E6B3EDE008BE2AC /* DownXMLRenderable.swift in Sources */,
|
||||
8A569F6B1E6B3ED9008BE2AC /* utf8.c in Sources */,
|
||||
8A569F791E6B3EE7008BE2AC /* DownOptions.swift in Sources */,
|
||||
@@ -668,21 +973,27 @@
|
||||
8A569F701E6B3EDE008BE2AC /* DownCommonMarkRenderable.swift in Sources */,
|
||||
8A569F7A1E6B3EEA008BE2AC /* Down.swift in Sources */,
|
||||
EE5F2BA42262564A00B7C0F3 /* Styler.swift in Sources */,
|
||||
EEA5C02922F58A0900B91D60 /* DownTextView.swift in Sources */,
|
||||
8A569F731E6B3EDE008BE2AC /* DownLaTeXRenderable.swift in Sources */,
|
||||
8A569F781E6B3EE7008BE2AC /* DownErrors.swift in Sources */,
|
||||
8A569F5C1E6B3ED9008BE2AC /* inlines.c in Sources */,
|
||||
EE48C7DB22EC946F004815ED /* ColorCollection.swift in Sources */,
|
||||
EEA5C02D22F5C96B00B91D60 /* QuoteStripeAttribute.swift in Sources */,
|
||||
8A569F571E6B3ED9008BE2AC /* houdini_href_e.c in Sources */,
|
||||
8A569F4D1E6B3ED9008BE2AC /* cmark.c in Sources */,
|
||||
EEEBEE65225D2AE800AE438D /* CustomInline.swift in Sources */,
|
||||
EE0E54F82300800E0070C83F /* BlockBackgroundColorAttribute.swift in Sources */,
|
||||
EEF1376F2259E53400D7DDE0 /* Node.swift in Sources */,
|
||||
8A569F6D1E6B3ED9008BE2AC /* xml.c in Sources */,
|
||||
8A569F6E1E6B3EDE008BE2AC /* DownASTRenderable.swift in Sources */,
|
||||
EEF8581122FA11690025370B /* DownDebugTextView.swift in Sources */,
|
||||
EEEBEE5B225D2A7E00AE438D /* Text.swift in Sources */,
|
||||
EEEBEE4F225D2A1400AE438D /* CodeBlock.swift in Sources */,
|
||||
EED8DA8E22BE404F00E54492 /* DownStyler.swift in Sources */,
|
||||
EEEBEE5F225D2AA700AE438D /* LineBreak.swift in Sources */,
|
||||
EEEBEE61225D2AC000AE438D /* Code.swift in Sources */,
|
||||
8A569F491E6B3ED9008BE2AC /* blocks.c in Sources */,
|
||||
EEF137712259E7E700D7DDE0 /* Vistor.swift in Sources */,
|
||||
EEF137712259E7E700D7DDE0 /* Visitor.swift in Sources */,
|
||||
EEEBEE53225D2A3C00AE438D /* CustomBlock.swift in Sources */,
|
||||
EEEBEE69225D2B1200AE438D /* Strong.swift in Sources */,
|
||||
EEEBEE47225D298D00AE438D /* Document.swift in Sources */,
|
||||
@@ -692,6 +1003,7 @@
|
||||
EEEBEE49225D29C200AE438D /* BlockQuote.swift in Sources */,
|
||||
8A569F651E6B3ED9008BE2AC /* references.c in Sources */,
|
||||
EEEBEE67225D2AF900AE438D /* Emphasis.swift in Sources */,
|
||||
EEA2BDCA22F7152B00D0C72C /* ThematicBreakOptions.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -699,8 +1011,23 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EE3E7E54260400F900170A52 /* ThematicBreakSyleTests.swift in Sources */,
|
||||
EE3E7E4D260400F500170A52 /* BlockQuoteStyleTests.swift in Sources */,
|
||||
EE97253E22C130D8004D3B3A /* NSMutableAttributedString+AttributesTests.swift in Sources */,
|
||||
EE3E7E622604010000170A52 /* InlineStyleTests.swift in Sources */,
|
||||
EE3E7E702604010700170A52 /* StylerTestSuite.swift in Sources */,
|
||||
EE3E7E692604010300170A52 /* ListItemStyleTests.swift in Sources */,
|
||||
EE3E7E46260400F100170A52 /* CodeBlockStyleTests.swift in Sources */,
|
||||
EE97254322C14B79004D3B3A /* NSAttributedString+HelpersTests.swift in Sources */,
|
||||
8AFAEB091E6E331700E09B68 /* StringTests.swift in Sources */,
|
||||
EE64FEF0225BEB3900A35B34 /* VisitorTests.swift in Sources */,
|
||||
EE3E7E5B260400FC00170A52 /* HeadingStyleTests.swift in Sources */,
|
||||
EE408A3D23033B6B00E5278A /* ListItemPrefixGeneratorTests.swift in Sources */,
|
||||
EE8F38CC22BFB2420056270E /* NodeTests.swift in Sources */,
|
||||
EE3E7E3F260400EE00170A52 /* LinkStyleTests.swift in Sources */,
|
||||
EE3E7E38260400E800170A52 /* DownDebugLayoutManagerTests.swift in Sources */,
|
||||
EE408A39230338B600E5278A /* CGPointTranslateTests.swift in Sources */,
|
||||
EE408A3B2303399B00E5278A /* CGRectHelpersTests.swift in Sources */,
|
||||
EE3E7E88260401F000170A52 /* VisitorTests.swift in Sources */,
|
||||
8AFAEB071E6E331700E09B68 /* DownViewTests.swift in Sources */,
|
||||
8AFAEB061E6E331700E09B68 /* BindingTests.swift in Sources */,
|
||||
8AFAEB081E6E331700E09B68 /* NSAttributedStringTests.swift in Sources */,
|
||||
@@ -722,6 +1049,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 90A40A991EC0309A004F2E91 /* Universal-Framework-Target.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -730,12 +1058,12 @@
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "Resources/Down-Info.plist";
|
||||
INFOPLIST_FILE = "Supporting Files/Down-Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_INCLUDE_PATHS = "${SRCROOT}/Source/cmark";
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_INCLUDE_PATHS = "${SRCROOT}/Sources/cmark";
|
||||
"VALID_ARCHS[sdk=iphonesimulator*]" = "i386 x86_64 arm64";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -743,6 +1071,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 90A40A991EC0309A004F2E91 /* Universal-Framework-Target.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -751,12 +1080,12 @@
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "Resources/Down-Info.plist";
|
||||
INFOPLIST_FILE = "Supporting Files/Down-Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_INCLUDE_PATHS = "${SRCROOT}/Source/cmark";
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_INCLUDE_PATHS = "${SRCROOT}/Sources/cmark";
|
||||
"VALID_ARCHS[sdk=iphonesimulator*]" = "i386 x86_64 arm64";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -764,9 +1093,17 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 90A40A9A1EC0309A004F2E91 /* Universal-Target-Base.xcconfig */;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = "Resources/DownTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.glazeddonut.DownTests;
|
||||
SWIFT_VERSION = 5.0;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
||||
);
|
||||
INFOPLIST_FILE = "Supporting Files/DownTests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.downMarkdown.DownTests;
|
||||
"TARGETED_DEVICE_FAMILY[sdk=appletvos*]" = 3;
|
||||
"TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*]" = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -774,9 +1111,17 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 90A40A9A1EC0309A004F2E91 /* Universal-Target-Base.xcconfig */;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = "Resources/DownTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.glazeddonut.DownTests;
|
||||
SWIFT_VERSION = 5.0;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
||||
);
|
||||
INFOPLIST_FILE = "Supporting Files/DownTests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.downMarkdown.DownTests;
|
||||
"TARGETED_DEVICE_FAMILY[sdk=appletvos*]" = 3;
|
||||
"TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*]" = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -833,12 +1178,11 @@
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.glazeddonut.$(TARGET_NAME:c99-identifier)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.$(TARGET_NAME:c99-identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@@ -891,11 +1235,11 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.glazeddonut.$(TARGET_NAME:c99-identifier)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.$(TARGET_NAME:c99-identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -934,6 +1278,25 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
EED7FED525E303000033E33A /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.8.2;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
EE3E7E802604019300170A52 /* SnapshotTesting */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = EED7FED525E303000033E33A /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */;
|
||||
productName = SnapshotTesting;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = D4201E771CFA5151008EEC6E /* Project object */;
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Down.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "SnapshotTesting",
|
||||
"repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c466812aa2e22898f27557e2e780d3aad7a27203",
|
||||
"version": "1.8.2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,8 +26,17 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8A569F3F1E6B3E50008BE2AC"
|
||||
BuildableName = "Down.framework"
|
||||
BlueprintName = "Down"
|
||||
ReferencedContainer = "container:Down.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -40,17 +49,6 @@
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8A569F3F1E6B3E50008BE2AC"
|
||||
BuildableName = "Down.framework"
|
||||
BlueprintName = "Down"
|
||||
ReferencedContainer = "container:Down.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -71,8 +69,6 @@
|
||||
ReferencedContainer = "container:Down.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import XCTest
|
||||
|
||||
var tests = [XCTestCaseEntry]()
|
||||
|
||||
// FIXME: Run on macOS `swift test --generate-linuxmain` and maintain Linux Tests.
|
||||
|
||||
XCTMain(tests)
|
||||
@@ -0,0 +1,64 @@
|
||||
// swift-tools-version:5.3
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Down",
|
||||
platforms: [
|
||||
.macOS("10.11"),
|
||||
.iOS("9.0"),
|
||||
.tvOS("9.0")
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "Down",
|
||||
targets: ["Down"]
|
||||
)
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "libcmark",
|
||||
dependencies: [],
|
||||
path: "Sources/cmark",
|
||||
exclude: [
|
||||
"include",
|
||||
"case_fold_switch.inc",
|
||||
"entities.inc",
|
||||
"COPYING"
|
||||
],
|
||||
publicHeadersPath: "./"
|
||||
),
|
||||
.target(
|
||||
name: "Down",
|
||||
dependencies: ["libcmark"],
|
||||
path: "Sources/Down",
|
||||
exclude: ["Down.h"],
|
||||
resources: [
|
||||
.copy("Resources/DownView.bundle"),
|
||||
.copy("Resources/DownView (macOS).bundle"),
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "DownTests",
|
||||
dependencies: ["Down"],
|
||||
path: "Tests/DownTests",
|
||||
exclude: [
|
||||
"AST/VisitorTests.swift",
|
||||
"AST/__Snapshots__",
|
||||
"DownViewTests.swift",
|
||||
"Fixtures",
|
||||
"Styler/__Snapshots__",
|
||||
"Styler/BlockQuoteStyleTests.swift",
|
||||
"Styler/CodeBlockStyleTests.swift",
|
||||
"Styler/DownDebugLayoutManagerTests.swift",
|
||||
"Styler/HeadingStyleTests.swift",
|
||||
"Styler/LinkStyleTests.swift",
|
||||
"Styler/InlineStyleTests.swift",
|
||||
"Styler/ListItemStyleTests.swift",
|
||||
"Styler/StylerTestSuite.swift",
|
||||
"Styler/ThematicBreakSyleTests.swift"
|
||||
]
|
||||
)
|
||||
],
|
||||
swiftLanguageVersions: [.v5]
|
||||
)
|
||||
@@ -1,42 +1,59 @@
|
||||
## Down
|
||||
[](https://travis-ci.org/iwasrobbed/Down)
|
||||
[](https://github.com/iwasrobbed/Down/blob/master/LICENSE)
|
||||
[]()
|
||||
[](https://travis-ci.com/johnxnguyen/Down)
|
||||
[](https://github.com/johnxnguyen/Down/blob/master/LICENSE)
|
||||
[](https://cocoapods.org/pods/Down)
|
||||
[](https://swift.org)
|
||||
[](https://developer.apple.com/macos/)
|
||||
[](https://developer.apple.com/ios/)
|
||||
[](https://developer.apple.com/tvos/)
|
||||
[](https://coveralls.io/github/iwasrobbed/Down?branch=master)
|
||||
[](https://www.linux.org/)
|
||||
[](https://codecov.io/gh/johnxnguyen/Down)
|
||||
|
||||
Blazing fast Markdown (CommonMark) rendering in Swift, built upon [cmark v0.29.0](https://github.com/commonmark/cmark).
|
||||
|
||||
Is your app using it? [Let us know!](mailto:rob@robphillips.me)
|
||||
Is your app using it? [Let us know!](mailto:polyxo@protonmail.com)
|
||||
|
||||
If you're looking for `iwasrobbed/Down`, you found it! [Rob Phillips](https://github.com/iwasrobbed), the originator of this repository,
|
||||
has transferred it to me as I will be the primary maintainer from now on. Thanks to Rob for bringing Down as far as it has come and for
|
||||
entrusting me with its care.
|
||||
|
||||
All existing references to `iwasrobbed/Down` should redirect to this repository. However, It is recommended to update those urls to point
|
||||
to this repository.
|
||||
|
||||
#### Maintainers
|
||||
|
||||
- [Rob Phillips](https://github.com/iwasrobbed)
|
||||
- [John Nguyen](https://github.com/johnxnguyen)
|
||||
- [Rob Phillips](https://github.com/iwasrobbed)
|
||||
- [Keaton Burleson](https://github.com/128keaton)
|
||||
- [phoney](https://github.com/phoney)
|
||||
- [Tony Arnold](https://github.com/tonyarnold)
|
||||
- [Ken Harris](https://github.com/kengruven)
|
||||
- [Chris Zielinski](https://github.com/chriszielinski)
|
||||
- [Other contributors](https://github.com/iwasrobbed/Down/graphs/contributors) 🙌
|
||||
- [Other contributors](https://github.com/johnxnguyen/Down/graphs/contributors) 🙌
|
||||
|
||||
### Installation
|
||||
|
||||
Note: Swift 5 support is now on the `master` branch and any tag >= 0.8.1 (Swift 4 is >= 0.4.x, Swift 3 is 0.3.x)
|
||||
Note: Swift support is summarized in the table below.
|
||||
|
||||
Quickly install using [CocoaPods](https://cocoapods.org):
|
||||
|Swift Version|Tag|
|
||||
| --- | --- |
|
||||
| Swift 5.1 | >= 0.9.0 |
|
||||
| Swift 5.0 | >= 0.8.1 |
|
||||
| Swift 4 | >= 0.4.x |
|
||||
| Swift 3 | 0.3.x |
|
||||
|
||||
now on the `master` branch and any tag >= 0.8.1 (Swift 4 is >= 0.4.x, Swift 3 is 0.3.x)
|
||||
|
||||
#### Quickly install using [CocoaPods](https://cocoapods.org):
|
||||
|
||||
```ruby
|
||||
pod 'Down'
|
||||
```
|
||||
|
||||
Or [Carthage](https://github.com/Carthage/Carthage):
|
||||
#### Install using [Carthage](https://github.com/Carthage/Carthage):
|
||||
|
||||
```
|
||||
github "iwasrobbed/Down"
|
||||
github "johnxnguyen/Down"
|
||||
```
|
||||
Due to limitations in Carthage regarding platform specification, you need to define the platform with Carthage.
|
||||
|
||||
@@ -44,11 +61,16 @@ e.g.
|
||||
|
||||
```carthage update --platform iOS```
|
||||
|
||||
Or manually install:
|
||||
#### Install using [Swift Package Manager](https://github.com/apple/swift-package-manager):
|
||||
|
||||
To add *Down* to your project, select `File → Swift Packages → Add Package Dependency` and enter the GitHub URL for *Down*.
|
||||
See [Adding Package Dependencies to Your App](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) for detailed instructions.
|
||||
|
||||
#### Or manually install:
|
||||
|
||||
1. Clone this repository
|
||||
2. Build the Down project
|
||||
3. Add the resulting framework file to your project
|
||||
2. Drag and drop the Down project into your workspace file, adding the framework in the embedded framework section
|
||||
2. Build and run your app
|
||||
4. ?
|
||||
5. Profit
|
||||
|
||||
@@ -92,27 +114,27 @@ Meta example of rendering this README:
|
||||
The `Down` struct has everything you need if you just want out-of-the-box setup for parsing and conversion.
|
||||
|
||||
```swift
|
||||
let down = Down(markdownString: "## [Down](https://github.com/iwasrobbed/Down)")
|
||||
let down = Down(markdownString: "## [Down](https://github.com/johnxnguyen/Down)")
|
||||
|
||||
// Convert to HTML
|
||||
let html = try? down.toHTML()
|
||||
// "<h2><a href=\"https://github.com/iwasrobbed/Down\">Down</a></h2>\n"
|
||||
// "<h2><a href=\"https://github.com/johnxnguyen/Down\">Down</a></h2>\n"
|
||||
|
||||
// Convert to XML
|
||||
let xml = try? down.toXML()
|
||||
// "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n<document xmlns=\"http://commonmark.org/xml/1.0\">\n <heading level=\"2\">\n <link destination=\"https://github.com/iwasrobbed/Down\" title=\"\">\n <text>Down</text>\n </link>\n </heading>\n</document>\n"
|
||||
// "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n<document xmlns=\"http://commonmark.org/xml/1.0\">\n <heading level=\"2\">\n <link destination=\"https://github.com/johnxnguyen/Down\" title=\"\">\n <text>Down</text>\n </link>\n </heading>\n</document>\n"
|
||||
|
||||
// Convert to groff man
|
||||
let man = try? down.toGroff()
|
||||
// ".SS\nDown (https://github.com/iwasrobbed/Down)\n"
|
||||
// ".SS\nDown (https://github.com/johnxnguyen/Down)\n"
|
||||
|
||||
// Convert to LaTeX
|
||||
let latex = try? down.toLaTeX()
|
||||
// "\\subsection{\\href{https://github.com/iwasrobbed/Down}{Down}}\n"
|
||||
// "\\subsection{\\href{https://github.com/johnxnguyen/Down}{Down}}\n"
|
||||
|
||||
// Convert to CommonMark Markdown
|
||||
let commonMark = try? down.toCommonMark()
|
||||
// "## [Down](https://github.com/iwasrobbed/Down)\n"
|
||||
// "## [Down](https://github.com/johnxnguyen/Down)\n"
|
||||
|
||||
// Convert to an attributed string
|
||||
let attributedString = try? down.toAttributedString()
|
||||
@@ -166,11 +188,11 @@ public struct MarkdownToHTML: DownHTMLRenderable {
|
||||
`DownView` can be configured with a custom bundle using your own HTML / CSS or to do things like supporting
|
||||
Dynamic Type or custom fonts, etc. It's completely configurable.
|
||||
|
||||
This option can be found in [DownView's instantiation function](https://github.com/iwasrobbed/Down/blob/master/Source/Views/DownView.swift#L26).
|
||||
This option can be found in [DownView's instantiation function](https://github.com/johnxnguyen/Down/blob/master/Source/Views/DownView.swift#L26).
|
||||
|
||||
##### Prevent zoom
|
||||
|
||||
The default implementation of the `DownView` allows for zooming in the rendered content. If you want to disable this, then you’ll need to instantiate the `DownView` with a custom bundle where the `viewport` in `index.html` has been assigned `user-scalable=no`. More info can be found [here](https://github.com/iwasrobbed/Down/pull/30).
|
||||
The default implementation of the `DownView` allows for zooming in the rendered content. If you want to disable this, then you’ll need to instantiate the `DownView` with a custom bundle where the `viewport` in `index.html` has been assigned `user-scalable=no`. More info can be found [here](https://github.com/johnxnguyen/Down/pull/30).
|
||||
|
||||
### Options
|
||||
|
||||
@@ -199,10 +221,18 @@ public static let hardBreaks = DownOptions(rawValue: 1 << 2)
|
||||
`file:`, and `data:`, except for `image/png`, `image/gif`,
|
||||
`image/jpeg`, or `image/webp` mime types). Raw HTML is replaced
|
||||
by a placeholder HTML comment. Unsafe links are replaced by
|
||||
empty strings.
|
||||
empty strings. Note that this option is provided for backwards
|
||||
compatibility, but safe mode is now the default.
|
||||
*/
|
||||
public static let safe = DownOptions(rawValue: 1 << 3)
|
||||
|
||||
/**
|
||||
Allow raw HTML and unsafe links. Note that safe mode is now
|
||||
the default, and the unsafe option must be used if rendering
|
||||
of raw HTML and unsafe links is desired.
|
||||
*/
|
||||
public static let unsafe = DownOptions(rawValue: 1 << 17)
|
||||
|
||||
// MARK: - Parsing Options
|
||||
|
||||
/**
|
||||
@@ -220,6 +250,11 @@ public static let validateUTF8 = DownOptions(rawValue: 1 << 5)
|
||||
Convert straight quotes to curly, --- to em dashes, -- to en dashes.
|
||||
*/
|
||||
public static let smart = DownOptions(rawValue: 1 << 6)
|
||||
|
||||
/**
|
||||
Combine smart typography with HTML rendering.
|
||||
*/
|
||||
public static let smartUnsaFe = DownOptions(rawValue: (1 << 17) + (1 << 6))
|
||||
```
|
||||
|
||||
### Supports
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0
|
||||
WATCHOS_DEPLOYMENT_TARGET = 3.0
|
||||
@@ -1,38 +0,0 @@
|
||||
//
|
||||
// BaseNode.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 21.04.19.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class BaseNode: Node {
|
||||
|
||||
public let cmarkNode: CMarkNode
|
||||
|
||||
public private(set) lazy var children: [Node] = {
|
||||
var result: [Node] = []
|
||||
var child = cmark_node_first_child(cmarkNode)
|
||||
|
||||
while let raw = child {
|
||||
|
||||
guard let node = raw.wrap() else {
|
||||
assertionFailure("Couldn't wrap node of type: \(raw.type)")
|
||||
continue
|
||||
}
|
||||
|
||||
result.append(node)
|
||||
child = cmark_node_next(child)
|
||||
}
|
||||
|
||||
return result
|
||||
}()
|
||||
|
||||
init(cmarkNode: CMarkNode) {
|
||||
self.cmarkNode = cmarkNode
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
//
|
||||
// List.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class List: BaseNode {
|
||||
|
||||
public enum ListType: CustomDebugStringConvertible {
|
||||
case bullet
|
||||
case ordered(start: Int)
|
||||
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .bullet: return "Bullet"
|
||||
case .ordered(let start): return "Ordered (start: \(start)"
|
||||
}
|
||||
}
|
||||
|
||||
init?(cmarkNode: CMarkNode) {
|
||||
switch cmarkNode.listType {
|
||||
case CMARK_BULLET_LIST: self = .bullet
|
||||
case CMARK_ORDERED_LIST: self = .ordered(start: cmarkNode.listStart)
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// The type of the list, either bullet or ordered.
|
||||
public lazy var listType: ListType = {
|
||||
guard let type = ListType(cmarkNode: cmarkNode) else {
|
||||
assertionFailure("Unsupported or missing list type. Defaulting to .bullet.")
|
||||
return .bullet
|
||||
}
|
||||
|
||||
return type
|
||||
}()
|
||||
|
||||
/// The number of items in the list.
|
||||
public lazy var numberOfItems: Int = children.count
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension List: CustomDebugStringConvertible {
|
||||
public var debugDescription: String {
|
||||
return "List - type: \(listType)"
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
//
|
||||
// Styler.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 13.04.19.
|
||||
// Copyright © 2019 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A styler is an object that manipulates the appearance of attributed strings generated
|
||||
/// for each particular markdown node. The attributed string passed into each method is
|
||||
/// mutable, so attributes (and even text) can be added, set, and removed.
|
||||
///
|
||||
/// A styler is used in conjunction with an instance of `AttributedStringVisitor` in order
|
||||
/// to generate an NSAttributedString from an abstract syntax tree.
|
||||
public protocol Styler {
|
||||
func style(document str: NSMutableAttributedString)
|
||||
func style(blockQuote str: NSMutableAttributedString)
|
||||
func style(list str: NSMutableAttributedString)
|
||||
func style(item str: NSMutableAttributedString)
|
||||
func style(codeBlock str: NSMutableAttributedString, fenceInfo: String?)
|
||||
func style(htmlBlock str: NSMutableAttributedString)
|
||||
func style(customBlock str: NSMutableAttributedString)
|
||||
func style(paragraph str: NSMutableAttributedString)
|
||||
func style(heading str: NSMutableAttributedString, level: Int)
|
||||
func style(thematicBreak str: NSMutableAttributedString)
|
||||
func style(text str: NSMutableAttributedString)
|
||||
func style(softBreak str: NSMutableAttributedString)
|
||||
func style(lineBreak str: NSMutableAttributedString)
|
||||
func style(code str: NSMutableAttributedString)
|
||||
func style(htmlInline str: NSMutableAttributedString)
|
||||
func style(customInline str: NSMutableAttributedString)
|
||||
func style(emphasis str: NSMutableAttributedString)
|
||||
func style(strong str: NSMutableAttributedString)
|
||||
func style(link str: NSMutableAttributedString, title: String?, url: String?)
|
||||
func style(image str: NSMutableAttributedString, title: String?, url: String?)
|
||||
|
||||
var listPrefixAttributes: [NSAttributedString.Key: Any] { get }
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
//
|
||||
// AttributedStringVisitor.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// This class is used to generated an `NSMutableAttributedString` from the abstract syntax
|
||||
/// tree produced by a markdown string. It traverses the tree to construct substrings
|
||||
/// represented at each node and uses an instance of `Styler` to apply the visual attributes.
|
||||
/// These substrings are joined together to produce the final result.
|
||||
public class AttributedStringVisitor {
|
||||
|
||||
private let styler: Styler
|
||||
private let options: DownOptions
|
||||
|
||||
/// Creates a new instance with the given styler and options.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - styler: used to style the markdown elements.
|
||||
/// - options: may be used to modify rendering.
|
||||
public init(styler: Styler, options: DownOptions = .default) {
|
||||
self.styler = styler
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension AttributedStringVisitor: Visitor {
|
||||
public typealias Result = NSMutableAttributedString
|
||||
|
||||
public func visit(document node: Document) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
styler.style(document: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(blockQuote node: BlockQuote) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { s.append(.blankLine) }
|
||||
styler.style(blockQuote: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(list node: List) -> NSMutableAttributedString {
|
||||
let items = visitChildren(of: node)
|
||||
|
||||
// Prepend prefixes to each item.
|
||||
items.enumerated().forEach { index, item in
|
||||
let prefix: String
|
||||
switch node.listType {
|
||||
case .bullet: prefix = "•\t"
|
||||
case .ordered(let start): prefix = "\(start + index).\t"
|
||||
}
|
||||
|
||||
let attrPrefix = NSAttributedString(string: prefix, attributes: styler.listPrefixAttributes)
|
||||
item.insert(attrPrefix, at: 0)
|
||||
}
|
||||
|
||||
let s = items.joined
|
||||
if node.hasSuccessor { s.append(.blankLine) }
|
||||
styler.style(list: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(item node: Item) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { s.append(.blankLine) }
|
||||
styler.style(item: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(codeBlock node: CodeBlock) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(codeBlock: s, fenceInfo: node.fenceInfo)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(htmlBlock node: HtmlBlock) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(htmlBlock: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(customBlock node: CustomBlock) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(customBlock: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(paragraph node: Paragraph) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { s.append(.blankLine) }
|
||||
styler.style(paragraph: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(heading node: Heading) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { s.append(.blankLine) }
|
||||
styler.style(heading: s, level: node.headingLevel)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(thematicBreak node: ThematicBreak) -> NSMutableAttributedString {
|
||||
let s = "\n".attributed
|
||||
styler.style(thematicBreak: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(text node: Text) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(text: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(softBreak node: SoftBreak) -> NSMutableAttributedString {
|
||||
let s = (options.contains(.hardBreaks) ? "\n" : " ").attributed
|
||||
styler.style(softBreak: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(lineBreak node: LineBreak) -> NSMutableAttributedString {
|
||||
let s = "\n".attributed
|
||||
styler.style(lineBreak: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(code node: Code) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(code: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(htmlInline node: HtmlInline) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(htmlInline: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(customInline node: CustomInline) -> NSMutableAttributedString {
|
||||
guard let s = node.literal?.attributed else { return .empty }
|
||||
styler.style(customInline: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(emphasis node: Emphasis) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
styler.style(emphasis: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(strong node: Strong) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
styler.style(strong: s)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(link node: Link) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
styler.style(link: s, title: node.title, url: node.url)
|
||||
return s
|
||||
}
|
||||
|
||||
public func visit(image node: Image) -> NSMutableAttributedString {
|
||||
let s = visitChildren(of: node).joined
|
||||
styler.style(image: s, title: node.title, url: node.url)
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper extentions
|
||||
|
||||
private extension Sequence where Iterator.Element == NSMutableAttributedString {
|
||||
var joined: NSMutableAttributedString {
|
||||
return reduce(into: NSMutableAttributedString()) { $0.append($1) }
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
var attributed: NSMutableAttributedString {
|
||||
return NSMutableAttributedString(string: self)
|
||||
}
|
||||
}
|
||||
|
||||
private extension NSAttributedString {
|
||||
static var blankLine: NSAttributedString {
|
||||
return "\n".attributed
|
||||
}
|
||||
}
|
||||
|
||||
private extension NSMutableAttributedString {
|
||||
static var empty: NSMutableAttributedString {
|
||||
return "".attributed
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// DownASTRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownASTRenderable: DownRenderable {
|
||||
func toAST(_ options: DownOptions) throws -> UnsafeMutablePointer<cmark_node>
|
||||
}
|
||||
|
||||
extension DownASTRenderable {
|
||||
/// Generates an abstract syntax tree from the `markdownString` property
|
||||
///
|
||||
/// - Parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: An abstract syntax tree representation of the Markdown input
|
||||
/// - Throws: `MarkdownToASTError` if conversion fails
|
||||
public func toAST(_ options: DownOptions = .default) throws -> UnsafeMutablePointer<cmark_node> {
|
||||
return try DownASTRenderer.stringToAST(markdownString, options: options)
|
||||
}
|
||||
}
|
||||
|
||||
public struct DownASTRenderer {
|
||||
/// Generates an abstract syntax tree from the given CommonMark Markdown string
|
||||
///
|
||||
/// **Important:** It is the caller's responsibility to call `cmark_node_free(ast)` on the returned value
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - string: A string containing CommonMark Markdown
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: An abstract syntax tree representation of the Markdown input
|
||||
/// - Throws: `MarkdownToASTError` if conversion fails
|
||||
public static func stringToAST(_ string: String, options: DownOptions = .default) throws -> UnsafeMutablePointer<cmark_node> {
|
||||
var tree: UnsafeMutablePointer<cmark_node>?
|
||||
string.withCString {
|
||||
let stringLength = Int(strlen($0))
|
||||
tree = cmark_parse_document($0, stringLength, options.rawValue)
|
||||
}
|
||||
|
||||
guard let ast = tree else {
|
||||
throw DownErrors.markdownToASTError
|
||||
}
|
||||
return ast
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
//
|
||||
// DownView.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
#if os(tvOS) || os(watchOS)
|
||||
// Sorry, not available for tvOS nor watchOS
|
||||
#else
|
||||
import WebKit
|
||||
|
||||
// MARK: - Public API
|
||||
|
||||
public typealias DownViewClosure = () -> ()
|
||||
|
||||
open class DownView: WKWebView {
|
||||
|
||||
/// Initializes a web view with the results of rendering a CommonMark Markdown string
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - frame: The frame size of the web view
|
||||
/// - markdownString: A string containing CommonMark Markdown
|
||||
/// - openLinksInBrowser: Whether or not to open links using an external browser
|
||||
/// - templateBundle: Optional custom template bundle. Leaving this as `nil` will use the bundle included with Down.
|
||||
/// - configuration: Optional custom web view configuration.
|
||||
/// - didLoadSuccessfully: Optional callback for when the web content has loaded successfully
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
public init(frame: CGRect, markdownString: String, openLinksInBrowser: Bool = true, templateBundle: Bundle? = nil, configuration: WKWebViewConfiguration? = nil, didLoadSuccessfully: DownViewClosure? = nil) throws {
|
||||
self.didLoadSuccessfully = didLoadSuccessfully
|
||||
|
||||
if let templateBundle = templateBundle {
|
||||
self.bundle = templateBundle
|
||||
} else {
|
||||
let classBundle = Bundle(for: DownView.self)
|
||||
let url = classBundle.url(forResource: "DownView", withExtension: "bundle")!
|
||||
self.bundle = Bundle(url: url)!
|
||||
}
|
||||
|
||||
super.init(frame: frame, configuration: configuration ?? WKWebViewConfiguration())
|
||||
|
||||
#if os(macOS)
|
||||
setupMacEnvironment()
|
||||
#endif
|
||||
|
||||
if openLinksInBrowser || didLoadSuccessfully != nil { navigationDelegate = self }
|
||||
try loadHTMLView(markdownString)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
deinit {
|
||||
clearTemporaryDirectory()
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: - API
|
||||
|
||||
/// Renders the given CommonMark Markdown string into HTML and updates the DownView while keeping the style intact
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - markdownString: A string containing CommonMark Markdown
|
||||
/// - didLoadSuccessfully: Optional callback for when the web content has loaded successfully
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
public func update(markdownString: String, didLoadSuccessfully: DownViewClosure? = nil) throws {
|
||||
// Note: As the init method takes this callback already, we only overwrite it here if
|
||||
// a non-nil value is passed in
|
||||
if let didLoadSuccessfully = didLoadSuccessfully {
|
||||
self.didLoadSuccessfully = didLoadSuccessfully
|
||||
}
|
||||
|
||||
try loadHTMLView(markdownString)
|
||||
}
|
||||
|
||||
// MARK: - Private Properties
|
||||
|
||||
let bundle: Bundle
|
||||
|
||||
private lazy var baseURL: URL = {
|
||||
return self.bundle.url(forResource: "index", withExtension: "html")!
|
||||
}()
|
||||
|
||||
#if os(macOS)
|
||||
private lazy var temporaryDirectoryURL: URL = {
|
||||
return try! FileManager.default.url(for: .itemReplacementDirectory,
|
||||
in: .userDomainMask,
|
||||
appropriateFor: URL(fileURLWithPath: "/"),
|
||||
create: true).appendingPathComponent("Down", isDirectory: true)
|
||||
}()
|
||||
#endif
|
||||
|
||||
private var didLoadSuccessfully: DownViewClosure?
|
||||
}
|
||||
|
||||
// MARK: - Private API
|
||||
|
||||
private extension DownView {
|
||||
|
||||
func loadHTMLView(_ markdownString: String) throws {
|
||||
let htmlString = try markdownString.toHTML()
|
||||
let pageHTMLString = try htmlFromTemplate(htmlString)
|
||||
|
||||
#if os(iOS)
|
||||
loadHTMLString(pageHTMLString, baseURL: baseURL)
|
||||
#elseif os(macOS)
|
||||
let indexURL = try createTemporaryBundle(pageHTMLString: pageHTMLString)
|
||||
loadFileURL(indexURL, allowingReadAccessTo: indexURL.deletingLastPathComponent())
|
||||
#endif
|
||||
}
|
||||
|
||||
func htmlFromTemplate(_ htmlString: String) throws -> String {
|
||||
let template = try String(contentsOf: baseURL, encoding: .utf8)
|
||||
return template.replacingOccurrences(of: "DOWN_HTML", with: htmlString)
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
func createTemporaryBundle(pageHTMLString: String) throws -> URL {
|
||||
guard let bundleResourceURL = bundle.resourceURL
|
||||
else { throw DownErrors.nonStandardBundleFormatError }
|
||||
let indexURL = temporaryDirectoryURL.appendingPathComponent("index.html", isDirectory: false)
|
||||
|
||||
// If updating markdown contents, no need to re-copy bundle.
|
||||
if !FileManager.default.fileExists(atPath: indexURL.path) {
|
||||
// Copy bundle resources to temporary location.
|
||||
try FileManager.default.copyItem(at: bundleResourceURL, to: temporaryDirectoryURL)
|
||||
}
|
||||
|
||||
// Write generated index.html to temporary location.
|
||||
try pageHTMLString.write(to: indexURL, atomically: true, encoding: .utf8)
|
||||
|
||||
return indexURL
|
||||
}
|
||||
|
||||
func setupMacEnvironment() {
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(clearTemporaryDirectory),
|
||||
name: NSApplication.willTerminateNotification,
|
||||
object: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func clearTemporaryDirectory() {
|
||||
try? FileManager.default.removeItem(at: temporaryDirectoryURL)
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// MARK: - WKNavigationDelegate
|
||||
|
||||
extension DownView: WKNavigationDelegate {
|
||||
public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
|
||||
decisionHandler(.allow)
|
||||
}
|
||||
|
||||
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||
guard let url = navigationAction.request.url else { return decisionHandler(.allow) }
|
||||
|
||||
switch navigationAction.navigationType {
|
||||
case .linkActivated:
|
||||
if #available(iOS 11.0, macOS 10.13, *) {
|
||||
if let scheme = url.scheme, configuration.urlSchemeHandler(forURLScheme: scheme) != nil {
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
decisionHandler(.cancel)
|
||||
openURL(url: url)
|
||||
default:
|
||||
decisionHandler(.allow)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
func openURL(url: URL) {
|
||||
#if os(iOS)
|
||||
UIApplication.shared.openURL(url)
|
||||
#elseif os(macOS)
|
||||
NSWorkspace.shared.open(url)
|
||||
#endif
|
||||
}
|
||||
|
||||
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
didLoadSuccessfully?()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension WKNavigationDelegate {
|
||||
/// A wrapper for `UIApplication.shared.openURL` so that an empty default
|
||||
/// implementation is available in app extensions
|
||||
func openURL(url: URL) {}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// BaseNode.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 21.04.19.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class BaseNode: Node {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public let cmarkNode: CMarkNode
|
||||
|
||||
public private(set) lazy var children: [Node] = Array(childSequence)
|
||||
|
||||
public private(set) lazy var nestDepth: Int = {
|
||||
var depth = 0
|
||||
var next = cmarkNode.parent
|
||||
|
||||
while let current = next {
|
||||
depth += current.type == cmarkNode.type ? 1 : 0
|
||||
next = current.parent
|
||||
}
|
||||
return depth
|
||||
}()
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
init(cmarkNode: CMarkNode) {
|
||||
self.cmarkNode = cmarkNode
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class BlockQuote: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension BlockQuote: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Block Quote"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// ChildSequence.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Sven Weidauer on 05.10.2020
|
||||
//
|
||||
|
||||
import libcmark
|
||||
|
||||
/// Sequence of child nodes.
|
||||
|
||||
public struct ChildSequence: Sequence {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
let node: CMarkNode
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
public func makeIterator() -> Iterator {
|
||||
return Iterator(node: cmark_node_first_child(node))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Iterator
|
||||
|
||||
public extension ChildSequence {
|
||||
|
||||
struct Iterator: IteratorProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var node: CMarkNode?
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
public mutating func next() -> Node? {
|
||||
guard let node = node else { return nil }
|
||||
defer { self.node = cmark_node_next(node) }
|
||||
|
||||
guard let result = node.wrap() else {
|
||||
assertionFailure("Couldn't wrap node of type: \(node.type)")
|
||||
return nil
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,21 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Code: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The code content, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Code: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Code - \(literal ?? "nil")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,10 +9,13 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class CodeBlock: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The code content, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
|
||||
|
||||
/// The fence info is an optional string that trails the opening sequence of backticks.
|
||||
/// It can be used to provide some contextual information about the block, such as
|
||||
/// the name of a programming language.
|
||||
@@ -24,14 +27,18 @@ public class CodeBlock: BaseNode {
|
||||
/// '''
|
||||
/// ```
|
||||
///
|
||||
|
||||
public private(set) lazy var fenceInfo: String? = cmarkNode.fenceInfo
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension CodeBlock: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Code Block - \(literal ?? "nil"), fenceInfo: \(fenceInfo ?? "nil")"
|
||||
let content = (literal ?? "nil").replacingOccurrences(of: "\n", with: "\\n")
|
||||
return "Code Block - fenceInfo: \(fenceInfo ?? "nil"), content: \(content)"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,21 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class CustomBlock: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properfies
|
||||
|
||||
/// The custom content, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension CustomBlock: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Custom Block - \(literal ?? "nil")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,15 +9,20 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class CustomInline: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The custom content, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension CustomInline: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Custom Inline - \(literal ?? "nil")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,24 +9,30 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Document: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
deinit {
|
||||
// Frees the node and all its children.
|
||||
cmark_node_free(cmarkNode)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
/// Accepts the given visitor and return its result.
|
||||
|
||||
@discardableResult
|
||||
public func accept<T: Visitor>(_ visitor: T) -> T.Result {
|
||||
return visitor.visit(document: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Document: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Document"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class Emphasis: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension Emphasis: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Emphasis"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,15 +9,20 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Heading: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The level of the heading, a value between 1 and 6.
|
||||
|
||||
public private(set) lazy var headingLevel: Int = cmarkNode.headingLevel
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Heading: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Heading - L\(headingLevel)"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,22 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class HtmlBlock: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The html content, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension HtmlBlock: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Html Block - \(literal ?? "nil")"
|
||||
let content = (literal ?? "nil").replacingOccurrences(of: "\n", with: "\\n")
|
||||
return "Html Block - content: \(content)"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,21 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class HtmlInline: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The html tag, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension HtmlInline: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Html Inline - \(literal ?? "nil")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Image: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The title of the image, if present.
|
||||
///
|
||||
/// In the example below, the first line is a reference link, with the reference at the
|
||||
@@ -21,9 +23,9 @@ public class Image: BaseNode {
|
||||
/// ...
|
||||
/// [<id>]: <url> "<title>"
|
||||
/// ```
|
||||
///
|
||||
|
||||
public private(set) lazy var title: String? = cmarkNode.title
|
||||
|
||||
|
||||
/// The url of the image, if present.
|
||||
///
|
||||
/// For example:
|
||||
@@ -31,15 +33,17 @@ public class Image: BaseNode {
|
||||
/// ```
|
||||
/// 
|
||||
/// ```
|
||||
///
|
||||
|
||||
public private(set) lazy var url: String? = cmarkNode.url
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Image: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Image - title: \(title ?? "nil"), url: \(url ?? "nil"))"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class Item: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension Item: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Item"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class LineBreak: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension LineBreak: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Line Break"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Link: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The title of the link, if present.
|
||||
///
|
||||
/// In the example below, the first line is a reference link, with the reference at the
|
||||
@@ -21,9 +23,9 @@ public class Link: BaseNode {
|
||||
/// ...
|
||||
/// [<id>]: <url> "<title>"
|
||||
/// ```
|
||||
///
|
||||
|
||||
public private(set) lazy var title: String? = cmarkNode.title
|
||||
|
||||
|
||||
/// The url of the link, if present.
|
||||
///
|
||||
/// For example:
|
||||
@@ -31,15 +33,17 @@ public class Link: BaseNode {
|
||||
/// ```
|
||||
/// [<text>](<url>)
|
||||
/// ```
|
||||
///
|
||||
|
||||
public private(set) lazy var url: String? = cmarkNode.url
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Link: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Link - title: \(title ?? "nil"), url: \(url ?? "nil"))"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// List.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class List: BaseNode {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The type of the list, either bullet or ordered.
|
||||
|
||||
public lazy var listType: ListType = {
|
||||
guard let type = ListType(cmarkNode: cmarkNode) else {
|
||||
assertionFailure("Unsupported or missing list type. Defaulting to .bullet.")
|
||||
return .bullet
|
||||
}
|
||||
|
||||
return type
|
||||
}()
|
||||
|
||||
/// The number of items in the list.
|
||||
|
||||
public lazy var numberOfItems: Int = children.count
|
||||
|
||||
/// Whether the list is "tight".
|
||||
///
|
||||
/// If any of the list items are separated by a blank line, then this property is `false`. This value is
|
||||
/// a hint to render the list with more (loose) or less (tight) spacing between items.
|
||||
|
||||
public lazy var isTight: Bool = cmark_node_get_list_tight(cmarkNode) == 1
|
||||
|
||||
/// The list delimiter.
|
||||
|
||||
public lazy var delimiter: Delimiter? = Delimiter(cmarkNode.listDelimiter)
|
||||
}
|
||||
|
||||
// MARK: - List Type
|
||||
|
||||
public extension List {
|
||||
|
||||
enum Delimiter {
|
||||
case period
|
||||
case paren
|
||||
|
||||
init?(_ cmark: cmark_delim_type) {
|
||||
switch cmark {
|
||||
case CMARK_NO_DELIM: return nil
|
||||
case CMARK_PERIOD_DELIM: self = .period
|
||||
case CMARK_PAREN_DELIM: self = .paren
|
||||
default: preconditionFailure("Invalid delim type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ListType: CustomDebugStringConvertible {
|
||||
case bullet
|
||||
case ordered(start: Int)
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .bullet: return "Bullet"
|
||||
case .ordered(let start): return "Ordered (start: \(start))"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
init?(cmarkNode: CMarkNode) {
|
||||
switch cmarkNode.listType {
|
||||
case CMARK_BULLET_LIST: self = .bullet
|
||||
case CMARK_ORDERED_LIST: self = .ordered(start: cmarkNode.listStart)
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension List: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
var result = "List - type: \(listType), isTight: \(isTight)"
|
||||
if let delim = delimiter {
|
||||
result += ", delimiter: \(delim)"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension List.Delimiter: CustomDebugStringConvertible {
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .paren: return "paren"
|
||||
case .period: return "period"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,28 +10,43 @@ import libcmark
|
||||
|
||||
/// A node is a wrapper of a raw `CMarkNode` belonging to the abstract syntax tree
|
||||
/// generated by cmark.
|
||||
|
||||
public protocol Node {
|
||||
|
||||
/// The wrapped node.
|
||||
|
||||
var cmarkNode: CMarkNode { get }
|
||||
|
||||
|
||||
/// The wrapped child nodes.
|
||||
|
||||
var children: [Node] { get }
|
||||
|
||||
}
|
||||
|
||||
public extension Node {
|
||||
|
||||
/// True iff the node has a sibling that succeeds it.
|
||||
|
||||
var hasSuccessor: Bool {
|
||||
return cmark_node_next(cmarkNode) != nil
|
||||
}
|
||||
|
||||
/// Sequence of wrapped child nodes.
|
||||
|
||||
var childSequence: ChildSequence {
|
||||
return ChildSequence(node: cmarkNode)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helper extensions
|
||||
|
||||
public typealias CMarkNode = UnsafeMutablePointer<cmark_node>
|
||||
|
||||
public extension UnsafeMutablePointer where Pointee == cmark_node {
|
||||
|
||||
public extension CMarkNode {
|
||||
|
||||
/// Wraps the cmark node referred to by this pointer.
|
||||
|
||||
func wrap() -> Node? {
|
||||
switch type {
|
||||
case CMARK_NODE_DOCUMENT: return Document(cmarkNode: self)
|
||||
@@ -57,45 +72,55 @@ public extension UnsafeMutablePointer where Pointee == cmark_node {
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var parent: CMarkNode? {
|
||||
return cmark_node_parent(self)
|
||||
}
|
||||
|
||||
var type: cmark_node_type {
|
||||
return cmark_node_get_type(self)
|
||||
}
|
||||
|
||||
|
||||
var literal: String? {
|
||||
return String(cString: cmark_node_get_literal(self))
|
||||
}
|
||||
|
||||
|
||||
var fenceInfo: String? {
|
||||
return String(cString: cmark_node_get_fence_info(self))
|
||||
}
|
||||
|
||||
|
||||
var headingLevel: Int {
|
||||
return Int(cmark_node_get_heading_level(self))
|
||||
}
|
||||
|
||||
|
||||
var listType: cmark_list_type {
|
||||
return cmark_node_get_list_type(self)
|
||||
}
|
||||
|
||||
|
||||
var listStart: Int {
|
||||
return Int(cmark_node_get_list_start(self))
|
||||
}
|
||||
|
||||
|
||||
var listDelimiter: cmark_delim_type {
|
||||
return cmark_node_get_list_delim(self)
|
||||
}
|
||||
|
||||
var url: String? {
|
||||
return String(cString: cmark_node_get_url(self))
|
||||
}
|
||||
|
||||
|
||||
var title: String? {
|
||||
return String(cString: cmark_node_get_title(self))
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
|
||||
init?(cString: UnsafePointer<Int8>?) {
|
||||
guard let unwrapped = cString else { return nil }
|
||||
let result = String(cString: unwrapped)
|
||||
guard !result.isEmpty else { return nil }
|
||||
self = result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class Paragraph: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension Paragraph: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Paragraph"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class SoftBreak: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension SoftBreak: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Soft Break"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class Strong: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension Strong: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Strong"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,21 @@ import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Text: BaseNode {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// The text content, if present.
|
||||
|
||||
public private(set) lazy var literal: String? = cmarkNode.literal
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Text: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Text - \(literal ?? "nil")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class ThematicBreak: BaseNode {}
|
||||
// MARK: - Debug
|
||||
|
||||
extension ThematicBreak: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Thematic Break"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// ColorCollection.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 27.07.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
public typealias DownColor = UIColor
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
public typealias DownColor = NSColor
|
||||
|
||||
#endif
|
||||
|
||||
public protocol ColorCollection {
|
||||
|
||||
var heading1: DownColor { get }
|
||||
var heading2: DownColor { get }
|
||||
var heading3: DownColor { get }
|
||||
var heading4: DownColor { get }
|
||||
var heading5: DownColor { get }
|
||||
var heading6: DownColor { get }
|
||||
var body: DownColor { get }
|
||||
var code: DownColor { get }
|
||||
var link: DownColor { get }
|
||||
var quote: DownColor { get }
|
||||
var quoteStripe: DownColor { get }
|
||||
var thematicBreak: DownColor { get }
|
||||
var listItemPrefix: DownColor { get }
|
||||
var codeBlockBackground: DownColor { get }
|
||||
|
||||
}
|
||||
|
||||
public struct StaticColorCollection: ColorCollection {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var heading1: DownColor
|
||||
public var heading2: DownColor
|
||||
public var heading3: DownColor
|
||||
public var heading4: DownColor
|
||||
public var heading5: DownColor
|
||||
public var heading6: DownColor
|
||||
public var body: DownColor
|
||||
public var code: DownColor
|
||||
public var link: DownColor
|
||||
public var quote: DownColor
|
||||
public var quoteStripe: DownColor
|
||||
public var thematicBreak: DownColor
|
||||
public var listItemPrefix: DownColor
|
||||
public var codeBlockBackground: DownColor
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(
|
||||
heading1: DownColor = .black,
|
||||
heading2: DownColor = .black,
|
||||
heading3: DownColor = .black,
|
||||
heading4: DownColor = .black,
|
||||
heading5: DownColor = .black,
|
||||
heading6: DownColor = .black,
|
||||
body: DownColor = .black,
|
||||
code: DownColor = .black,
|
||||
link: DownColor = .blue,
|
||||
quote: DownColor = .darkGray,
|
||||
quoteStripe: DownColor = .darkGray,
|
||||
thematicBreak: DownColor = .init(white: 0.9, alpha: 1),
|
||||
listItemPrefix: DownColor = .lightGray,
|
||||
codeBlockBackground: DownColor = .init(red: 0.96, green: 0.97, blue: 0.98, alpha: 1)
|
||||
) {
|
||||
self.heading1 = heading1
|
||||
self.heading2 = heading2
|
||||
self.heading3 = heading3
|
||||
self.heading4 = heading4
|
||||
self.heading5 = heading5
|
||||
self.heading6 = heading6
|
||||
self.body = body
|
||||
self.code = code
|
||||
self.link = link
|
||||
self.quote = quote
|
||||
self.quoteStripe = quoteStripe
|
||||
self.thematicBreak = thematicBreak
|
||||
self.listItemPrefix = listItemPrefix
|
||||
self.codeBlockBackground = codeBlockBackground
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// FontCollection.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 22.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
public typealias DownFont = UIFont
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
public typealias DownFont = NSFont
|
||||
|
||||
#endif
|
||||
|
||||
public protocol FontCollection {
|
||||
|
||||
var heading1: DownFont { get }
|
||||
var heading2: DownFont { get }
|
||||
var heading3: DownFont { get }
|
||||
var heading4: DownFont { get }
|
||||
var heading5: DownFont { get }
|
||||
var heading6: DownFont { get }
|
||||
var body: DownFont { get }
|
||||
var code: DownFont { get }
|
||||
var listItemPrefix: DownFont { get }
|
||||
|
||||
}
|
||||
|
||||
public struct StaticFontCollection: FontCollection {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var heading1: DownFont
|
||||
public var heading2: DownFont
|
||||
public var heading3: DownFont
|
||||
public var heading4: DownFont
|
||||
public var heading5: DownFont
|
||||
public var heading6: DownFont
|
||||
public var body: DownFont
|
||||
public var code: DownFont
|
||||
public var listItemPrefix: DownFont
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(
|
||||
heading1: DownFont = .boldSystemFont(ofSize: 28),
|
||||
heading2: DownFont = .boldSystemFont(ofSize: 24),
|
||||
heading3: DownFont = .boldSystemFont(ofSize: 20),
|
||||
heading4: DownFont = .boldSystemFont(ofSize: 20),
|
||||
heading5: DownFont = .boldSystemFont(ofSize: 20),
|
||||
heading6: DownFont = .boldSystemFont(ofSize: 20),
|
||||
body: DownFont = .systemFont(ofSize: 17),
|
||||
code: DownFont = DownFont(name: "menlo", size: 17) ?? .systemFont(ofSize: 17),
|
||||
listItemPrefix: DownFont = DownFont.monospacedDigitSystemFont(ofSize: 17, weight: .regular)
|
||||
) {
|
||||
self.heading1 = heading1
|
||||
self.heading2 = heading2
|
||||
self.heading3 = heading3
|
||||
self.heading4 = heading4
|
||||
self.heading5 = heading5
|
||||
self.heading6 = heading6
|
||||
self.body = body
|
||||
self.code = code
|
||||
self.listItemPrefix = listItemPrefix
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// ParagraphStyleCollection.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 27.07.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
public protocol ParagraphStyleCollection {
|
||||
|
||||
var heading1: NSParagraphStyle { get }
|
||||
var heading2: NSParagraphStyle { get }
|
||||
var heading3: NSParagraphStyle { get }
|
||||
var heading4: NSParagraphStyle { get }
|
||||
var heading5: NSParagraphStyle { get }
|
||||
var heading6: NSParagraphStyle { get }
|
||||
var body: NSParagraphStyle { get }
|
||||
var code: NSParagraphStyle { get }
|
||||
|
||||
}
|
||||
|
||||
public struct StaticParagraphStyleCollection: ParagraphStyleCollection {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var heading1: NSParagraphStyle
|
||||
public var heading2: NSParagraphStyle
|
||||
public var heading3: NSParagraphStyle
|
||||
public var heading4: NSParagraphStyle
|
||||
public var heading5: NSParagraphStyle
|
||||
public var heading6: NSParagraphStyle
|
||||
public var body: NSParagraphStyle
|
||||
public var code: NSParagraphStyle
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init() {
|
||||
let headingStyle = NSMutableParagraphStyle()
|
||||
headingStyle.paragraphSpacing = 8
|
||||
|
||||
let bodyStyle = NSMutableParagraphStyle()
|
||||
bodyStyle.paragraphSpacingBefore = 8
|
||||
bodyStyle.paragraphSpacing = 8
|
||||
bodyStyle.lineSpacing = 8
|
||||
|
||||
let codeStyle = NSMutableParagraphStyle()
|
||||
codeStyle.paragraphSpacingBefore = 8
|
||||
codeStyle.paragraphSpacing = 8
|
||||
|
||||
heading1 = headingStyle
|
||||
heading2 = headingStyle
|
||||
heading3 = headingStyle
|
||||
heading4 = headingStyle
|
||||
heading5 = headingStyle
|
||||
heading6 = headingStyle
|
||||
body = bodyStyle
|
||||
code = codeStyle
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// BlockBackgroundColorAttribute.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 11.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
struct BlockBackgroundColorAttribute {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var color: DownColor
|
||||
var inset: CGFloat
|
||||
|
||||
}
|
||||
|
||||
extension NSAttributedString.Key {
|
||||
|
||||
static let blockBackgroundColor = NSAttributedString.Key("blockBackgroundColor")
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// QuoteStripeAttrbute.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 03.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
struct QuoteStripeAttribute {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var color: DownColor
|
||||
var thickness: CGFloat
|
||||
var spacingAfter: CGFloat
|
||||
var locations: [CGFloat]
|
||||
|
||||
var layoutWidth: CGFloat {
|
||||
return thickness + spacingAfter
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
init(color: DownColor, thickness: CGFloat, spacingAfter: CGFloat, locations: [CGFloat]) {
|
||||
self.color = color
|
||||
self.thickness = thickness
|
||||
self.spacingAfter = spacingAfter
|
||||
self.locations = locations
|
||||
}
|
||||
|
||||
init(level: Int, color: DownColor, options: QuoteStripeOptions) {
|
||||
self.init(color: color, thickness: options.thickness, spacingAfter: options.spacingAfter, locations: [])
|
||||
locations = (0..<level).map { CGFloat($0) * layoutWidth }
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
func indented(by indentation: CGFloat) -> QuoteStripeAttribute {
|
||||
var copy = self
|
||||
copy.locations = locations.map { $0 + indentation }
|
||||
return copy
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NSAttributedString.Key {
|
||||
|
||||
static let quoteStripe = NSAttributedString.Key(rawValue: "quoteStripe")
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ThematicBreaAttributek.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 02.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
struct ThematicBreakAttribute {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var thickness: CGFloat
|
||||
var color: DownColor
|
||||
|
||||
}
|
||||
|
||||
extension NSAttributedString.Key {
|
||||
|
||||
static let thematicBreak = NSAttributedString.Key(rawValue: "thematicBreak")
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// CGPoint+Translate.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 12.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
extension CGPoint {
|
||||
|
||||
func translated(by point: CGPoint) -> CGPoint {
|
||||
return CGPoint(x: x + point.x, y: y + point.y)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// CGRect+Helpers.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 12.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
extension CGRect {
|
||||
|
||||
init(minX: CGFloat, minY: CGFloat, maxX: CGFloat, maxY: CGFloat) {
|
||||
self.init(x: minX, y: minY, width: maxX - minX, height: maxY - minY)
|
||||
}
|
||||
|
||||
func translated(by point: CGPoint) -> CGRect {
|
||||
return CGRect(origin: origin.translated(by: point), size: size)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// NSAttributedString+Helpers.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 22.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NSAttributedString {
|
||||
|
||||
typealias Attributes = [NSAttributedString.Key: Any]
|
||||
|
||||
// MARK: - Ranges
|
||||
|
||||
var wholeRange: NSRange {
|
||||
return NSRange(location: 0, length: length)
|
||||
}
|
||||
|
||||
func ranges(of key: Key) -> [NSRange] {
|
||||
return ranges(of: key, in: wholeRange)
|
||||
}
|
||||
|
||||
func ranges(of key: Key, in range: NSRange) -> [NSRange] {
|
||||
return ranges(for: key, in: range, where: { $0 != nil })
|
||||
}
|
||||
|
||||
func rangesMissingAttribute(for key: Key) -> [NSRange] {
|
||||
return rangesMissingAttribute(for: key, in: wholeRange)
|
||||
}
|
||||
|
||||
func rangesMissingAttribute(for key: Key, in range: NSRange) -> [NSRange] {
|
||||
return ranges(for: key, in: range, where: { $0 == nil })
|
||||
}
|
||||
|
||||
private func ranges(for key: Key, in range: NSRange, where predicate: (Any?) -> Bool) -> [NSRange] {
|
||||
var ranges = [NSRange]()
|
||||
|
||||
enumerateAttribute(key, in: range, options: []) { value, attrRange, _ in
|
||||
if predicate(value) {
|
||||
ranges.append(attrRange)
|
||||
}
|
||||
}
|
||||
|
||||
return ranges
|
||||
}
|
||||
|
||||
func paragraphRanges() -> [NSRange] {
|
||||
guard length > 0 else { return [] }
|
||||
|
||||
func nextParagraphRange(at location: Int) -> NSRange {
|
||||
return NSString(string: string).paragraphRange(for: NSRange(location: location, length: 1))
|
||||
}
|
||||
|
||||
var result = [nextParagraphRange(at: 0)]
|
||||
|
||||
while let currentLocation = result.last?.upperBound, currentLocation < length {
|
||||
result.append(nextParagraphRange(at: currentLocation))
|
||||
}
|
||||
|
||||
return result.filter { $0.length > 1 }
|
||||
}
|
||||
|
||||
// MARK: - Enumerate attributes
|
||||
|
||||
func enumerateAttributes<A>(for key: Key, block: (_ attr: A, _ range: NSRange) -> Void) {
|
||||
enumerateAttributes(for: key, in: wholeRange, block: block)
|
||||
}
|
||||
|
||||
func enumerateAttributes<A>(for key: Key, in range: NSRange, block: (_ attr: A, _ range: NSRange) -> Void) {
|
||||
enumerateAttribute(key, in: range, options: []) { value, range, _ in
|
||||
if let value = value as? A {
|
||||
block(value, range)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// NSMutableAttributedString+Attributes.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 22.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NSMutableAttributedString {
|
||||
|
||||
func setAttributes(_ attrs: Attributes) {
|
||||
setAttributes(attrs, range: wholeRange)
|
||||
}
|
||||
|
||||
func addAttributes(_ attrs: Attributes) {
|
||||
addAttributes(attrs, range: wholeRange)
|
||||
}
|
||||
|
||||
func addAttribute(for key: Key, value: Any) {
|
||||
addAttribute(key, value: value, range: wholeRange)
|
||||
}
|
||||
|
||||
func removeAttribute(for key: Key) {
|
||||
removeAttribute(key, range: wholeRange)
|
||||
}
|
||||
|
||||
func replaceAttribute(for key: Key, value: Any) {
|
||||
replaceAttribute(for: key, value: value, inRange: wholeRange)
|
||||
}
|
||||
|
||||
func replaceAttribute(for key: Key, value: Any, inRange range: NSRange) {
|
||||
removeAttribute(key, range: range)
|
||||
addAttribute(key, value: value, range: range)
|
||||
}
|
||||
|
||||
func updateExistingAttributes<A>(for key: Key, using transform: (A) -> A) {
|
||||
updateExistingAttributes(for: key, in: wholeRange, using: transform)
|
||||
}
|
||||
|
||||
func updateExistingAttributes<A>(for key: Key, in range: NSRange, using transform: (A) -> A) {
|
||||
var existingValues = [(value: A, range: NSRange)]()
|
||||
enumerateAttributes(for: key, in: range) { existingValues.append(($0, $1)) }
|
||||
existingValues.forEach { addAttribute(key, value: transform($0.0), range: $0.1) }
|
||||
}
|
||||
|
||||
func addAttributeInMissingRanges<A>(for key: Key, value: A) {
|
||||
addAttributeInMissingRanges(for: key, value: value, within: wholeRange)
|
||||
}
|
||||
|
||||
func addAttributeInMissingRanges<A>(for key: Key, value: A, within range: NSRange) {
|
||||
rangesMissingAttribute(for: key, in: range).forEach {
|
||||
addAttribute(key, value: value, range: $0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// UIFont+Traits.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 22.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
public typealias DownFontDescriptor = UIFontDescriptor
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
public typealias DownFontDescriptor = NSFontDescriptor
|
||||
|
||||
#endif
|
||||
|
||||
extension DownFont {
|
||||
|
||||
var isStrong: Bool {
|
||||
return contains(.strong)
|
||||
}
|
||||
|
||||
var isEmphasized: Bool {
|
||||
return contains(.emphasis)
|
||||
}
|
||||
|
||||
var isMonospace: Bool {
|
||||
return contains(.monoSpace)
|
||||
}
|
||||
|
||||
var strong: DownFont {
|
||||
return with(.strong) ?? self
|
||||
}
|
||||
|
||||
var emphasis: DownFont {
|
||||
return with(.emphasis) ?? self
|
||||
}
|
||||
|
||||
var monospace: DownFont {
|
||||
return with(.monoSpace) ?? self
|
||||
}
|
||||
|
||||
private func with(_ trait: DownFontDescriptor.SymbolicTraits) -> DownFont? {
|
||||
guard !contains(trait) else { return self }
|
||||
|
||||
var traits = fontDescriptor.symbolicTraits
|
||||
traits.insert(trait)
|
||||
|
||||
#if canImport(UIKit)
|
||||
guard let newDescriptor = fontDescriptor.withSymbolicTraits(traits) else { return self }
|
||||
return DownFont(descriptor: newDescriptor, size: pointSize)
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
let newDescriptor = fontDescriptor.withSymbolicTraits(traits)
|
||||
return DownFont(descriptor: newDescriptor, size: pointSize)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
private func contains(_ trait: DownFontDescriptor.SymbolicTraits) -> Bool {
|
||||
return fontDescriptor.symbolicTraits.contains(trait)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
private extension DownFontDescriptor.SymbolicTraits {
|
||||
|
||||
static let strong = DownFontDescriptor.SymbolicTraits.traitBold
|
||||
static let emphasis = DownFontDescriptor.SymbolicTraits.traitItalic
|
||||
static let monoSpace = DownFontDescriptor.SymbolicTraits.traitMonoSpace
|
||||
|
||||
}
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
private extension DownFontDescriptor.SymbolicTraits {
|
||||
|
||||
static let strong = DownFontDescriptor.SymbolicTraits.bold
|
||||
static let emphasis = DownFontDescriptor.SymbolicTraits.italic
|
||||
static let monoSpace = DownFontDescriptor.SymbolicTraits.monoSpace
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// ParagraphStyler.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 25.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
/// A convenient class used to format lists, such that list item prefixes
|
||||
/// are right aligned and list item content left aligns.
|
||||
|
||||
public class ListItemParagraphStyler {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var indentation: CGFloat {
|
||||
return largestPrefixWidth + options.spacingAfterPrefix
|
||||
}
|
||||
|
||||
/// The paragraph style intended for all paragraphs excluding the first.
|
||||
|
||||
public var trailingParagraphStyle: NSParagraphStyle {
|
||||
let contentIndentation = indentation
|
||||
let style = baseStyle
|
||||
style.firstLineHeadIndent = contentIndentation
|
||||
style.headIndent = contentIndentation
|
||||
return style
|
||||
}
|
||||
|
||||
private let options: ListItemOptions
|
||||
private let largestPrefixWidth: CGFloat
|
||||
|
||||
private var baseStyle: NSMutableParagraphStyle {
|
||||
let style = NSMutableParagraphStyle()
|
||||
style.paragraphSpacingBefore = options.spacingAbove
|
||||
style.paragraphSpacing = options.spacingBelow
|
||||
style.alignment = options.alignment
|
||||
return style
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(options: ListItemOptions, prefixFont: DownFont) {
|
||||
self.options = options
|
||||
self.largestPrefixWidth = prefixFont.widthOfNumberedPrefix(digits: options.maxPrefixDigits)
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
/// The paragraph style intended for the first paragraph of the list item.
|
||||
///
|
||||
/// - Parameter prefixWidth: the width (in points) of the list item prefix.
|
||||
|
||||
public func leadingParagraphStyle(prefixWidth: CGFloat) -> NSParagraphStyle {
|
||||
let contentIndentation = indentation
|
||||
let prefixIndentation: CGFloat = contentIndentation - options.spacingAfterPrefix - prefixWidth
|
||||
let prefixSpill = max(0, prefixWidth - largestPrefixWidth)
|
||||
let firstLineContentIndentation = contentIndentation + prefixSpill
|
||||
|
||||
let style = baseStyle
|
||||
style.firstLineHeadIndent = prefixIndentation
|
||||
style.tabStops = [tabStop(at: firstLineContentIndentation)]
|
||||
style.headIndent = contentIndentation
|
||||
return style
|
||||
}
|
||||
|
||||
private func tabStop(at location: CGFloat) -> NSTextTab {
|
||||
return NSTextTab(textAlignment: options.alignment, location: location, options: [:])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private extension DownFont {
|
||||
|
||||
func widthOfNumberedPrefix(digits: UInt) -> CGFloat {
|
||||
return widthOfLargestDigit * CGFloat(digits) + widthOfPeriod
|
||||
}
|
||||
|
||||
private var widthOfLargestDigit: CGFloat {
|
||||
return Int.decimalDigits
|
||||
.map { NSAttributedString(string: "\($0)", attributes: [.font: self]).size().width }
|
||||
.max()!
|
||||
}
|
||||
|
||||
private var widthOfPeriod: CGFloat {
|
||||
return NSAttributedString(string: ".", attributes: [.font: self])
|
||||
.size()
|
||||
.width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension Int {
|
||||
|
||||
static var decimalDigits: [Int] {
|
||||
return Array(0...9)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// DownDebugLayoutManager.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 06.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
/// A layout manager that draws the line fragments.
|
||||
///
|
||||
/// Line fragments are the areas with a document that contain lines of text. There
|
||||
/// are two types.
|
||||
///
|
||||
/// 1. A *line rect* (drawn in red) indicates the maximum rect enclosing the line.
|
||||
/// This inlcudes not only the textual content, but also the padding (if any) around that text.
|
||||
/// 2. A *line used rect* (drawn in blue) is the smallest rect enclosing the textual content.
|
||||
///
|
||||
/// The visualization of these rects is useful when determining the paragraph styles
|
||||
/// of a `DownStyler`.
|
||||
///
|
||||
/// Insert this into a TextKit stack manually, or use the provided `DownDebugTextView`.
|
||||
|
||||
public class DownDebugLayoutManager: DownLayoutManager {
|
||||
|
||||
// MARK: - Drawing
|
||||
|
||||
override public func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
|
||||
super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
|
||||
drawLineFragments(forGlyphRange: glyphsToShow, at: origin)
|
||||
}
|
||||
|
||||
private func drawLineFragments(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
|
||||
enumerateLineFragments(forGlyphRange: glyphsToShow) { rect, usedRect, _, _, _ in
|
||||
[(usedRect, DownColor.blue), (rect, DownColor.red)].forEach { rectToDraw, color in
|
||||
let adjustedRect = rectToDraw.translated(by: origin)
|
||||
self.drawRect(adjustedRect, color: color.cgColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func drawRect(_ rect: CGRect, color: CGColor) {
|
||||
guard let context = context else { return }
|
||||
push(context: context)
|
||||
defer { popContext() }
|
||||
|
||||
context.setStrokeColor(color)
|
||||
context.stroke(rect)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,231 @@
|
||||
//
|
||||
// DownLayoutManager.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 02.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
/// A layout manager capable of drawing the custom attributes set by the `DownStyler`.
|
||||
///
|
||||
/// Insert this into a TextKit stack manually, or use the provided `DownTextView`.
|
||||
|
||||
public class DownLayoutManager: NSLayoutManager {
|
||||
|
||||
// MARK: - Graphic context
|
||||
|
||||
#if canImport(UIKit)
|
||||
var context: CGContext? {
|
||||
return UIGraphicsGetCurrentContext()
|
||||
}
|
||||
|
||||
func push(context: CGContext) {
|
||||
UIGraphicsPushContext(context)
|
||||
}
|
||||
|
||||
func popContext() {
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
var context: CGContext? {
|
||||
return NSGraphicsContext.current?.cgContext
|
||||
}
|
||||
|
||||
func push(context: CGContext) {
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
}
|
||||
|
||||
func popContext() {
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - Drawing
|
||||
|
||||
override public func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
|
||||
drawCustomBackgrounds(forGlyphRange: glyphsToShow, at: origin)
|
||||
super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
|
||||
drawCustomAttributes(forGlyphRange: glyphsToShow, at: origin)
|
||||
}
|
||||
|
||||
private func drawCustomBackgrounds(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
|
||||
guard let context = context else { return }
|
||||
push(context: context)
|
||||
defer { popContext() }
|
||||
|
||||
guard let textStorage = textStorage else { return }
|
||||
|
||||
let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
|
||||
|
||||
textStorage.enumerateAttributes(for: .blockBackgroundColor,
|
||||
in: characterRange) { (attr: BlockBackgroundColorAttribute, blockRange) in
|
||||
let inset = attr.inset
|
||||
|
||||
context.setFillColor(attr.color.cgColor)
|
||||
|
||||
let allBlockColorRanges = glyphRanges(for: .blockBackgroundColor,
|
||||
in: textStorage,
|
||||
inCharacterRange: blockRange)
|
||||
|
||||
let glyphRange = self.glyphRange(forCharacterRange: blockRange, actualCharacterRange: nil)
|
||||
|
||||
enumerateLineFragments(forGlyphRange: glyphRange) { lineRect, lineUsedRect, container, lineGlyphRange, _ in
|
||||
let isLineStartOfBlock = allBlockColorRanges.contains {
|
||||
lineGlyphRange.overlapsStart(of: $0)
|
||||
}
|
||||
|
||||
let isLineEndOfBlock = allBlockColorRanges.contains {
|
||||
lineGlyphRange.overlapsEnd(of: $0)
|
||||
}
|
||||
|
||||
let minX = lineUsedRect.minX + container.lineFragmentPadding - inset
|
||||
let maxX = lineRect.maxX
|
||||
let minY = isLineStartOfBlock ? lineUsedRect.minY - inset : lineRect.minY
|
||||
let maxY = isLineEndOfBlock ? lineUsedRect.maxY + inset : lineUsedRect.maxY
|
||||
let blockRect = CGRect(minX: minX, minY: minY, maxX: maxX, maxY: maxY).translated(by: origin)
|
||||
|
||||
context.fill(blockRect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func drawCustomAttributes(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
|
||||
let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
|
||||
drawThematicBreakIfNeeded(in: characterRange, at: origin)
|
||||
drawQuoteStripeIfNeeded(in: characterRange, at: origin)
|
||||
}
|
||||
|
||||
private func drawThematicBreakIfNeeded(in characterRange: NSRange, at origin: CGPoint) {
|
||||
guard let context = context else { return }
|
||||
push(context: context)
|
||||
defer { popContext() }
|
||||
|
||||
textStorage?.enumerateAttributes(for: .thematicBreak,
|
||||
in: characterRange) { (attr: ThematicBreakAttribute, range) in
|
||||
|
||||
let firstGlyphIndex = glyphIndexForCharacter(at: range.lowerBound)
|
||||
|
||||
let lineRect = lineFragmentRect(forGlyphAt: firstGlyphIndex, effectiveRange: nil)
|
||||
let usedRect = lineFragmentUsedRect(forGlyphAt: firstGlyphIndex, effectiveRange: nil)
|
||||
|
||||
let lineStart = usedRect.minX + fragmentPadding(forGlyphAt: firstGlyphIndex)
|
||||
|
||||
let width = lineRect.width - lineStart
|
||||
let height = lineRect.height
|
||||
|
||||
let boundingRect = CGRect(x: lineStart, y: lineRect.minY, width: width, height: height)
|
||||
let adjustedLineRect = boundingRect.translated(by: origin)
|
||||
|
||||
drawThematicBreak(with: context, in: adjustedLineRect, attr: attr)
|
||||
}
|
||||
}
|
||||
|
||||
private func fragmentPadding(forGlyphAt glyphIndex: Int) -> CGFloat {
|
||||
let textContainer = self.textContainer(forGlyphAt: glyphIndex, effectiveRange: nil)
|
||||
return textContainer?.lineFragmentPadding ?? 0
|
||||
}
|
||||
|
||||
private func drawThematicBreak(with context: CGContext, in rect: CGRect, attr: ThematicBreakAttribute) {
|
||||
context.setStrokeColor(attr.color.cgColor)
|
||||
context.setLineWidth(attr.thickness)
|
||||
context.move(to: CGPoint(x: rect.minX, y: rect.midY))
|
||||
context.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
|
||||
context.strokePath()
|
||||
}
|
||||
|
||||
private func drawQuoteStripeIfNeeded(in characterRange: NSRange, at origin: CGPoint) {
|
||||
guard let context = context else { return }
|
||||
push(context: context)
|
||||
defer { popContext() }
|
||||
|
||||
textStorage?.enumerateAttributes(for: .quoteStripe,
|
||||
in: characterRange) { (attr: QuoteStripeAttribute, quoteRange) in
|
||||
|
||||
context.setFillColor(attr.color.cgColor)
|
||||
|
||||
let glyphRangeOfQuote = self.glyphRange(forCharacterRange: quoteRange, actualCharacterRange: nil)
|
||||
|
||||
enumerateLineFragments(forGlyphRange: glyphRangeOfQuote) { lineRect, _, container, _, _ in
|
||||
let locations = attr.locations.map {
|
||||
CGPoint(x: $0 + container.lineFragmentPadding, y: 0)
|
||||
.translated(by: lineRect.origin)
|
||||
.translated(by: origin)
|
||||
}
|
||||
|
||||
let stripeSize = CGSize(width: attr.thickness, height: lineRect.height)
|
||||
self.drawQuoteStripes(with: context, locations: locations, size: stripeSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func drawQuoteStripes(with context: CGContext, locations: [CGPoint], size: CGSize) {
|
||||
locations.forEach {
|
||||
let stripeRect = CGRect(origin: $0, size: size)
|
||||
context.fill(stripeRect)
|
||||
}
|
||||
}
|
||||
|
||||
private func glyphRanges(for key: NSAttributedString.Key,
|
||||
in storage: NSTextStorage,
|
||||
inCharacterRange range: NSRange) -> [NSRange] {
|
||||
|
||||
return storage
|
||||
.ranges(of: key, in: range)
|
||||
.map { self.glyphRange(forCharacterRange: $0, actualCharacterRange: nil) }
|
||||
.mergeNeighbors()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private extension NSRange {
|
||||
|
||||
func overlapsStart(of range: NSRange) -> Bool {
|
||||
return lowerBound <= range.lowerBound && upperBound > range.lowerBound
|
||||
}
|
||||
|
||||
func overlapsEnd(of range: NSRange) -> Bool {
|
||||
return lowerBound < range.upperBound && upperBound >= range.upperBound
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension Array where Element == NSRange {
|
||||
|
||||
func mergeNeighbors() -> [Element] {
|
||||
let sorted = self.sorted { $0.lowerBound <= $1.lowerBound }
|
||||
|
||||
let result = sorted.reduce(into: [NSRange]()) { acc, next in
|
||||
guard let last = acc.popLast() else {
|
||||
acc.append(next)
|
||||
return
|
||||
}
|
||||
|
||||
guard last.upperBound == next.lowerBound else {
|
||||
acc.append(contentsOf: [last, next])
|
||||
return
|
||||
}
|
||||
|
||||
acc.append(NSRange(location: last.lowerBound, length: next.upperBound - last.lowerBound))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// CodeBlockOptions.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 12.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
public struct CodeBlockOptions {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var containerInset: CGFloat
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(containerInset: CGFloat = 8) {
|
||||
self.containerInset = containerInset
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// ListItemOptions.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 04.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
public struct ListItemOptions {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var maxPrefixDigits: UInt
|
||||
public var spacingAfterPrefix: CGFloat
|
||||
public var spacingAbove: CGFloat
|
||||
public var spacingBelow: CGFloat
|
||||
public var alignment: NSTextAlignment
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(maxPrefixDigits: UInt = 2,
|
||||
spacingAfterPrefix: CGFloat = 8,
|
||||
spacingAbove: CGFloat = 4,
|
||||
spacingBelow: CGFloat = 8,
|
||||
alignment: NSTextAlignment = .natural) {
|
||||
|
||||
self.maxPrefixDigits = maxPrefixDigits
|
||||
self.spacingAfterPrefix = spacingAfterPrefix
|
||||
self.spacingAbove = spacingAbove
|
||||
self.spacingBelow = spacingBelow
|
||||
self.alignment = alignment
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// QuoteStripeOptions.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 04.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
public struct QuoteStripeOptions {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var thickness: CGFloat
|
||||
public var spacingAfter: CGFloat
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(thickness: CGFloat = 2, spacingAfter: CGFloat = 8) {
|
||||
self.thickness = thickness
|
||||
self.spacingAfter = spacingAfter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// ThematicBreakOptions.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 04.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
public struct ThematicBreakOptions {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var thickness: CGFloat
|
||||
public var indentation: CGFloat
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(thickness: CGFloat = 1, indentation: CGFloat = 0) {
|
||||
self.thickness = thickness
|
||||
self.indentation = indentation
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,308 @@
|
||||
//
|
||||
// DownStyler.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 22.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
/// A default `Styler` implementation that supports a variety of configurable
|
||||
/// properties for font, text color and paragraph styling, as well as formatting
|
||||
/// of nested lists and quotes.
|
||||
|
||||
open class DownStyler: Styler {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public let fonts: FontCollection
|
||||
public let colors: ColorCollection
|
||||
public let paragraphStyles: ParagraphStyleCollection
|
||||
|
||||
public let quoteStripeOptions: QuoteStripeOptions
|
||||
public let thematicBreakOptions: ThematicBreakOptions
|
||||
public let codeBlockOptions: CodeBlockOptions
|
||||
|
||||
private let itemParagraphStyler: ListItemParagraphStyler
|
||||
|
||||
private var listPrefixAttributes: [NSAttributedString.Key: Any] {[
|
||||
.font: fonts.listItemPrefix,
|
||||
.foregroundColor: colors.listItemPrefix]
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(configuration: DownStylerConfiguration = DownStylerConfiguration()) {
|
||||
fonts = configuration.fonts
|
||||
colors = configuration.colors
|
||||
paragraphStyles = configuration.paragraphStyles
|
||||
quoteStripeOptions = configuration.quoteStripeOptions
|
||||
thematicBreakOptions = configuration.thematicBreakOptions
|
||||
codeBlockOptions = configuration.codeBlockOptions
|
||||
itemParagraphStyler = ListItemParagraphStyler(options: configuration.listItemOptions,
|
||||
prefixFont: fonts.listItemPrefix)
|
||||
}
|
||||
|
||||
// MARK: - Styling
|
||||
|
||||
open func style(document str: NSMutableAttributedString) {
|
||||
|
||||
}
|
||||
|
||||
open func style(blockQuote str: NSMutableAttributedString, nestDepth: Int) {
|
||||
let stripeAttribute = QuoteStripeAttribute(level: nestDepth + 1,
|
||||
color: colors.quoteStripe,
|
||||
options: quoteStripeOptions)
|
||||
|
||||
str.updateExistingAttributes(for: .paragraphStyle) { (style: NSParagraphStyle) in
|
||||
style.indented(by: stripeAttribute.layoutWidth)
|
||||
}
|
||||
|
||||
str.addAttributeInMissingRanges(for: .quoteStripe, value: stripeAttribute)
|
||||
str.addAttribute(for: .foregroundColor, value: colors.quote)
|
||||
}
|
||||
|
||||
open func style(list str: NSMutableAttributedString, nestDepth: Int) {
|
||||
|
||||
}
|
||||
|
||||
open func style(listItemPrefix str: NSMutableAttributedString) {
|
||||
str.setAttributes(listPrefixAttributes)
|
||||
}
|
||||
|
||||
open func style(item str: NSMutableAttributedString, prefixLength: Int) {
|
||||
let paragraphRanges = str.paragraphRanges()
|
||||
|
||||
guard let leadingParagraphRange = paragraphRanges.first else { return }
|
||||
|
||||
indentListItemLeadingParagraph(in: str, prefixLength: prefixLength, in: leadingParagraphRange)
|
||||
|
||||
paragraphRanges.dropFirst().forEach {
|
||||
indentListItemTrailingParagraph(in: str, inRange: $0)
|
||||
}
|
||||
}
|
||||
|
||||
open func style(codeBlock str: NSMutableAttributedString, fenceInfo: String?) {
|
||||
styleGenericCodeBlock(in: str)
|
||||
}
|
||||
|
||||
open func style(htmlBlock str: NSMutableAttributedString) {
|
||||
styleGenericCodeBlock(in: str)
|
||||
}
|
||||
|
||||
open func style(customBlock str: NSMutableAttributedString) {
|
||||
|
||||
}
|
||||
|
||||
open func style(paragraph str: NSMutableAttributedString) {
|
||||
str.addAttribute(for: .paragraphStyle, value: paragraphStyles.body)
|
||||
}
|
||||
|
||||
open func style(heading str: NSMutableAttributedString, level: Int) {
|
||||
let (font, color, paragraphStyle) = headingAttributes(for: level)
|
||||
|
||||
str.updateExistingAttributes(for: .font) { (currentFont: DownFont) in
|
||||
var newFont = font
|
||||
|
||||
if currentFont.isMonospace {
|
||||
newFont = newFont.monospace
|
||||
}
|
||||
|
||||
if currentFont.isEmphasized {
|
||||
newFont = newFont.emphasis
|
||||
}
|
||||
|
||||
if currentFont.isStrong {
|
||||
newFont = newFont.strong
|
||||
}
|
||||
|
||||
return newFont
|
||||
}
|
||||
|
||||
str.addAttributes([
|
||||
.foregroundColor: color,
|
||||
.paragraphStyle: paragraphStyle])
|
||||
}
|
||||
|
||||
open func style(thematicBreak str: NSMutableAttributedString) {
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.firstLineHeadIndent = thematicBreakOptions.indentation
|
||||
let attr = ThematicBreakAttribute(thickness: thematicBreakOptions.thickness, color: colors.thematicBreak)
|
||||
str.addAttribute(for: .thematicBreak, value: attr)
|
||||
str.addAttribute(for: .paragraphStyle, value: paragraphStyle)
|
||||
}
|
||||
|
||||
open func style(text str: NSMutableAttributedString) {
|
||||
str.setAttributes([
|
||||
.font: fonts.body,
|
||||
.foregroundColor: colors.body])
|
||||
}
|
||||
|
||||
open func style(softBreak str: NSMutableAttributedString) {
|
||||
|
||||
}
|
||||
|
||||
open func style(lineBreak str: NSMutableAttributedString) {
|
||||
|
||||
}
|
||||
|
||||
open func style(code str: NSMutableAttributedString) {
|
||||
styleGenericInlineCode(in: str)
|
||||
}
|
||||
|
||||
open func style(htmlInline str: NSMutableAttributedString) {
|
||||
styleGenericInlineCode(in: str)
|
||||
}
|
||||
|
||||
open func style(customInline str: NSMutableAttributedString) {
|
||||
|
||||
}
|
||||
|
||||
open func style(emphasis str: NSMutableAttributedString) {
|
||||
str.updateExistingAttributes(for: .font) { (font: DownFont) in
|
||||
font.emphasis
|
||||
}
|
||||
}
|
||||
|
||||
open func style(strong str: NSMutableAttributedString) {
|
||||
str.updateExistingAttributes(for: .font) { (font: DownFont) in
|
||||
font.strong
|
||||
}
|
||||
}
|
||||
|
||||
open func style(link str: NSMutableAttributedString, title: String?, url: String?) {
|
||||
guard let url = url else { return }
|
||||
styleGenericLink(in: str, url: url)
|
||||
}
|
||||
|
||||
open func style(image str: NSMutableAttributedString, title: String?, url: String?) {
|
||||
guard let url = url else { return }
|
||||
styleGenericLink(in: str, url: url)
|
||||
}
|
||||
|
||||
// MARK: - Common Styling
|
||||
|
||||
private func styleGenericCodeBlock(in str: NSMutableAttributedString) {
|
||||
let blockBackgroundAttribute = BlockBackgroundColorAttribute(
|
||||
color: colors.codeBlockBackground,
|
||||
inset: codeBlockOptions.containerInset)
|
||||
|
||||
let adjustedParagraphStyle = paragraphStyles.code.inset(by: blockBackgroundAttribute.inset)
|
||||
|
||||
str.setAttributes([
|
||||
.font: fonts.code,
|
||||
.foregroundColor: colors.code,
|
||||
.paragraphStyle: adjustedParagraphStyle,
|
||||
.blockBackgroundColor: blockBackgroundAttribute])
|
||||
}
|
||||
|
||||
private func styleGenericInlineCode(in str: NSMutableAttributedString) {
|
||||
str.setAttributes([
|
||||
.font: fonts.code,
|
||||
.foregroundColor: colors.code])
|
||||
}
|
||||
|
||||
private func styleGenericLink(in str: NSMutableAttributedString, url: String) {
|
||||
str.addAttributes([
|
||||
.link: url,
|
||||
.foregroundColor: colors.link])
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func headingAttributes(for level: Int) -> (DownFont, DownColor, NSParagraphStyle) {
|
||||
switch level {
|
||||
case 1: return (fonts.heading1, colors.heading1, paragraphStyles.heading1)
|
||||
case 2: return (fonts.heading2, colors.heading2, paragraphStyles.heading2)
|
||||
case 3: return (fonts.heading3, colors.heading3, paragraphStyles.heading3)
|
||||
case 4: return (fonts.heading4, colors.heading4, paragraphStyles.heading4)
|
||||
case 5: return (fonts.heading5, colors.heading5, paragraphStyles.heading5)
|
||||
case 6: return (fonts.heading6, colors.heading6, paragraphStyles.heading6)
|
||||
default: return (fonts.heading1, colors.heading1, paragraphStyles.heading1)
|
||||
}
|
||||
}
|
||||
|
||||
private func indentListItemLeadingParagraph(in str: NSMutableAttributedString,
|
||||
prefixLength: Int,
|
||||
in range: NSRange) {
|
||||
|
||||
str.updateExistingAttributes(for: .paragraphStyle, in: range) { (existingStyle: NSParagraphStyle) in
|
||||
existingStyle.indented(by: itemParagraphStyler.indentation)
|
||||
}
|
||||
|
||||
let attributedPrefix = str.prefix(with: prefixLength)
|
||||
let prefixWidth = attributedPrefix.size().width
|
||||
|
||||
let defaultStyle = itemParagraphStyler.leadingParagraphStyle(prefixWidth: prefixWidth)
|
||||
str.addAttributeInMissingRanges(for: .paragraphStyle, value: defaultStyle, within: range)
|
||||
}
|
||||
|
||||
private func indentListItemTrailingParagraph(in str: NSMutableAttributedString, inRange range: NSRange) {
|
||||
str.updateExistingAttributes(for: .paragraphStyle, in: range) { (existingStyle: NSParagraphStyle) in
|
||||
existingStyle.indented(by: itemParagraphStyler.indentation)
|
||||
}
|
||||
|
||||
let defaultStyle = itemParagraphStyler.trailingParagraphStyle
|
||||
str.addAttributeInMissingRanges(for: .paragraphStyle, value: defaultStyle, within: range)
|
||||
|
||||
indentListItemQuotes(in: str, inRange: range)
|
||||
}
|
||||
|
||||
private func indentListItemQuotes(in str: NSMutableAttributedString, inRange range: NSRange) {
|
||||
str.updateExistingAttributes(for: .quoteStripe, in: range) { (stripe: QuoteStripeAttribute) in
|
||||
stripe.indented(by: itemParagraphStyler.indentation)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helper Extensions
|
||||
|
||||
private extension NSParagraphStyle {
|
||||
|
||||
func indented(by indentation: CGFloat) -> NSParagraphStyle {
|
||||
guard let result = mutableCopy() as? NSMutableParagraphStyle else { return self }
|
||||
result.firstLineHeadIndent += indentation
|
||||
result.headIndent += indentation
|
||||
|
||||
result.tabStops = tabStops.map {
|
||||
NSTextTab(textAlignment: $0.alignment, location: $0.location + indentation, options: $0.options)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func inset(by amount: CGFloat) -> NSParagraphStyle {
|
||||
guard let result = mutableCopy() as? NSMutableParagraphStyle else { return self }
|
||||
result.paragraphSpacingBefore += amount
|
||||
result.paragraphSpacing += amount
|
||||
result.firstLineHeadIndent += amount
|
||||
result.headIndent += amount
|
||||
result.tailIndent = -amount
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension NSAttributedString {
|
||||
|
||||
func prefix(with length: Int) -> NSAttributedString {
|
||||
guard length <= self.length else { return self }
|
||||
guard length > 0 else { return NSAttributedString() }
|
||||
return attributedSubstring(from: NSRange(location: 0, length: length))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// DownStylerConfiguration.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 10.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
/// A configuration object used to initialze the `DownStyler`.
|
||||
|
||||
public struct DownStylerConfiguration {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public var fonts: FontCollection
|
||||
public var colors: ColorCollection
|
||||
public var paragraphStyles: ParagraphStyleCollection
|
||||
|
||||
public var listItemOptions: ListItemOptions
|
||||
public var quoteStripeOptions: QuoteStripeOptions
|
||||
public var thematicBreakOptions: ThematicBreakOptions
|
||||
public var codeBlockOptions: CodeBlockOptions
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(fonts: FontCollection = StaticFontCollection(),
|
||||
colors: ColorCollection = StaticColorCollection(),
|
||||
paragraphStyles: ParagraphStyleCollection = StaticParagraphStyleCollection(),
|
||||
listItemOptions: ListItemOptions = ListItemOptions(),
|
||||
quoteStripeOptions: QuoteStripeOptions = QuoteStripeOptions(),
|
||||
thematicBreakOptions: ThematicBreakOptions = ThematicBreakOptions(),
|
||||
codeBlockOptions: CodeBlockOptions = CodeBlockOptions()
|
||||
) {
|
||||
self.fonts = fonts
|
||||
self.colors = colors
|
||||
self.paragraphStyles = paragraphStyles
|
||||
self.listItemOptions = listItemOptions
|
||||
self.quoteStripeOptions = quoteStripeOptions
|
||||
self.thematicBreakOptions = thematicBreakOptions
|
||||
self.codeBlockOptions = codeBlockOptions
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Styler.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 13.04.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A styler is an object that manipulates the appearance of attributed strings generated
|
||||
/// for each particular markdown node. The attributed string passed into each method is
|
||||
/// mutable, so new attributes can be added and/or existing attributes modified or removed.
|
||||
///
|
||||
/// When applying paragraph styles to a string, take care not to cause any conflicts with
|
||||
/// existing paragraph styles, as this can lead to visual bugs that are difficult to
|
||||
/// understand.
|
||||
///
|
||||
/// A styler is used in conjunction with an instance of `AttributedStringVisitor` in order
|
||||
/// to generate an NSAttributedString from an abstract syntax tree.
|
||||
|
||||
public protocol Styler {
|
||||
|
||||
/// Styles the content of the document in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the document content.
|
||||
|
||||
func style(document str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the block quote contained in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the quote content.
|
||||
/// - nestDepth: the zero indexed nesting depth of the block quote node.
|
||||
|
||||
func style(blockQuote str: NSMutableAttributedString, nestDepth: Int)
|
||||
|
||||
/// Styles the content of the list contained in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the list content.
|
||||
/// - nestDepth: the zero indexed nesting depth of the list node.
|
||||
|
||||
func style(list str: NSMutableAttributedString, nestDepth: Int)
|
||||
|
||||
/// Styles the number or bullet list item prefix.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the list item prefix.
|
||||
|
||||
func style(listItemPrefix str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the list item contained in the given string, including the
|
||||
/// number or bullet prefix.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the item content.
|
||||
/// - prefixLength: the character length of the number or bullet prefix.
|
||||
|
||||
func style(item str: NSMutableAttributedString, prefixLength: Int)
|
||||
|
||||
/// Styles the content of the code block in the given string.
|
||||
///
|
||||
/// An example use case for `fenceInfo` is to specify a programming language name,
|
||||
/// which could be used to support syntax highlighting.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the code content.
|
||||
/// - fenceInfo: the string that trails the initial \`\`\` ticks.
|
||||
|
||||
func style(codeBlock str: NSMutableAttributedString, fenceInfo: String?)
|
||||
|
||||
/// Styles the content of the html block contained in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the html content.
|
||||
|
||||
func style(htmlBlock str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the custom block contained in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the content.
|
||||
|
||||
func style(customBlock str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the paragraph in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the paragraph content.
|
||||
|
||||
func style(paragraph str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the heading in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the heading content.
|
||||
/// - level: the heading level [1, 6]
|
||||
|
||||
func style(heading str: NSMutableAttributedString, level: Int)
|
||||
|
||||
/// Styles the content of the thematic break in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the thematic break.
|
||||
|
||||
func style(thematicBreak str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline text node in the given string.
|
||||
///
|
||||
/// The text nodes are always the leaves of the AST, thus they
|
||||
/// contain the base style upon which other nodes can work with.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the text content.
|
||||
|
||||
func style(text str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the soft break in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the soft break.
|
||||
|
||||
func style(softBreak str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the line break in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the line break.
|
||||
|
||||
func style(lineBreak str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline code in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the code content.
|
||||
|
||||
func style(code str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline html tags in the given string.
|
||||
///
|
||||
/// Note, the content does not include text between matching tags.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the html content.
|
||||
|
||||
func style(htmlInline str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline custom node in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the custom content.
|
||||
|
||||
func style(customInline str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline emphasis node in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the ephasized content.
|
||||
|
||||
func style(emphasis str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline strong node in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the strong content.
|
||||
|
||||
func style(strong str: NSMutableAttributedString)
|
||||
|
||||
/// Styles the content of the inline link node in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the link content.
|
||||
/// - title: the link title.
|
||||
/// - url: the linked url.
|
||||
|
||||
func style(link str: NSMutableAttributedString, title: String?, url: String?)
|
||||
|
||||
/// Styles the content of the inline image node in the given string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - str: the link content.
|
||||
/// - title: the link title.
|
||||
/// - url: the linked url.
|
||||
|
||||
func style(image str: NSMutableAttributedString, title: String?, url: String?)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// DownDebugTextView.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 06.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
/// A text view capable of parsing and rendering markdown via the AST, as well as line fragments.
|
||||
///
|
||||
/// See `DownDebugLayoutManager`.
|
||||
|
||||
public class DownDebugTextView: DownTextView {
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(frame: CGRect, styler: Styler = DownStyler()) {
|
||||
super.init(frame: frame, styler: styler, layoutManager: DownDebugLayoutManager())
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// DownTextView.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 03.08.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(watchOS) && !os(Linux)
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
public typealias TextView = UITextView
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
import AppKit
|
||||
public typealias TextView = NSTextView
|
||||
|
||||
#endif
|
||||
|
||||
/// A text view capable of parsing and rendering markdown via the AST.
|
||||
|
||||
open class DownTextView: TextView {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
open var styler: Styler {
|
||||
didSet {
|
||||
try? render()
|
||||
}
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
open override var text: String! {
|
||||
didSet {
|
||||
guard oldValue != text else { return }
|
||||
try? render()
|
||||
}
|
||||
}
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
|
||||
open override var string: String {
|
||||
didSet {
|
||||
guard oldValue != string else { return }
|
||||
try? render()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public convenience init(frame: CGRect, styler: Styler = DownStyler()) {
|
||||
self.init(frame: frame, styler: styler, layoutManager: DownLayoutManager())
|
||||
}
|
||||
|
||||
public init(frame: CGRect, styler: Styler, layoutManager: NSLayoutManager) {
|
||||
self.styler = styler
|
||||
|
||||
let textStorage = NSTextStorage()
|
||||
let textContainer = NSTextContainer()
|
||||
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
layoutManager.addTextContainer(textContainer)
|
||||
|
||||
super.init(frame: frame, textContainer: textContainer)
|
||||
|
||||
// We don't want the text view to overwrite link attributes set
|
||||
// by the styler.
|
||||
linkTextAttributes = [:]
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
open func render() throws {
|
||||
#if canImport(UIKit)
|
||||
let down = Down(markdownString: text)
|
||||
let markdown = try down.toAttributedString(styler: styler)
|
||||
attributedText = markdown
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
guard let textStorage = textStorage else { return }
|
||||
let down = Down(markdownString: string)
|
||||
let markdown = try down.toAttributedString(styler: styler)
|
||||
textStorage.replaceCharacters(in: textStorage.wholeRange, with: markdown)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,249 @@
|
||||
//
|
||||
// AttributedStringVisitor.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import Foundation
|
||||
|
||||
/// This class is used to generated an `NSMutableAttributedString` from the abstract syntax
|
||||
/// tree produced by a markdown string. It traverses the tree to construct substrings
|
||||
/// represented at each node and uses an instance of `Styler` to apply the visual attributes.
|
||||
/// These substrings are joined together to produce the final result.
|
||||
|
||||
public typealias ListPrefixGeneratorBuilder = (List) -> ListItemPrefixGenerator
|
||||
|
||||
public class AttributedStringVisitor {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
private let styler: Styler
|
||||
private let options: DownOptions
|
||||
private let listPrefixGeneratorBuilder: ListPrefixGeneratorBuilder
|
||||
private var listPrefixGenerators = [ListItemPrefixGenerator]()
|
||||
|
||||
/// Creates a new instance with the given styler and options.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - styler: used to style the markdown elements.
|
||||
/// - options: may be used to modify rendering.
|
||||
/// - listPrefixGeneratorBuilder: may be used to modify list prefixes.
|
||||
|
||||
public init(
|
||||
styler: Styler,
|
||||
options: DownOptions = .default,
|
||||
listPrefixGeneratorBuilder: @escaping ListPrefixGeneratorBuilder = { StaticListItemPrefixGenerator(list: $0) }
|
||||
) {
|
||||
self.styler = styler
|
||||
self.options = options
|
||||
self.listPrefixGeneratorBuilder = listPrefixGeneratorBuilder
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension AttributedStringVisitor: Visitor {
|
||||
|
||||
public typealias Result = NSMutableAttributedString
|
||||
|
||||
public func visit(document node: Document) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
styler.style(document: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(blockQuote node: BlockQuote) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(blockQuote: result, nestDepth: node.nestDepth)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(list node: List) -> NSMutableAttributedString {
|
||||
|
||||
listPrefixGenerators.append(listPrefixGeneratorBuilder(node))
|
||||
defer { listPrefixGenerators.removeLast() }
|
||||
|
||||
let items = visitChildren(of: node)
|
||||
|
||||
let result = items.joined
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(list: result, nestDepth: node.nestDepth)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(item node: Item) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
|
||||
let prefix = listPrefixGenerators.last?.next() ?? "•"
|
||||
let attributedPrefix = "\(prefix)\t".attributed
|
||||
styler.style(listItemPrefix: attributedPrefix)
|
||||
result.insert(attributedPrefix, at: 0)
|
||||
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(item: result, prefixLength: (prefix as NSString).length)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(codeBlock node: CodeBlock) -> NSMutableAttributedString {
|
||||
guard let literal = node.literal else { return .empty }
|
||||
let result = literal.replacingNewlinesWithLineSeparators().attributed
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(codeBlock: result, fenceInfo: node.fenceInfo)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(htmlBlock node: HtmlBlock) -> NSMutableAttributedString {
|
||||
guard let literal = node.literal else { return .empty }
|
||||
let result = literal.replacingNewlinesWithLineSeparators().attributed
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(htmlBlock: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(customBlock node: CustomBlock) -> NSMutableAttributedString {
|
||||
guard let result = node.literal?.attributed else { return .empty }
|
||||
styler.style(customBlock: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(paragraph node: Paragraph) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(paragraph: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(heading node: Heading) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
if node.hasSuccessor { result.append(.paragraphSeparator) }
|
||||
styler.style(heading: result, level: node.headingLevel)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(thematicBreak node: ThematicBreak) -> NSMutableAttributedString {
|
||||
let result = "\(String.zeroWidthSpace)\n".attributed
|
||||
styler.style(thematicBreak: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(text node: Text) -> NSMutableAttributedString {
|
||||
guard let result = node.literal?.attributed else { return .empty }
|
||||
styler.style(text: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(softBreak node: SoftBreak) -> NSMutableAttributedString {
|
||||
let result = (options.contains(.hardBreaks) ? String.lineSeparator : " ").attributed
|
||||
styler.style(softBreak: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(lineBreak node: LineBreak) -> NSMutableAttributedString {
|
||||
let result = String.lineSeparator.attributed
|
||||
styler.style(lineBreak: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(code node: Code) -> NSMutableAttributedString {
|
||||
guard let result = node.literal?.attributed else { return .empty }
|
||||
styler.style(code: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(htmlInline node: HtmlInline) -> NSMutableAttributedString {
|
||||
guard let result = node.literal?.attributed else { return .empty }
|
||||
styler.style(htmlInline: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(customInline node: CustomInline) -> NSMutableAttributedString {
|
||||
guard let result = node.literal?.attributed else { return .empty }
|
||||
styler.style(customInline: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(emphasis node: Emphasis) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
styler.style(emphasis: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(strong node: Strong) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
styler.style(strong: result)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(link node: Link) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
styler.style(link: result, title: node.title, url: node.url)
|
||||
return result
|
||||
}
|
||||
|
||||
public func visit(image node: Image) -> NSMutableAttributedString {
|
||||
let result = visitChildren(of: node).joined
|
||||
styler.style(image: result, title: node.title, url: node.url)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper extensions
|
||||
|
||||
private extension Sequence where Iterator.Element == NSMutableAttributedString {
|
||||
|
||||
var joined: NSMutableAttributedString {
|
||||
return reduce(into: NSMutableAttributedString()) { $0.append($1) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension NSMutableAttributedString {
|
||||
|
||||
static var empty: NSMutableAttributedString {
|
||||
return "".attributed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension NSAttributedString {
|
||||
|
||||
static var paragraphSeparator: NSAttributedString {
|
||||
return String.paragraphSeparator.attributed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension String {
|
||||
|
||||
var attributed: NSMutableAttributedString {
|
||||
return NSMutableAttributedString(string: self)
|
||||
}
|
||||
|
||||
// This codepoint marks the end of a paragraph and the start of the next.
|
||||
|
||||
static var paragraphSeparator: String {
|
||||
return "\u{2029}"
|
||||
}
|
||||
|
||||
// This code point allows line breaking, without starting a new paragraph.
|
||||
|
||||
static var lineSeparator: String {
|
||||
return "\u{2028}"
|
||||
}
|
||||
|
||||
static var zeroWidthSpace: String {
|
||||
return "\u{200B}"
|
||||
}
|
||||
|
||||
func replacingNewlinesWithLineSeparators() -> String {
|
||||
let trimmed = trimmingCharacters(in: .newlines)
|
||||
let lines = trimmed.components(separatedBy: .newlines)
|
||||
return lines.joined(separator: .lineSeparator)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !os(Linux)
|
||||
+37
-31
@@ -9,22 +9,27 @@ import Foundation
|
||||
|
||||
/// This visitor will generate the debug description of an entire abstract syntax tree,
|
||||
/// indicating relationships between nodes with indentation.
|
||||
public class DebugVisitor {
|
||||
|
||||
/// Current depth in the tree.
|
||||
|
||||
public class DebugVisitor: Visitor {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
private var depth = 0
|
||||
|
||||
/// The amount of indent for the current depth.
|
||||
|
||||
private var indent: String {
|
||||
return String(repeating: " ", count: depth)
|
||||
}
|
||||
|
||||
/// Debug representation of node.
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init() {}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func report(_ node: Node) -> String {
|
||||
return "\(indent)\(node is Document ? "" : "↳ ")\(String(reflecting: node))\n"
|
||||
}
|
||||
|
||||
/// Debug representation of node including all children.
|
||||
|
||||
private func reportWithChildren(_ node: Node) -> String {
|
||||
let thisNode = report(node)
|
||||
depth += 1
|
||||
@@ -32,88 +37,89 @@ public class DebugVisitor {
|
||||
depth -= 1
|
||||
return "\(thisNode)\(children)"
|
||||
}
|
||||
}
|
||||
|
||||
extension DebugVisitor: Visitor {
|
||||
// MARK: - Visitor
|
||||
|
||||
public typealias Result = String
|
||||
|
||||
|
||||
public func visit(document node: Document) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(blockQuote node: BlockQuote) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(list node: List) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(item node: Item) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(codeBlock node: CodeBlock) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(htmlBlock node: HtmlBlock) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(customBlock node: CustomBlock) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(paragraph node: Paragraph) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(heading node: Heading) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(thematicBreak node: ThematicBreak) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(text node: Text) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(softBreak node: SoftBreak) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(lineBreak node: LineBreak) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(code node: Code) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(htmlInline node: HtmlInline) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(customInline node: CustomInline) -> String {
|
||||
return report(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(emphasis node: Emphasis) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(strong node: Strong) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(link node: Link) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
|
||||
public func visit(image node: Image) -> String {
|
||||
return reportWithChildren(node)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// ListItemPrefixGenerator.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 23.06.19.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A ListItemPrefixGenerator is an object used to generate list item prefix.
|
||||
public protocol ListItemPrefixGenerator {
|
||||
init(listType: List.ListType, numberOfItems: Int, nestDepth: Int)
|
||||
func next() -> String?
|
||||
}
|
||||
|
||||
public extension ListItemPrefixGenerator {
|
||||
init(list: List) {
|
||||
self.init(listType: list.listType, numberOfItems: list.numberOfItems, nestDepth: list.nestDepth)
|
||||
}
|
||||
}
|
||||
|
||||
/// Default implementation of `ListItemPrefixGenerator`.
|
||||
/// Generating the following symbol based on `List.ListType`:
|
||||
/// - List.ListType is bullet => "•"
|
||||
/// - List.ListType is ordered => "X." (where is the item number)
|
||||
public class StaticListItemPrefixGenerator: ListItemPrefixGenerator {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
private var prefixes: IndexingIterator<[String]>
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
required public init(listType: List.ListType, numberOfItems: Int, nestDepth: Int) {
|
||||
switch listType {
|
||||
case .bullet:
|
||||
prefixes = [String](repeating: "•", count: numberOfItems)
|
||||
.makeIterator()
|
||||
|
||||
case .ordered(let start):
|
||||
prefixes = (start..<(start + numberOfItems))
|
||||
.map { "\($0)." }
|
||||
.makeIterator()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
public func next() -> String? {
|
||||
prefixes.next()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,8 +11,11 @@ import Foundation
|
||||
/// each node of the tree and produces some result for that node. A visitor is "accepted" by
|
||||
/// the root node (of type `Document`), which will start the traversal by first invoking
|
||||
/// `visit(document:)`.
|
||||
|
||||
public protocol Visitor {
|
||||
|
||||
associatedtype Result
|
||||
|
||||
func visit(document node: Document) -> Result
|
||||
func visit(blockQuote node: BlockQuote) -> Result
|
||||
func visit(list node: List) -> Result
|
||||
@@ -34,36 +37,39 @@ public protocol Visitor {
|
||||
func visit(link node: Link) -> Result
|
||||
func visit(image node: Image) -> Result
|
||||
func visitChildren(of node: Node) -> [Result]
|
||||
|
||||
}
|
||||
|
||||
extension Visitor {
|
||||
|
||||
public func visitChildren(of node: Node) -> [Result] {
|
||||
return node.children.compactMap { child in
|
||||
return node.childSequence.compactMap { child in
|
||||
switch child {
|
||||
case is Document: return visit(document: child as! Document)
|
||||
case is BlockQuote: return visit(blockQuote: child as! BlockQuote)
|
||||
case is List: return visit(list: child as! List)
|
||||
case is Item: return visit(item: child as! Item)
|
||||
case is CodeBlock: return visit(codeBlock: child as! CodeBlock)
|
||||
case is HtmlBlock: return visit(htmlBlock: child as! HtmlBlock)
|
||||
case is CustomBlock: return visit(customBlock: child as! CustomBlock)
|
||||
case is Paragraph: return visit(paragraph: child as! Paragraph)
|
||||
case is Heading: return visit(heading: child as! Heading)
|
||||
case is ThematicBreak: return visit(thematicBreak: child as! ThematicBreak)
|
||||
case is Text: return visit(text: child as! Text)
|
||||
case is SoftBreak: return visit(softBreak: child as! SoftBreak)
|
||||
case is LineBreak: return visit(lineBreak: child as! LineBreak)
|
||||
case is Code: return visit(code: child as! Code)
|
||||
case is HtmlInline: return visit(htmlInline: child as! HtmlInline)
|
||||
case is CustomInline: return visit(customInline: child as! CustomInline)
|
||||
case is Emphasis: return visit(emphasis: child as! Emphasis)
|
||||
case is Strong: return visit(strong: child as! Strong)
|
||||
case is Link: return visit(link: child as! Link)
|
||||
case is Image: return visit(image: child as! Image)
|
||||
case let child as Document: return visit(document: child)
|
||||
case let child as BlockQuote: return visit(blockQuote: child)
|
||||
case let child as List: return visit(list: child)
|
||||
case let child as Item: return visit(item: child)
|
||||
case let child as CodeBlock: return visit(codeBlock: child)
|
||||
case let child as HtmlBlock: return visit(htmlBlock: child)
|
||||
case let child as CustomBlock: return visit(customBlock: child)
|
||||
case let child as Paragraph: return visit(paragraph: child)
|
||||
case let child as Heading: return visit(heading: child)
|
||||
case let child as ThematicBreak: return visit(thematicBreak: child)
|
||||
case let child as Text: return visit(text: child)
|
||||
case let child as SoftBreak: return visit(softBreak: child)
|
||||
case let child as LineBreak: return visit(lineBreak: child)
|
||||
case let child as Code: return visit(code: child)
|
||||
case let child as HtmlInline: return visit(htmlInline: child)
|
||||
case let child as CustomInline: return visit(customInline: child)
|
||||
case let child as Emphasis: return visit(emphasis: child)
|
||||
case let child as Strong: return visit(strong: child)
|
||||
case let child as Link: return visit(link: child)
|
||||
case let child as Image: return visit(image: child)
|
||||
default:
|
||||
assertionFailure("Unexpected child")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
@@ -3,21 +3,25 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Down: DownASTRenderable, DownHTMLRenderable, DownXMLRenderable,
|
||||
DownLaTeXRenderable, DownGroffRenderable, DownCommonMarkRenderable,
|
||||
DownAttributedStringRenderable {
|
||||
DownLaTeXRenderable, DownGroffRenderable, DownCommonMarkRenderable {
|
||||
/// A string containing CommonMark Markdown
|
||||
public var markdownString: String
|
||||
|
||||
/// Initializes the container with a CommonMark Markdown string which can then be rendered depending on protocol conformance
|
||||
/// Initializes the container with a CommonMark Markdown string which can then be
|
||||
/// rendered depending on protocol conformance.
|
||||
///
|
||||
/// - Parameter markdownString: A string containing CommonMark Markdown
|
||||
public init(markdownString: String) {
|
||||
self.markdownString = markdownString
|
||||
}
|
||||
}
|
||||
|
||||
#if !os(Linux)
|
||||
extension Down: DownAttributedStringRenderable { }
|
||||
#endif // !os(Linux)
|
||||
+14
-5
@@ -3,25 +3,34 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum DownErrors: Error {
|
||||
/// Thrown when there was an issue converting the Markdown into an abstract syntax tree
|
||||
|
||||
/// Thrown when there was an issue converting the Markdown into an abstract syntax tree.
|
||||
|
||||
case markdownToASTError
|
||||
|
||||
/// Thrown when the abstract syntax tree could not be rendered into another format
|
||||
/// Thrown when the abstract syntax tree could not be rendered into another format.
|
||||
|
||||
case astRenderingError
|
||||
|
||||
/// Thrown when an HTML string cannot be converted into an `NSData` representation
|
||||
/// Thrown when an HTML string cannot be converted into an `NSData` representation.
|
||||
|
||||
case htmlDataConversionError
|
||||
|
||||
#if os(macOS)
|
||||
|
||||
/// Thrown when a custom template bundle has a non-standard bundle format.
|
||||
///
|
||||
/// Specifically, the file URL of the bundle’s subdirectory containing resource files could not be found (i.e. the bundle's `resourceURL` property is nil).
|
||||
/// Specifically, the file URL of the bundle’s subdirectory containing resource files could
|
||||
/// not be found (i.e. the bundle's `resourceURL` property is nil).
|
||||
|
||||
case nonStandardBundleFormatError
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
+24
-4
@@ -3,25 +3,34 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public struct DownOptions: OptionSet {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public let rawValue: Int32
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
public init(rawValue: Int32) { self.rawValue = rawValue }
|
||||
|
||||
/// Default options
|
||||
/// Default options.
|
||||
|
||||
public static let `default` = DownOptions(rawValue: CMARK_OPT_DEFAULT)
|
||||
|
||||
// MARK: - Rendering Options
|
||||
|
||||
/// Include a `data-sourcepos` attribute on all block elements
|
||||
/// Include a `data-sourcepos` attribute on all block elements.
|
||||
|
||||
public static let sourcePos = DownOptions(rawValue: CMARK_OPT_SOURCEPOS)
|
||||
|
||||
/// Render `softbreak` elements as hard line breaks.
|
||||
|
||||
public static let hardBreaks = DownOptions(rawValue: CMARK_OPT_HARDBREAKS)
|
||||
|
||||
/// Suppress raw HTML and unsafe links (`javascript:`, `vbscript:`,
|
||||
@@ -32,8 +41,9 @@ public struct DownOptions: OptionSet {
|
||||
///
|
||||
/// Note: this is the default option as of cmark v0.29.0. Use `unsafe`
|
||||
/// to disable this behavior.
|
||||
|
||||
public static let safe = DownOptions(rawValue: CMARK_OPT_SAFE)
|
||||
|
||||
|
||||
/// Render raw HTML and unsafe links (`javascript:`, `vbscript:`,
|
||||
/// `file:`, and `data:`, except for `image/png`, `image/gif`,
|
||||
/// `image/jpeg`, or `image/webp` mime types). By default,
|
||||
@@ -41,18 +51,28 @@ public struct DownOptions: OptionSet {
|
||||
/// links are replaced by empty strings.
|
||||
///
|
||||
/// Note: `safe` is the default as of cmark v0.29.0
|
||||
|
||||
public static let unsafe = DownOptions(rawValue: CMARK_OPT_UNSAFE)
|
||||
|
||||
// MARK: - Parsing Options
|
||||
|
||||
/// Normalize tree by consolidating adjacent text nodes.
|
||||
|
||||
public static let normalize = DownOptions(rawValue: CMARK_OPT_NORMALIZE)
|
||||
|
||||
/// Validate UTF-8 in the input before parsing, replacing illegal
|
||||
/// sequences with the replacement character U+FFFD.
|
||||
|
||||
public static let validateUTF8 = DownOptions(rawValue: CMARK_OPT_VALIDATE_UTF8)
|
||||
|
||||
/// Convert straight quotes to curly, --- to em dashes, -- to en dashes.
|
||||
|
||||
public static let smart = DownOptions(rawValue: CMARK_OPT_SMART)
|
||||
|
||||
// MARK: - Combo Options
|
||||
|
||||
/// Combines 'unsafe' and 'smart' to render raw HTML and produce smart typography.
|
||||
|
||||
public static let smartUnsafe = DownOptions(rawValue: CMARK_OPT_SMART + CMARK_OPT_UNSAFE)
|
||||
|
||||
}
|
||||
+20
-8
@@ -3,22 +3,31 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
#else
|
||||
import UIKit
|
||||
#endif
|
||||
#if !os(Linux)
|
||||
|
||||
#if os(macOS)
|
||||
|
||||
import AppKit
|
||||
|
||||
#else
|
||||
|
||||
import UIKit
|
||||
|
||||
#endif
|
||||
|
||||
extension NSAttributedString {
|
||||
|
||||
/// Instantiates an attributed string with the given HTML string
|
||||
///
|
||||
/// - Parameter htmlString: An HTML string
|
||||
/// - Throws: `HTMLDataConversionError` or an instantiation error
|
||||
/// - Parameters:
|
||||
/// - htmlString: An HTML string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `HTMLDataConversionError` or an instantiation error.
|
||||
|
||||
convenience init(htmlString: String) throws {
|
||||
guard let data = htmlString.data(using: String.Encoding.utf8) else {
|
||||
throw DownErrors.htmlDataConversionError
|
||||
@@ -28,7 +37,10 @@ extension NSAttributedString {
|
||||
.documentType: NSAttributedString.DocumentType.html,
|
||||
.characterEncoding: NSNumber(value: String.Encoding.utf8.rawValue)
|
||||
]
|
||||
|
||||
try self.init(data: data, options: options, documentAttributes: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !os(Linux)
|
||||
+10
-5
@@ -3,7 +3,7 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@@ -11,11 +11,16 @@ import libcmark
|
||||
|
||||
extension String {
|
||||
|
||||
/// Generates an HTML string from the contents of the string (self), which should contain CommonMark Markdown
|
||||
/// Generates an HTML string from the contents of the string (self), which should contain CommonMark Markdown.
|
||||
///
|
||||
/// - Parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: HTML string
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - Returns:
|
||||
/// An HTML string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toHTML(_ options: DownOptions = .default) throws -> String {
|
||||
let ast = try DownASTRenderer.stringToAST(self, options: options)
|
||||
let html = try DownHTMLRenderer.astToHTML(ast, options: options)
|
||||
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// DownASTRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownASTRenderable: DownRenderable {
|
||||
|
||||
func toAST(_ options: DownOptions) throws -> CMarkNode
|
||||
|
||||
}
|
||||
|
||||
extension DownASTRenderable {
|
||||
|
||||
/// Generates an abstract syntax tree from the `markdownString` property.
|
||||
///
|
||||
/// - Parametera:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An abstract syntax tree representation of the Markdown input.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `MarkdownToASTError` if conversion fails.
|
||||
|
||||
public func toAST(_ options: DownOptions = .default) throws -> CMarkNode {
|
||||
return try DownASTRenderer.stringToAST(markdownString, options: options)
|
||||
}
|
||||
|
||||
/// Parses the `markdownString` property into an abstract syntax tree and returns the root `Document` node.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// The root Document node for the abstract syntax tree representation of the Markdown input.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `MarkdownToASTError` if conversion fails.
|
||||
|
||||
public func toDocument(_ options: DownOptions = .default) throws -> Document {
|
||||
let tree = try toAST(options)
|
||||
|
||||
guard tree.type == CMARK_NODE_DOCUMENT else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return Document(cmarkNode: tree)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct DownASTRenderer {
|
||||
|
||||
/// Generates an abstract syntax tree from the given CommonMark Markdown string.
|
||||
///
|
||||
/// **Important:** It is the caller's responsibility to call `cmark_node_free(ast)` on the returned value.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - string: A string containing CommonMark Markdown.
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An abstract syntax tree representation of the Markdown input.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `MarkdownToASTError` if conversion fails.
|
||||
public static func stringToAST(_ string: String, options: DownOptions = .default) throws -> CMarkNode {
|
||||
var tree: CMarkNode?
|
||||
|
||||
string.withCString {
|
||||
let stringLength = Int(strlen($0))
|
||||
tree = cmark_parse_document($0, stringLength, options.rawValue)
|
||||
}
|
||||
|
||||
guard let ast = tree else {
|
||||
throw DownErrors.markdownToASTError
|
||||
}
|
||||
|
||||
return ast
|
||||
}
|
||||
|
||||
}
|
||||
+35
-20
@@ -3,19 +3,24 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownAttributedStringRenderable: DownHTMLRenderable, DownASTRenderable {
|
||||
|
||||
func toAttributedString(_ options: DownOptions, stylesheet: String?) throws -> NSAttributedString
|
||||
func toAttributedString(_ options: DownOptions, styler: Styler) throws -> NSAttributedString
|
||||
|
||||
}
|
||||
|
||||
extension DownAttributedStringRenderable {
|
||||
/// Generates an `NSAttributedString` from the `markdownString` property
|
||||
|
||||
/// Generates an `NSAttributedString` from the `markdownString` property.
|
||||
///
|
||||
/// **Note:** The attributed string is constructed and rendered via WebKit from html generated from the
|
||||
/// abstract syntax tree. This process is not background safe and must be executed on the main
|
||||
@@ -23,36 +28,46 @@ extension DownAttributedStringRenderable {
|
||||
/// use the `toAttributedString(options: styler:)` method below.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - stylesheet: a `String` to use as the CSS stylesheet when rendering, defaulting to a style that uses the `NSAttributedString` default font
|
||||
/// - Returns: An `NSAttributedString`
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
public func toAttributedString(_ options: DownOptions = .default, stylesheet: String? = nil) throws -> NSAttributedString {
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - stylesheet: a `String` to use as the CSS stylesheet when rendering, defaulting
|
||||
/// to a style that uses the `NSAttributedString` default font.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An `NSAttributedString`.
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toAttributedString(_ options: DownOptions = .default,
|
||||
stylesheet: String? = nil) throws -> NSAttributedString {
|
||||
|
||||
let html = try self.toHTML(options)
|
||||
let defaultStylesheet = "* {font-family: Helvetica } code, pre { font-family: Menlo }"
|
||||
return try NSAttributedString(htmlString: "<style>" + (stylesheet ?? defaultStylesheet) + "</style>" + html)
|
||||
}
|
||||
|
||||
/// Generates an `NSAttributedString` from the `markdownString` property
|
||||
|
||||
/// Generates an `NSAttributedString` from the `markdownString` property.
|
||||
///
|
||||
/// **Note:** The attributed string is constructed directly by traversing the abstract syntax tree. It is
|
||||
/// much faster than the `toAttributedString(options: stylesheet)` method and it can be also be
|
||||
/// rendered in a background thread.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering
|
||||
/// - styler: a class/struct conforming to `Styler` to use when rendering the various elements of the attributed string
|
||||
/// - Returns: `DownErrors` depending on the scenario
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - options: `DownOptions` to modify parsing or rendering.
|
||||
/// - styler: a class/struct conforming to `Styler` to use when rendering the various
|
||||
/// elements of the attributed string
|
||||
///
|
||||
/// - Returns:
|
||||
/// An `NSAttributedString`.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toAttributedString(_ options: DownOptions = .default, styler: Styler) throws -> NSAttributedString {
|
||||
let tree = try self.toAST(options)
|
||||
|
||||
guard tree.type == CMARK_NODE_DOCUMENT else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
let document = Document(cmarkNode: tree)
|
||||
let document = try self.toDocument(options)
|
||||
let visitor = AttributedStringVisitor(styler: styler, options: options)
|
||||
return document.accept(visitor)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !os(Linux)
|
||||
+37
-17
@@ -3,55 +3,75 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownCommonMarkRenderable: DownRenderable {
|
||||
|
||||
func toCommonMark(_ options: DownOptions, width: Int32) throws -> String
|
||||
|
||||
}
|
||||
|
||||
extension DownCommonMarkRenderable {
|
||||
/// Generates a CommonMark Markdown string from the `markdownString` property
|
||||
|
||||
/// Generates a CommonMark Markdown string from the `markdownString` property.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - width: The width to break on, defaulting to 0
|
||||
/// - Returns: CommonMark Markdown string
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - width: The width to break on, defaulting to 0.
|
||||
///
|
||||
/// - Returns:
|
||||
/// A CommonMark Markdown string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toCommonMark(_ options: DownOptions = .default, width: Int32 = 0) throws -> String {
|
||||
let ast = try DownASTRenderer.stringToAST(markdownString, options: options)
|
||||
let commonMark = try DownCommonMarkRenderer.astToCommonMark(ast, options: options, width: width)
|
||||
cmark_node_free(ast)
|
||||
return commonMark
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct DownCommonMarkRenderer {
|
||||
/// Generates a CommonMark Markdown string from the given abstract syntax tree
|
||||
|
||||
/// Generates a CommonMark Markdown string from the given abstract syntax tree.
|
||||
///
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - width: The width to break on, defaulting to 0
|
||||
/// - Returns: CommonMark Markdown string
|
||||
/// - Throws: `ASTRenderingError` if the AST could not be converted
|
||||
public static func astToCommonMark(_ ast: UnsafeMutablePointer<cmark_node>,
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree.
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - width: The width to break on, defaulting to 0.
|
||||
///
|
||||
/// - Returns:
|
||||
/// A CommonMark Markdown string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `ASTRenderingError` if the AST could not be converted.
|
||||
|
||||
public static func astToCommonMark(_ ast: CMarkNode,
|
||||
options: DownOptions = .default,
|
||||
width: Int32 = 0) throws -> String {
|
||||
|
||||
guard let cCommonMarkString = cmark_render_commonmark(ast, options.rawValue, width) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cCommonMarkString) }
|
||||
|
||||
|
||||
defer {
|
||||
free(cCommonMarkString)
|
||||
}
|
||||
|
||||
guard let commonMarkString = String(cString: cCommonMarkString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
|
||||
return commonMarkString
|
||||
}
|
||||
|
||||
}
|
||||
+36
-16
@@ -3,55 +3,75 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownGroffRenderable: DownRenderable {
|
||||
|
||||
func toGroff(_ options: DownOptions, width: Int32) throws -> String
|
||||
|
||||
}
|
||||
|
||||
extension DownGroffRenderable {
|
||||
/// Generates a groff man string from the `markdownString` property
|
||||
|
||||
/// Generates a groff man string from the `markdownString` property.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - width: The width to break on, defaulting to 0
|
||||
/// - Returns: groff man string
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - width: The width to break on, defaulting to 0.
|
||||
///
|
||||
/// - Returns:
|
||||
/// A groff man string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toGroff(_ options: DownOptions = .default, width: Int32 = 0) throws -> String {
|
||||
let ast = try DownASTRenderer.stringToAST(markdownString, options: options)
|
||||
let groff = try DownGroffRenderer.astToGroff(ast, options: options, width: width)
|
||||
cmark_node_free(ast)
|
||||
return groff
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct DownGroffRenderer {
|
||||
/// Generates a groff man string from the given abstract syntax tree
|
||||
|
||||
/// Generates a groff man string from the given abstract syntax tree.
|
||||
///
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - width: The width to break on, defaulting to 0
|
||||
/// - Returns: groff man string
|
||||
/// - Throws: `ASTRenderingError` if the AST could not be converted
|
||||
public static func astToGroff(_ ast: UnsafeMutablePointer<cmark_node>,
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree.
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - width: The width to break on, defaulting to 0.
|
||||
///
|
||||
/// - Returns:
|
||||
/// A groff man string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `ASTRenderingError` if the AST could not be converted.
|
||||
|
||||
public static func astToGroff(_ ast: CMarkNode,
|
||||
options: DownOptions = .default,
|
||||
width: Int32 = 0) throws -> String {
|
||||
|
||||
guard let cGroffString = cmark_render_man(ast, options.rawValue, width) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cGroffString) }
|
||||
|
||||
|
||||
defer {
|
||||
free(cGroffString)
|
||||
}
|
||||
|
||||
guard let groffString = String(cString: cGroffString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return groffString
|
||||
}
|
||||
|
||||
}
|
||||
+34
-14
@@ -3,47 +3,67 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownHTMLRenderable: DownRenderable {
|
||||
|
||||
func toHTML(_ options: DownOptions) throws -> String
|
||||
|
||||
}
|
||||
|
||||
extension DownHTMLRenderable {
|
||||
/// Generates an HTML string from the `markdownString` property
|
||||
|
||||
/// Generates an HTML string from the `markdownString` property.
|
||||
///
|
||||
/// - Parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: HTML string
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An HTML string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toHTML(_ options: DownOptions = .default) throws -> String {
|
||||
return try markdownString.toHTML(options)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct DownHTMLRenderer {
|
||||
/// Generates an HTML string from the given abstract syntax tree
|
||||
|
||||
/// Generates an HTML string from the given abstract syntax tree.
|
||||
///
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: HTML string
|
||||
/// - Throws: `ASTRenderingError` if the AST could not be converted
|
||||
public static func astToHTML(_ ast: UnsafeMutablePointer<cmark_node>, options: DownOptions = .default) throws -> String {
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree.
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An HTML string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `ASTRenderingError` if the AST could not be converted.
|
||||
|
||||
public static func astToHTML(_ ast: CMarkNode, options: DownOptions = .default) throws -> String {
|
||||
guard let cHTMLString = cmark_render_html(ast, options.rawValue) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cHTMLString) }
|
||||
|
||||
|
||||
defer {
|
||||
free(cHTMLString)
|
||||
}
|
||||
|
||||
guard let htmlString = String(cString: cHTMLString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return htmlString
|
||||
}
|
||||
|
||||
}
|
||||
+37
-17
@@ -3,55 +3,75 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownLaTeXRenderable: DownRenderable {
|
||||
|
||||
func toLaTeX(_ options: DownOptions, width: Int32) throws -> String
|
||||
|
||||
}
|
||||
|
||||
extension DownLaTeXRenderable {
|
||||
/// Generates a LaTeX string from the `markdownString` property
|
||||
|
||||
/// Generates a LaTeX string from the `markdownString` property.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - width: The width to break on, defaulting to 0
|
||||
/// - Returns: LaTeX string
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - width: The width to break on, defaulting to 0.
|
||||
///
|
||||
/// - Returns:
|
||||
/// A LaTeX string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toLaTeX(_ options: DownOptions = .default, width: Int32 = 0) throws -> String {
|
||||
let ast = try DownASTRenderer.stringToAST(markdownString, options: options)
|
||||
let latex = try DownLaTeXRenderer.astToLaTeX(ast, options: options, width: width)
|
||||
cmark_node_free(ast)
|
||||
return latex
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct DownLaTeXRenderer {
|
||||
/// Generates a LaTeX string from the given abstract syntax tree
|
||||
|
||||
/// Generates a LaTeX string from the given abstract syntax tree.
|
||||
///
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - width: The width to break on, defaulting to 0
|
||||
/// - Returns: LaTeX string
|
||||
/// - Throws: `ASTRenderingError` if the AST could not be converted
|
||||
public static func astToLaTeX(_ ast: UnsafeMutablePointer<cmark_node>,
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree.
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
/// - width: The width to break on, defaulting to 0.
|
||||
///
|
||||
/// - Returns:
|
||||
/// A LaTeX string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `ASTRenderingError` if the AST could not be converted.
|
||||
|
||||
public static func astToLaTeX(_ ast: CMarkNode,
|
||||
options: DownOptions = .default,
|
||||
width: Int32 = 0) throws -> String {
|
||||
|
||||
guard let cLatexString = cmark_render_latex(ast, options.rawValue, width) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cLatexString) }
|
||||
|
||||
|
||||
defer {
|
||||
free(cLatexString)
|
||||
}
|
||||
|
||||
guard let latexString = String(cString: cLatexString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
|
||||
return latexString
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,12 +3,15 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol DownRenderable {
|
||||
/// A string containing CommonMark Markdown
|
||||
|
||||
/// A string containing CommonMark Markdown.
|
||||
|
||||
var markdownString: String { get set }
|
||||
|
||||
}
|
||||
+33
-13
@@ -3,50 +3,70 @@
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016-2019 Glazed Donut, LLC. All rights reserved.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownXMLRenderable: DownRenderable {
|
||||
|
||||
func toXML(_ options: DownOptions) throws -> String
|
||||
|
||||
}
|
||||
|
||||
extension DownXMLRenderable {
|
||||
/// Generates an XML string from the `markdownString` property
|
||||
|
||||
/// Generates an XML string from the `markdownString` property.
|
||||
///
|
||||
/// - Parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: XML string
|
||||
/// - Throws: `DownErrors` depending on the scenario
|
||||
/// - Parameters:
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An XML string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `DownErrors` depending on the scenario.
|
||||
|
||||
public func toXML(_ options: DownOptions = .default) throws -> String {
|
||||
let ast = try DownASTRenderer.stringToAST(markdownString, options: options)
|
||||
let xml = try DownXMLRenderer.astToXML(ast, options: options)
|
||||
cmark_node_free(ast)
|
||||
return xml
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct DownXMLRenderer {
|
||||
|
||||
/// Generates an XML string from the given abstract syntax tree
|
||||
///
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
/// **Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
/// - Returns: XML string
|
||||
/// - Throws: `ASTRenderingError` if the AST could not be converted
|
||||
public static func astToXML(_ ast: UnsafeMutablePointer<cmark_node>, options: DownOptions = .default) throws -> String {
|
||||
/// - ast: The `cmark_node` representing the abstract syntax tree.
|
||||
/// - options: `DownOptions` to modify parsing or rendering, defaulting to `.default`.
|
||||
///
|
||||
/// - Returns:
|
||||
/// An XML string.
|
||||
///
|
||||
/// - Throws:
|
||||
/// `ASTRenderingError` if the AST could not be converted.
|
||||
|
||||
public static func astToXML(_ ast: CMarkNode, options: DownOptions = .default) throws -> String {
|
||||
guard let cXMLString = cmark_render_xml(ast, options.rawValue) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cXMLString) }
|
||||
|
||||
|
||||
defer {
|
||||
free(cXMLString)
|
||||
}
|
||||
|
||||
guard let xmlString = String(cString: cXMLString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return xmlString
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user