Compare commits
134 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 | |||
| 49b3ebae4d | |||
| c0660dcda8 | |||
| a0535b7222 | |||
| 17a5842293 | |||
| 25fde3d7c8 | |||
| 3d044c766b | |||
| 4c35c7b0c5 | |||
| 410e45c77b | |||
| bc65c735bc | |||
| 8c96f29e91 | |||
| c70d824918 | |||
| 6e566e2d45 | |||
| 54664f90be | |||
| 07a117ef4a | |||
| a146258961 | |||
| 1685184749 | |||
| 1fecb4b3a4 | |||
| 8b1f549ace | |||
| 421a92f5df | |||
| bdd5215c9a | |||
| 23e7744b67 | |||
| 3e1e986138 | |||
| 4d947996fc | |||
| 8d0dcae7c1 | |||
| 8db18023dd | |||
| d93f3650c8 | |||
| d02f0f1d6e | |||
| 1c90cbbd7d | |||
| b38d1d6e63 | |||
| fc5081d065 | |||
| d71ec73d27 | |||
| 0c5cd04c76 | |||
| d753044f9d | |||
| 954004ba80 | |||
| b50767598c | |||
| b3094ba7c1 | |||
| 604bc5085e | |||
| 9c4c1881b6 | |||
| 6b0e3d87c3 | |||
| a2d6ee7fc7 | |||
| 121441f803 | |||
| b5c9b4f123 | |||
| 9a7f648504 | |||
| 5982d7792f | |||
| 0b9f0a2f72 | |||
| 17c07067f2 | |||
| 9d6ca2e042 | |||
| 267d8e7e10 | |||
| 7f1fd50d8c | |||
| b4de8302a1 | |||
| 35c2a7cc6a | |||
| 1f58905c61 | |||
| 1c3c8db4fc | |||
| 534a0f3fee | |||
| 713f5705dc | |||
| 69ac9c228e | |||
| 8b1392c3f4 | |||
| c5c571487e | |||
| f1ea78c18d | |||
| a681d1e3f9 | |||
| 4082c8d943 | |||
| 5fe883cbef |
@@ -1,3 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Help isolate and fix bugs
|
||||
|
||||
---
|
||||
|
||||
Please help prevent duplicate issues before submitting a new one:
|
||||
|
||||
* [ ] I've searched other open/closed issues for duplicates before opening up this new issue.
|
||||
@@ -15,5 +21,3 @@ Please help prevent duplicate issues before submitting a new one:
|
||||
## What happened instead?
|
||||
|
||||
ℹ Please replace this with what happened instead (e.g. the issue).
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an enhancement for this project
|
||||
|
||||
---
|
||||
|
||||
Please help prevent duplicate requests before submitting a new one:
|
||||
|
||||
* [ ] I've searched other open/closed issues for duplicates before opening up this new issue.
|
||||
|
||||
# Feature Request
|
||||
|
||||
## Is your feature request related to a problem? Please describe.
|
||||
|
||||
ℹ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
## Describe the solution you'd like
|
||||
|
||||
ℹ A clear and concise description of what you want to happen.
|
||||
|
||||
## Describe alternatives you've considered
|
||||
|
||||
ℹ A clear and concise description of any alternative solutions or features you've considered.
|
||||
@@ -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 @@
|
||||
4.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>
|
||||
+9
-9
@@ -1,12 +1,12 @@
|
||||
osx_image: xcode9
|
||||
osx_image: xcode12.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- set -o pipefail
|
||||
- gem install xcpretty slather -N
|
||||
- xcrun instruments -w "iPhone 6 (11.0)" || echo "(Pre)Launched the simulator."
|
||||
- set -o pipefail
|
||||
- xcrun simctl boot "iPhone 12" || echo "(Pre)Launched the simulator."
|
||||
script:
|
||||
- xcodebuild -project Down.xcodeproj -scheme "Down" -destination "platform=iOS Simulator,name=iPhone 6,OS=11.0" -enableCodeCoverage YES ONLY_ACTIVE_ARCH=YES test | xcpretty -c
|
||||
- xcodebuild -project Down.xcodeproj -scheme "Down" -sdk macosx -destination 'platform=OS X,arch=x86_64' -enableCodeCoverage YES test | xcpretty -c
|
||||
- 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)
|
||||
|
||||
+539
-109
@@ -1,181 +1,611 @@
|
||||
# Change Log
|
||||
# Changelog
|
||||
|
||||
## [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.11.0](https://github.com/johnxnguyen/Down/tree/v0.11.0) (2021-05-04)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.10.0...v0.11.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Fix/update example app [\#58](https://github.com/iwasrobbed/Down/pull/58) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- \[CodeCoverage\] Improve accuracy for combined code coverage reporting [\#205](https://github.com/johnxnguyen/Down/issues/205)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- \[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.10.0](https://github.com/johnxnguyen/Down/tree/v0.10.0) (2021-02-28)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.9.5...v0.10.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- \[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.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:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- 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))
|
||||
- Crash rendering markdown [\#126](https://github.com/johnxnguyen/Down/issues/126)
|
||||
|
||||
**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)
|
||||
- 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:**
|
||||
|
||||
- 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))
|
||||
- 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.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.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/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:**
|
||||
|
||||
- Push v0.4.1 to cocoapods [\#51](https://github.com/iwasrobbed/Down/issues/51)
|
||||
- 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:**
|
||||
|
||||
- \[tvOS\] Conditionally compile DownView [\#52](https://github.com/iwasrobbed/Down/pull/52) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- \[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.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.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:**
|
||||
|
||||
- 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)
|
||||
- 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:**
|
||||
|
||||
- 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))
|
||||
- \[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.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)
|
||||
## [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:**
|
||||
|
||||
- Example project [\#37](https://github.com/iwasrobbed/Down/issues/37)
|
||||
- Markdown tables support [\#36](https://github.com/iwasrobbed/Down/issues/36)
|
||||
- ” 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:**
|
||||
|
||||
- \[Xcode 10\] Crash in XCBuildService; need to use old build system [\#91](https://github.com/johnxnguyen/Down/issues/91)
|
||||
|
||||
**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)
|
||||
- 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:**
|
||||
|
||||
- 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))
|
||||
- \[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.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.5.2](https://github.com/johnxnguyen/Down/tree/v0.5.2) (2018-05-05)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Disable analysis of cmark source code [\#31](https://github.com/iwasrobbed/Down/pull/31) ([tonyarnold](https://github.com/tonyarnold))
|
||||
|
||||
## [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)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.5.1...v0.5.2)
|
||||
|
||||
**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))
|
||||
- \[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.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)
|
||||
## [v0.5.1](https://github.com/johnxnguyen/Down/tree/v0.5.1) (2018-03-03)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add OS X support [\#6](https://github.com/iwasrobbed/Down/issues/6)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \#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)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.5.0...v0.5.1)
|
||||
|
||||
**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)
|
||||
- `DocumentReadingOptionKey` Error via pod [\#80](https://github.com/johnxnguyen/Down/issues/80)
|
||||
|
||||
**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))
|
||||
- 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.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)
|
||||
## [v0.5.0](https://github.com/johnxnguyen/Down/tree/v0.5.0) (2018-02-24)
|
||||
|
||||
**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)
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.4.2...v0.5.0)
|
||||
|
||||
**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)
|
||||
- Fix/update example app [\#58](https://github.com/johnxnguyen/Down/pull/58) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- Can you give an example how to custom the parser? [\#9](https://github.com/iwasrobbed/Down/issues/9)
|
||||
- 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:**
|
||||
|
||||
- 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))
|
||||
- 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.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)
|
||||
## [v0.4.2](https://github.com/johnxnguyen/Down/tree/v0.4.2) (2017-10-21)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.4.1...v0.4.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Push v0.4.1 to cocoapods [\#51](https://github.com/johnxnguyen/Down/issues/51)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \[tvOS\] Conditionally compile DownView [\#52](https://github.com/johnxnguyen/Down/pull/52) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [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:**
|
||||
|
||||
- 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))
|
||||
- Example project [\#37](https://github.com/johnxnguyen/Down/issues/37)
|
||||
- Markdown tables support [\#36](https://github.com/johnxnguyen/Down/issues/36)
|
||||
|
||||
## [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)
|
||||
**Closed issues:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- 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.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:**
|
||||
|
||||
- Add CocoaPods support & cmark license [\#1](https://github.com/iwasrobbed/Down/pull/1) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
- Disable analysis of cmark source code [\#31](https://github.com/johnxnguyen/Down/pull/31) ([tonyarnold](https://github.com/tonyarnold))
|
||||
|
||||
## [v0.1](https://github.com/iwasrobbed/Down/tree/v0.1) (2016-06-01)
|
||||
## [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:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- 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.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:**
|
||||
|
||||
- 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)
|
||||
|
||||
## [v0.3](https://github.com/johnxnguyen/Down/tree/v0.3) (2016-10-12)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.2...v0.3)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- 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:**
|
||||
|
||||
- Can you give an example how to custom the parser? [\#9](https://github.com/johnxnguyen/Down/issues/9)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- 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.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:**
|
||||
|
||||
- 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.1.1](https://github.com/johnxnguyen/Down/tree/v0.1.1) (2016-06-01)
|
||||
|
||||
[Full Changelog](https://github.com/johnxnguyen/Down/compare/v0.1...v0.1.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add CocoaPods support & cmark license [\#1](https://github.com/johnxnguyen/Down/pull/1) ([iwasrobbed](https://github.com/iwasrobbed))
|
||||
|
||||
## [v0.1](https://github.com/johnxnguyen/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)*
|
||||
|
||||
@@ -7,16 +7,38 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
14090A4C2185411800503C06 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14090A4B2185411800503C06 /* AppDelegate.swift */; };
|
||||
14090A4E2185411800503C06 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14090A4D2185411800503C06 /* ViewController.swift */; };
|
||||
14090A502185411A00503C06 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14090A4F2185411A00503C06 /* Assets.xcassets */; };
|
||||
14090A532185411A00503C06 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14090A512185411A00503C06 /* Main.storyboard */; };
|
||||
1466417E218D2A18009627F9 /* Down.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D49980B51FA560F8004EE42E /* Down.framework */; };
|
||||
1466417F218D2A18009627F9 /* Down.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D49980B51FA560F8004EE42E /* Down.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
14954EA521A7DCB9001933C4 /* README-sample.md in Resources */ = {isa = PBXBuildFile; fileRef = 14954EA421A7DCA3001933C4 /* README-sample.md */; };
|
||||
14954EA621A7DCBA001933C4 /* README-sample.md in Resources */ = {isa = PBXBuildFile; fileRef = 14954EA421A7DCA3001933C4 /* README-sample.md */; };
|
||||
8A07D7D31F085EC6004D7141 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A07D7D21F085EC6004D7141 /* AppDelegate.swift */; };
|
||||
8A07D7D51F085EC6004D7141 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A07D7D41F085EC6004D7141 /* ViewController.swift */; };
|
||||
8A07D7D81F085EC6004D7141 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8A07D7D61F085EC6004D7141 /* Main.storyboard */; };
|
||||
8A07D7DA1F085EC6004D7141 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8A07D7D91F085EC6004D7141 /* Assets.xcassets */; };
|
||||
8A07D7DD1F085EC6004D7141 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8A07D7DB1F085EC6004D7141 /* LaunchScreen.storyboard */; };
|
||||
D49980B81FA560FF004EE42E /* Down.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D49980B51FA560F8004EE42E /* Down.framework */; };
|
||||
D49980B91FA560FF004EE42E /* Down.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D49980B51FA560F8004EE42E /* Down.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
D4591E9C226D293F00EBD476 /* Down.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D49980B51FA560F8004EE42E /* Down.framework */; };
|
||||
D4591E9D226D293F00EBD476 /* Down.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D49980B51FA560F8004EE42E /* Down.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
14664180218D2A18009627F9 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D49980AF1FA560F8004EE42E /* Down.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8A569F3F1E6B3E50008BE2AC;
|
||||
remoteInfo = Down;
|
||||
};
|
||||
D4591E9E226D293F00EBD476 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D49980AF1FA560F8004EE42E /* Down.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8A569F3F1E6B3E50008BE2AC;
|
||||
remoteInfo = Down;
|
||||
};
|
||||
D49980B41FA560F8004EE42E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D49980AF1FA560F8004EE42E /* Down.xcodeproj */;
|
||||
@@ -31,23 +53,34 @@
|
||||
remoteGlobalIDString = 8AFAEAFB1E6E32E900E09B68;
|
||||
remoteInfo = DownTests;
|
||||
};
|
||||
D49980BA1FA560FF004EE42E /* PBXContainerItemProxy */ = {
|
||||
D4C77E06240EEB64004675B3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D49980AF1FA560F8004EE42E /* Down.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8A569F3F1E6B3E50008BE2AC;
|
||||
remoteInfo = Down;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = EEBA153A2344845500B54ECB;
|
||||
remoteInfo = DownSnapshotTests;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
D49980AD1FA5605D004EE42E /* Embed Frameworks */ = {
|
||||
14664182218D2A18009627F9 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
D49980B91FA560FF004EE42E /* Down.framework in Embed Frameworks */,
|
||||
1466417F218D2A18009627F9 /* Down.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D4591EA0226D293F00EBD476 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
D4591E9D226D293F00EBD476 /* Down.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -55,6 +88,14 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
14090A492185411800503C06 /* macOS Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "macOS Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
14090A4B2185411800503C06 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
14090A4D2185411800503C06 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
14090A4F2185411A00503C06 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
14090A522185411A00503C06 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
14090A542185411A00503C06 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
14090A5E2185443800503C06 /* macOS Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "macOS Demo.entitlements"; sourceTree = "<group>"; };
|
||||
14954EA421A7DCA3001933C4 /* README-sample.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "README-sample.md"; sourceTree = "<group>"; };
|
||||
8A07D7CF1F085EC6004D7141 /* Down-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Down-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8A07D7D21F085EC6004D7141 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
8A07D7D41F085EC6004D7141 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -66,22 +107,61 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
14090A462185411800503C06 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D4591E9C226D293F00EBD476 /* Down.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8A07D7CC1F085EC6004D7141 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D49980B81FA560FF004EE42E /* Down.framework in Frameworks */,
|
||||
1466417E218D2A18009627F9 /* Down.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
14090A4A2185411800503C06 /* macOS Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
14090A5E2185443800503C06 /* macOS Demo.entitlements */,
|
||||
14090A4B2185411800503C06 /* AppDelegate.swift */,
|
||||
14090A4D2185411800503C06 /* ViewController.swift */,
|
||||
14090A4F2185411A00503C06 /* Assets.xcassets */,
|
||||
14090A512185411A00503C06 /* Main.storyboard */,
|
||||
14090A542185411A00503C06 /* Info.plist */,
|
||||
);
|
||||
path = "macOS Demo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
14664175218D264A009627F9 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
14954EA321A7DCA3001933C4 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
14954EA421A7DCA3001933C4 /* README-sample.md */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8A07D7C61F085EC6004D7141 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D49980AF1FA560F8004EE42E /* Down.xcodeproj */,
|
||||
8A07D7D11F085EC6004D7141 /* Down-Example */,
|
||||
14090A4A2185411800503C06 /* macOS Demo */,
|
||||
14954EA321A7DCA3001933C4 /* Shared */,
|
||||
14664175218D264A009627F9 /* Frameworks */,
|
||||
8A07D7D01F085EC6004D7141 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
@@ -90,6 +170,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8A07D7CF1F085EC6004D7141 /* Down-Example.app */,
|
||||
14090A492185411800503C06 /* macOS Demo.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -112,6 +193,7 @@
|
||||
children = (
|
||||
D49980B51FA560F8004EE42E /* Down.framework */,
|
||||
D49980B71FA560F8004EE42E /* DownTests.xctest */,
|
||||
D4C77E07240EEB64004675B3 /* DownSnapshotTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -119,6 +201,25 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
14090A482185411800503C06 /* macOS Demo */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 14090A562185411A00503C06 /* Build configuration list for PBXNativeTarget "macOS Demo" */;
|
||||
buildPhases = (
|
||||
14090A452185411800503C06 /* Sources */,
|
||||
14090A462185411800503C06 /* Frameworks */,
|
||||
14090A472185411800503C06 /* Resources */,
|
||||
D4591EA0226D293F00EBD476 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D4591E9F226D293F00EBD476 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "macOS Demo";
|
||||
productName = "macOS Demo";
|
||||
productReference = 14090A492185411800503C06 /* macOS Demo.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
8A07D7CE1F085EC6004D7141 /* Down-Example */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 8A07D7E11F085EC6004D7141 /* Build configuration list for PBXNativeTarget "Down-Example" */;
|
||||
@@ -126,12 +227,12 @@
|
||||
8A07D7CB1F085EC6004D7141 /* Sources */,
|
||||
8A07D7CC1F085EC6004D7141 /* Frameworks */,
|
||||
8A07D7CD1F085EC6004D7141 /* Resources */,
|
||||
D49980AD1FA5605D004EE42E /* Embed Frameworks */,
|
||||
14664182218D2A18009627F9 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D49980BB1FA560FF004EE42E /* PBXTargetDependency */,
|
||||
14664181218D2A18009627F9 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "Down-Example";
|
||||
productName = "Down-Example";
|
||||
@@ -144,20 +245,30 @@
|
||||
8A07D7C71F085EC6004D7141 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0830;
|
||||
LastUpgradeCheck = 0900;
|
||||
ORGANIZATIONNAME = down;
|
||||
LastSwiftUpdateCheck = 1000;
|
||||
LastUpgradeCheck = 1130;
|
||||
ORGANIZATIONNAME = Down;
|
||||
TargetAttributes = {
|
||||
14090A482185411800503C06 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
DevelopmentTeam = 7V68668DJN;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.Sandbox = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
8A07D7CE1F085EC6004D7141 = {
|
||||
CreatedOnToolsVersion = 8.3.3;
|
||||
LastSwiftMigration = 0900;
|
||||
ProvisioningStyle = Automatic;
|
||||
LastSwiftMigration = 1020;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8A07D7CA1F085EC6004D7141 /* Build configuration list for PBXProject "Down-Example" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -175,6 +286,7 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8A07D7CE1F085EC6004D7141 /* Down-Example */,
|
||||
14090A482185411800503C06 /* macOS Demo */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -194,13 +306,31 @@
|
||||
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 */
|
||||
14090A472185411800503C06 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
14090A502185411A00503C06 /* Assets.xcassets in Resources */,
|
||||
14090A532185411A00503C06 /* Main.storyboard in Resources */,
|
||||
14954EA521A7DCB9001933C4 /* README-sample.md in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8A07D7CD1F085EC6004D7141 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
14954EA621A7DCBA001933C4 /* README-sample.md in Resources */,
|
||||
8A07D7DD1F085EC6004D7141 /* LaunchScreen.storyboard in Resources */,
|
||||
8A07D7DA1F085EC6004D7141 /* Assets.xcassets in Resources */,
|
||||
8A07D7D81F085EC6004D7141 /* Main.storyboard in Resources */,
|
||||
@@ -210,6 +340,15 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
14090A452185411800503C06 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
14090A4E2185411800503C06 /* ViewController.swift in Sources */,
|
||||
14090A4C2185411800503C06 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8A07D7CB1F085EC6004D7141 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -222,14 +361,27 @@
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
D49980BB1FA560FF004EE42E /* PBXTargetDependency */ = {
|
||||
14664181218D2A18009627F9 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = Down;
|
||||
targetProxy = D49980BA1FA560FF004EE42E /* PBXContainerItemProxy */;
|
||||
targetProxy = 14664180218D2A18009627F9 /* PBXContainerItemProxy */;
|
||||
};
|
||||
D4591E9F226D293F00EBD476 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = Down;
|
||||
targetProxy = D4591E9E226D293F00EBD476 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
14090A512185411A00503C06 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
14090A522185411A00503C06 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8A07D7D61F085EC6004D7141 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
@@ -249,10 +401,64 @@
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
14090A572185411A00503C06 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS Demo/macOS Demo.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
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.downMarkdown.macOS-Demo";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
14090A582185411A00503C06 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS Demo/macOS Demo.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
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.downMarkdown.macOS-Demo";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
8A07D7DF1F085EC6004D7141 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
@@ -263,6 +469,7 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -270,6 +477,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
@@ -277,7 +485,7 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -311,6 +519,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
@@ -321,6 +530,7 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -328,6 +538,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
@@ -335,7 +546,7 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
@@ -363,7 +574,6 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -372,10 +582,10 @@
|
||||
INFOPLIST_FILE = "Down-Example/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.down.Down-Example";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.Down-Example";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -384,7 +594,6 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -393,16 +602,25 @@
|
||||
INFOPLIST_FILE = "Down-Example/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.down.Down-Example";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.downMarkdown.Down-Example";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
14090A562185411A00503C06 /* Build configuration list for PBXNativeTarget "macOS Demo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
14090A572185411A00503C06 /* Debug */,
|
||||
14090A582185411A00503C06 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
8A07D7CA1F085EC6004D7141 /* Build configuration list for PBXProject "Down-Example" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?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>
|
||||
+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
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8A07D7CE1F085EC6004D7141"
|
||||
BuildableName = "Down-Example.app"
|
||||
BlueprintName = "Down-Example"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8A07D7CE1F085EC6004D7141"
|
||||
BuildableName = "Down-Example.app"
|
||||
BlueprintName = "Down-Example"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8A07D7CE1F085EC6004D7141"
|
||||
BuildableName = "Down-Example.app"
|
||||
BlueprintName = "Down-Example"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8A07D7CE1F085EC6004D7141"
|
||||
BuildableName = "Down-Example.app"
|
||||
BlueprintName = "Down-Example"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "14090A482185411800503C06"
|
||||
BuildableName = "macOS Demo.app"
|
||||
BlueprintName = "macOS Demo"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "14090A482185411800503C06"
|
||||
BuildableName = "macOS Demo.app"
|
||||
BlueprintName = "macOS Demo"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "14090A482185411800503C06"
|
||||
BuildableName = "macOS Demo.app"
|
||||
BlueprintName = "macOS Demo"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "14090A482185411800503C06"
|
||||
BuildableName = "macOS Demo.app"
|
||||
BlueprintName = "macOS Demo"
|
||||
ReferencedContainer = "container:Down-Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -3,21 +3,13 @@
|
||||
// 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
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
@@ -30,6 +40,16 @@
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
@@ -59,6 +79,16 @@
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Down_Example" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<view key="view" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -28,9 +28,15 @@
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleDefault</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
|
||||
@@ -3,74 +3,67 @@
|
||||
// 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
|
||||
import Down
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
final class ViewController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
guard let downView = try? DownView(frame: self.view.bounds, markdownString: markdownString, didLoadSuccessfully: {
|
||||
// Optional callback for loading finished
|
||||
print("Markdown was rendered.")
|
||||
}) else { return }
|
||||
view.addSubview(downView)
|
||||
|
||||
renderDownInWebView()
|
||||
}
|
||||
|
||||
fileprivate let markdownString = """
|
||||
## Down
|
||||
[](https://travis-ci.org/iwasrobbed/Down)
|
||||
[](https://github.com/iwasrobbed/Down/blob/master/LICENSE)
|
||||
[]()
|
||||
[](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)
|
||||
|
||||
Blazing fast Markdown rendering in Swift, built upon [cmark](https://github.com/jgm/cmark).
|
||||
|
||||
Is your app using it? [Let us know!](mailto:rob@robphillips.me)
|
||||
|
||||
#### Maintainers
|
||||
|
||||
- [Rob Phillips](https://github.com/iwasrobbed)
|
||||
- [Keaton Burleson](https://github.com/128keaton)
|
||||
- [Other contributors](https://github.com/iwasrobbed/Down/graphs/contributors) 🙌
|
||||
|
||||
### Installation
|
||||
|
||||
Note: Swift 4 support is now on the `master` branch and any tag >= 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):
|
||||
|
||||
```
|
||||
github "iwasrobbed/Down"
|
||||
```
|
||||
Due to limitations in Carthage regarding platform specification, you need to define the platform with Carthage.
|
||||
|
||||
e.g.
|
||||
|
||||
```carthage update --platform iOS```
|
||||
|
||||
Or manually install:
|
||||
|
||||
1. Clone this repository
|
||||
2. Build the Down project
|
||||
3. Add the resulting framework file to your project
|
||||
4. ?
|
||||
5. Profit
|
||||
"""
|
||||
|
||||
}
|
||||
|
||||
private extension ViewController {
|
||||
|
||||
func renderDownInWebView() {
|
||||
guard let readMeURL = Bundle.main.url(forResource: nil, withExtension: "md"),
|
||||
let readMeContents = try? String(contentsOf: readMeURL)
|
||||
else {
|
||||
showError(message: "Could not load readme contents.")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let downView = try DownView(frame: view.bounds, markdownString: readMeContents, didLoadSuccessfully: {
|
||||
print("Markdown was rendered.")
|
||||
})
|
||||
downView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(downView)
|
||||
constrain(subview: downView)
|
||||
createStatusBarBackgrounds(above: downView)
|
||||
} catch {
|
||||
showError(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func createStatusBarBackgrounds(above subview: UIView) {
|
||||
let blurEffect = UIBlurEffect(style: .prominent)
|
||||
let blurEffectView = UIVisualEffectView(effect: blurEffect)
|
||||
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.insertSubview(blurEffectView, aboveSubview: subview)
|
||||
constrain(subview: blurEffectView, bottomAnchor: topLayoutGuide.bottomAnchor)
|
||||
}
|
||||
|
||||
func constrain(subview: UIView, bottomAnchor: NSLayoutYAxisAnchor? = nil) {
|
||||
NSLayoutConstraint.activate([
|
||||
subview.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
subview.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
subview.topAnchor.constraint(equalTo: topLayoutGuide.topAnchor),
|
||||
subview.bottomAnchor.constraint(equalTo: bottomAnchor ?? bottomLayoutGuide.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
func showError(message: String) {
|
||||
let alertController = UIAlertController(title: "DownView Render Error",
|
||||
message: message,
|
||||
preferredStyle: .alert)
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
## Down
|
||||
[](https://travis-ci.org/iwasrobbed/Down)
|
||||
[](https://github.com/iwasrobbed/Down/blob/master/LICENSE)
|
||||
[]()
|
||||
[](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)
|
||||
|
||||
Blazing fast Markdown (CommonMark) rendering in Swift, built upon [cmark v0.28.3](https://github.com/commonmark/cmark).
|
||||
|
||||
Is your app using it? [Let us know!](mailto:rob@robphillips.me)
|
||||
|
||||
#### Maintainers
|
||||
|
||||
- [Rob Phillips](https://github.com/iwasrobbed)
|
||||
- [John Nguyen](https://github.com/johnxnguyen)
|
||||
- [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) 🙌
|
||||
|
||||
### Installation
|
||||
|
||||
Note: Swift 4 support is now on the `master` branch and any tag >= 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):
|
||||
|
||||
```
|
||||
github "iwasrobbed/Down"
|
||||
```
|
||||
Due to limitations in Carthage regarding platform specification, you need to define the platform with Carthage.
|
||||
|
||||
e.g.
|
||||
|
||||
```carthage update --platform iOS```
|
||||
|
||||
Or manually install:
|
||||
|
||||
1. Clone this repository
|
||||
2. Build the Down project
|
||||
3. Add the resulting framework file to your project
|
||||
4. ?
|
||||
5. Profit
|
||||
|
||||
### Robust Performance
|
||||
|
||||
>[cmark](https://github.com/commonmark/cmark) can render a Markdown version of War and Peace in the blink of an eye (127 milliseconds on a ten year old laptop, vs. 100-400 milliseconds for an eye blink). In our [benchmarks](https://github.com/commonmark/cmark/blob/master/benchmarks.md), cmark is 10,000 times faster than the original Markdown.pl, and on par with the very fastest available Markdown processors.
|
||||
|
||||
> The library has been extensively fuzz-tested using [american fuzzy lop](http://lcamtuf.coredump.cx/afl). The test suite includes pathological cases that bring many other Markdown parsers to a crawl (for example, thousands-deep nested bracketed text or block quotes).
|
||||
|
||||
### Output Formats
|
||||
* Web View (see DownView class)
|
||||
* HTML
|
||||
* XML
|
||||
* LaTeX
|
||||
* groff man
|
||||
* CommonMark Markdown
|
||||
* NSAttributedString
|
||||
* AST (abstract syntax tree)
|
||||
|
||||
### View Rendering
|
||||
|
||||
The `DownView` class offers a very simple way to parse a UTF-8 encoded string with Markdown and convert it to a web view that can be added to any view:
|
||||
|
||||
```swift
|
||||
let downView = try? DownView(frame: self.view.bounds, markdownString: "**Oh Hai**") {
|
||||
// Optional callback for loading finished
|
||||
}
|
||||
// Now add to view or constrain w/ Autolayout
|
||||
// Or you could optionally update the contents at some point:
|
||||
try? downView?.update(markdownString: "## [Google](https://google.com)") {
|
||||
// Optional callback for loading finished
|
||||
}
|
||||
```
|
||||
|
||||
Meta example of rendering this README:
|
||||
|
||||

|
||||
|
||||
### Parsing API
|
||||
|
||||
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)")
|
||||
|
||||
// Convert to HTML
|
||||
let html = try? down.toHTML()
|
||||
// "<h2><a href=\"https://github.com/iwasrobbed/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"
|
||||
|
||||
// Convert to groff man
|
||||
let man = try? down.toGroff()
|
||||
// ".SS\nDown (https://github.com/iwasrobbed/Down)\n"
|
||||
|
||||
// Convert to LaTeX
|
||||
let latex = try? down.toLaTeX()
|
||||
// "\\subsection{\\href{https://github.com/iwasrobbed/Down}{Down}}\n"
|
||||
|
||||
// Convert to CommonMark Markdown
|
||||
let commonMark = try? down.toCommonMark()
|
||||
// "## [Down](https://github.com/iwasrobbed/Down)\n"
|
||||
|
||||
// Convert to an attributed string
|
||||
let attributedString = try? down.toAttributedString()
|
||||
// NSAttributedString representation of the rendered HTML;
|
||||
// by default, uses a stylesheet that matches NSAttributedString's default font,
|
||||
// but you can override this by passing in your own, using the 'stylesheet:' parameter.
|
||||
|
||||
// Convert to abstract syntax tree
|
||||
let ast = try? down.toAST()
|
||||
// Returns pointer to AST that you can manipulate
|
||||
|
||||
```
|
||||
|
||||
### Rendering Granularity
|
||||
|
||||
If you'd like more granularity for the output types you want to support, you can create your own struct conforming to at least one of the renderable protocols:
|
||||
|
||||
* DownHTMLRenderable
|
||||
* DownXMLRenderable
|
||||
* DownLaTeXRenderable
|
||||
* DownGroffRenderable
|
||||
* DownCommonMarkRenderable
|
||||
* DownASTRenderable
|
||||
* DownAttributedStringRenderable
|
||||
|
||||
Example:
|
||||
|
||||
```swift
|
||||
public struct MarkdownToHTML: DownHTMLRenderable {
|
||||
/**
|
||||
A string containing CommonMark Markdown
|
||||
*/
|
||||
public var markdownString: String
|
||||
|
||||
/**
|
||||
Initializes the container with a CommonMark Markdown string which can then be rendered as HTML using `toHTML()`
|
||||
|
||||
- parameter markdownString: A string containing CommonMark Markdown
|
||||
|
||||
- returns: An instance of Self
|
||||
*/
|
||||
@warn_unused_result
|
||||
public init(markdownString: String) {
|
||||
self.markdownString = markdownString
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration of `DownView`
|
||||
|
||||
`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).
|
||||
|
||||
##### 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).
|
||||
|
||||
### Options
|
||||
|
||||
Each protocol has options that will influence either rendering or parsing:
|
||||
|
||||
```swift
|
||||
/**
|
||||
Default options
|
||||
*/
|
||||
public static let `default` = DownOptions(rawValue: 0)
|
||||
|
||||
// MARK: - Rendering Options
|
||||
|
||||
/**
|
||||
Include a `data-sourcepos` attribute on all block elements
|
||||
*/
|
||||
public static let sourcePos = DownOptions(rawValue: 1 << 1)
|
||||
|
||||
/**
|
||||
Render `softbreak` elements as hard line breaks.
|
||||
*/
|
||||
public static let hardBreaks = DownOptions(rawValue: 1 << 2)
|
||||
|
||||
/**
|
||||
Suppress raw HTML and unsafe links (`javascript:`, `vbscript:`,
|
||||
`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.
|
||||
*/
|
||||
public static let safe = DownOptions(rawValue: 1 << 3)
|
||||
|
||||
// MARK: - Parsing Options
|
||||
|
||||
/**
|
||||
Normalize tree by consolidating adjacent text nodes.
|
||||
*/
|
||||
public static let normalize = DownOptions(rawValue: 1 << 4)
|
||||
|
||||
/**
|
||||
Validate UTF-8 in the input before parsing, replacing illegal
|
||||
sequences with the replacement character U+FFFD.
|
||||
*/
|
||||
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)
|
||||
```
|
||||
|
||||
### Supports
|
||||
Swift; iOS 9+, tvOS 9+, macOS 10.11+
|
||||
|
||||
### Markdown Specification
|
||||
|
||||
Down is built upon the [CommonMark](http://commonmark.org) specification.
|
||||
|
||||
### A little help from my friends
|
||||
Please feel free to fork and create a pull request for bug fixes or improvements, being sure to maintain the general coding style, adding tests, and adding comments as necessary.
|
||||
|
||||
### Credit
|
||||
This library is a wrapper around [cmark](https://github.com/commonmark/cmark), which is built upon the [CommonMark](http://commonmark.org) Markdown specification.
|
||||
|
||||
[cmark](https://github.com/commonmark/cmark) is Copyright (c) 2014 - 2017, John MacFarlane. View [full license](https://github.com/commonmark/cmark/blob/master/COPYING).
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// macOS Demo
|
||||
//
|
||||
// Created by Chris Zielinski on 10/27/18.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,730 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Application-->
|
||||
<scene sceneID="JPo-4y-FX3">
|
||||
<objects>
|
||||
<application id="hnw-xV-0zn" sceneMemberID="viewController">
|
||||
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="macOS Demo" id="1Xt-HY-uBw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="macOS Demo" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<items>
|
||||
<menuItem title="About macOS Demo" id="5kV-Vb-QxS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||
<menuItem title="Services" id="NMo-om-nkz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||
<menuItem title="Hide macOS Demo" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<connections>
|
||||
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||
<menuItem title="Quit macOS Demo" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<connections>
|
||||
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="dMs-cI-mzQ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
||||
<items>
|
||||
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
|
||||
<connections>
|
||||
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
|
||||
<connections>
|
||||
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Open Recent" id="tXI-mr-wws">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
|
||||
<items>
|
||||
<menuItem title="Clear Menu" id="vNY-rz-j42">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
|
||||
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
||||
<connections>
|
||||
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
|
||||
<connections>
|
||||
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
|
||||
<connections>
|
||||
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
|
||||
<connections>
|
||||
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
|
||||
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
|
||||
<connections>
|
||||
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||
<items>
|
||||
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||
<connections>
|
||||
<action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||
<connections>
|
||||
<action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||
<connections>
|
||||
<action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||
<connections>
|
||||
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||
<connections>
|
||||
<action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||
<menuItem title="Find" id="4EN-yA-p0u">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
||||
<items>
|
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
||||
<connections>
|
||||
<action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||
<items>
|
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||
<items>
|
||||
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||
<items>
|
||||
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Format" id="jxT-CU-nIS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
|
||||
<items>
|
||||
<menuItem title="Font" id="Gi5-1S-RQB">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
|
||||
<items>
|
||||
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
|
||||
<connections>
|
||||
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
|
||||
<connections>
|
||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
|
||||
<connections>
|
||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
|
||||
<connections>
|
||||
<action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
|
||||
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
|
||||
<connections>
|
||||
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
|
||||
<connections>
|
||||
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
|
||||
<menuItem title="Kern" id="jBQ-r6-VK2">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
|
||||
<items>
|
||||
<menuItem title="Use Default" id="GUa-eO-cwY">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use None" id="cDB-IK-hbR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Tighten" id="46P-cB-AYj">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Loosen" id="ogc-rX-tC1">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Ligatures" id="o6e-r0-MWq">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
|
||||
<items>
|
||||
<menuItem title="Use Default" id="agt-UL-0e3">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use None" id="J7y-lM-qPV">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use All" id="xQD-1f-W4t">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Baseline" id="OaQ-X3-Vso">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
|
||||
<items>
|
||||
<menuItem title="Use Default" id="3Om-Ey-2VK">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Superscript" id="Rqc-34-cIF">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Subscript" id="I0S-gh-46l">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Raise" id="2h7-ER-AoG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Lower" id="1tx-W0-xDw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
|
||||
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
|
||||
<connections>
|
||||
<action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
|
||||
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Text" id="Fal-I4-PZk">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Text" id="d9c-me-L2H">
|
||||
<items>
|
||||
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
|
||||
<connections>
|
||||
<action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
|
||||
<connections>
|
||||
<action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Justify" id="J5U-5w-g23">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
|
||||
<connections>
|
||||
<action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
|
||||
<menuItem title="Writing Direction" id="H1b-Si-o9J">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
|
||||
<items>
|
||||
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem id="YGs-j5-SAR">
|
||||
<string key="title"> Default</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="Lbh-J2-qVU">
|
||||
<string key="title"> Left to Right</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="jFq-tB-4Kx">
|
||||
<string key="title"> Right to Left</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
|
||||
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem id="Nop-cj-93Q">
|
||||
<string key="title"> Default</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="BgM-ve-c93">
|
||||
<string key="title"> Left to Right</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="RB4-Sm-HuC">
|
||||
<string key="title"> Right to Left</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
|
||||
<menuItem title="Show Ruler" id="vLm-3I-IUL">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="View" id="H8h-7b-M4v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
||||
<items>
|
||||
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
||||
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="p" id="OY7-WF-poV">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||
<items>
|
||||
<menuItem title="macOS Demo Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||
<connections>
|
||||
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||
</connections>
|
||||
</application>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="macOS_Demo" customModuleProvider="target"/>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="0.0"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||
<window key="window" title="DownView" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="IQv-IB-iLA">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" texturedBackground="YES" fullSizeContentView="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
|
||||
</connections>
|
||||
</window>
|
||||
<connections>
|
||||
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
|
||||
</connections>
|
||||
</windowController>
|
||||
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="74" y="247"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="hIz-AP-VOD">
|
||||
<objects>
|
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="macOS_Demo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="900" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<visualEffectView appearanceType="inheritedVibrantLight" blendingMode="withinWindow" material="titlebar" state="active" translatesAutoresizingMaskIntoConstraints="NO" id="mkd-yO-PAt">
|
||||
<rect key="frame" x="0.0" y="578" width="900" height="22"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="22" id="KaJ-za-bSI"/>
|
||||
</constraints>
|
||||
</visualEffectView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="mkd-yO-PAt" secondAttribute="trailing" id="ETW-Wk-5Bo"/>
|
||||
<constraint firstItem="mkd-yO-PAt" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="Shf-qK-e0N"/>
|
||||
<constraint firstItem="mkd-yO-PAt" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="Th9-5p-z2m"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="74" y="845"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016-2019 Down. All rights reserved.</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// macOS Demo
|
||||
//
|
||||
// Created by Chris Zielinski on 10/27/18.
|
||||
// Copyright © 2016-2019 Down. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import Down
|
||||
|
||||
final class ViewController: NSViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
renderDownInWebView()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension ViewController {
|
||||
|
||||
func renderDownInWebView() {
|
||||
let readMeURL = Bundle.main.url(forResource: nil, withExtension: "md")!
|
||||
let readMeContents = try! String(contentsOf: readMeURL)
|
||||
|
||||
do {
|
||||
let downView = try DownView(frame: view.bounds, markdownString: readMeContents, didLoadSuccessfully: {
|
||||
print("Markdown was rendered.")
|
||||
})
|
||||
downView.autoresizingMask = [.width, .height]
|
||||
view.addSubview(downView, positioned: .below, relativeTo: nil)
|
||||
} catch {
|
||||
NSApp.presentError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?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>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+13
-12
@@ -1,22 +1,23 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Down"
|
||||
spec.summary = "Blazing fast Markdown rendering in Swift, built upon cmark."
|
||||
spec.version = "0.5.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/{cmark,Enums & Options,Extensions,Renderers}/**", "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_path = 'Source/cmark/module.modulemap'
|
||||
spec.pod_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(SRCROOT)/Down/Source/cmark/**' }
|
||||
spec.ios.resource = 'Resources/DownView.bundle'
|
||||
spec.osx.resource = 'Resources/DownView.bundle'
|
||||
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
|
||||
|
||||
+592
-63
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Down.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?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/>
|
||||
</plist>
|
||||
@@ -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 = "0900"
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,9 +26,17 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
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">
|
||||
@@ -41,23 +49,11 @@
|
||||
</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"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -73,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,55 +1,82 @@
|
||||
## Down
|
||||
[](https://travis-ci.org/iwasrobbed/Down)
|
||||
[](https://github.com/iwasrobbed/Down/blob/master/LICENSE)
|
||||
[]()
|
||||
[](https://swift.org)
|
||||
[](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 rendering in Swift, built upon [cmark](https://github.com/jgm/cmark).
|
||||
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
|
||||
|
||||
- [John Nguyen](https://github.com/johnxnguyen)
|
||||
- [Rob Phillips](https://github.com/iwasrobbed)
|
||||
- [Keaton Burleson](https://github.com/128keaton)
|
||||
- [Other contributors](https://github.com/iwasrobbed/Down/graphs/contributors) 🙌
|
||||
- [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/johnxnguyen/Down/graphs/contributors) 🙌
|
||||
|
||||
### Installation
|
||||
|
||||
Note: Swift 4 support is now on the `master` branch and any tag >= 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.
|
||||
Due to limitations in Carthage regarding platform specification, you need to define the platform with Carthage.
|
||||
|
||||
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
|
||||
|
||||
### Robust Performance
|
||||
|
||||
>[cmark](https://github.com/jgm/cmark) can render a Markdown version of War and Peace in the blink of an eye (127 milliseconds on a ten year old laptop, vs. 100-400 milliseconds for an eye blink). In our [benchmarks](https://github.com/jgm/cmark/blob/master/benchmarks.md), cmark is 10,000 times faster than the original Markdown.pl, and on par with the very fastest available Markdown processors.
|
||||
>[cmark](https://github.com/commonmark/cmark) can render a Markdown version of War and Peace in the blink of an eye (127 milliseconds on a ten year old laptop, vs. 100-400 milliseconds for an eye blink). In our [benchmarks](https://github.com/commonmark/cmark/blob/master/benchmarks.md), cmark is 10,000 times faster than the original Markdown.pl, and on par with the very fastest available Markdown processors.
|
||||
|
||||
> The library has been extensively fuzz-tested using [american fuzzy lop](http://lcamtuf.coredump.cx/afl). The test suite includes pathological cases that bring many other Markdown parsers to a crawl (for example, thousands-deep nested bracketed text or block quotes).
|
||||
|
||||
@@ -82,35 +109,32 @@ Meta example of rendering this README:
|
||||
|
||||

|
||||
|
||||
##### 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).
|
||||
|
||||
### Parsing API
|
||||
|
||||
The `Down` struct has everything you need if you just want out-of-the-box setup for parsing and conversion.
|
||||
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()
|
||||
@@ -159,6 +183,17 @@ public struct MarkdownToHTML: DownHTMLRenderable {
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration of `DownView`
|
||||
|
||||
`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/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/johnxnguyen/Down/pull/30).
|
||||
|
||||
### Options
|
||||
|
||||
Each protocol has options that will influence either rendering or parsing:
|
||||
@@ -186,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
|
||||
|
||||
/**
|
||||
@@ -207,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
|
||||
@@ -220,6 +268,6 @@ Down is built upon the [CommonMark](http://commonmark.org) specification.
|
||||
Please feel free to fork and create a pull request for bug fixes or improvements, being sure to maintain the general coding style, adding tests, and adding comments as necessary.
|
||||
|
||||
### Credit
|
||||
This library is a wrapper around [cmark](https://github.com/jgm/cmark), which is built upon the [CommonMark](http://commonmark.org) Markdown specification.
|
||||
This library is a wrapper around [cmark](https://github.com/commonmark/cmark), which is built upon the [CommonMark](http://commonmark.org) Markdown specification.
|
||||
|
||||
[cmark](https://github.com/jgm/cmark) is Copyright (c) 2014 - 2017, John MacFarlane. View [full license](https://github.com/jgm/cmark/blob/master/COPYING).
|
||||
[cmark](https://github.com/commonmark/cmark) is Copyright (c) 2014, John MacFarlane. View [full license](https://github.com/commonmark/cmark/blob/master/COPYING).
|
||||
|
||||
@@ -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,30 +0,0 @@
|
||||
//
|
||||
// Down.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Down: DownASTRenderable, DownHTMLRenderable, DownXMLRenderable,
|
||||
DownLaTeXRenderable, DownGroffRenderable, DownCommonMarkRenderable,
|
||||
DownAttributedStringRenderable {
|
||||
/**
|
||||
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
|
||||
|
||||
- parameter markdownString: A string containing CommonMark Markdown
|
||||
|
||||
- returns: An instance of Self
|
||||
*/
|
||||
|
||||
public init(markdownString: String) {
|
||||
self.markdownString = markdownString
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// DownErrors.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum DownErrors: Error {
|
||||
/**
|
||||
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
|
||||
*/
|
||||
case astRenderingError
|
||||
|
||||
/**
|
||||
Thrown when an HTML string cannot be converted into an `NSData` representation
|
||||
*/
|
||||
case htmlDataConversionError
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
//
|
||||
// DownOptions.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public struct DownOptions: OptionSet {
|
||||
public let rawValue: Int32
|
||||
public init(rawValue: Int32) { self.rawValue = rawValue }
|
||||
|
||||
/**
|
||||
Default options
|
||||
*/
|
||||
public static let `default` = DownOptions(rawValue: CMARK_OPT_DEFAULT)
|
||||
|
||||
// MARK: - Rendering Options
|
||||
|
||||
/**
|
||||
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:`,
|
||||
`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.
|
||||
*/
|
||||
public static let safe = DownOptions(rawValue: CMARK_OPT_SAFE)
|
||||
|
||||
// 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)
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
//
|
||||
// DownASTRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownASTRenderable: DownRenderable {
|
||||
/**
|
||||
Generates an abstract syntax tree from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
|
||||
- throws: `MarkdownToASTError` if conversion fails
|
||||
|
||||
- returns: An abstract syntax tree representation of the Markdown input
|
||||
*/
|
||||
|
||||
func toAST(_ options: DownOptions) throws -> UnsafeMutablePointer<cmark_node>
|
||||
}
|
||||
|
||||
public extension DownASTRenderable {
|
||||
/**
|
||||
Generates an abstract syntax tree from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- throws: `MarkdownToASTError` if conversion fails
|
||||
|
||||
- returns: An abstract syntax tree representation of the Markdown input
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- throws: `MarkdownToASTError` if conversion fails
|
||||
|
||||
- returns: An abstract syntax tree representation of the Markdown input
|
||||
*/
|
||||
|
||||
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,46 +0,0 @@
|
||||
//
|
||||
// DownAttributedStringRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownAttributedStringRenderable: DownHTMLRenderable {
|
||||
/**
|
||||
Generates an `NSAttributedString` from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
|
||||
- parameter stylesheet: a `String` to use as a CSS stylesheet when rendering
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: An `NSAttributedString`
|
||||
*/
|
||||
|
||||
func toAttributedString(_ options: DownOptions, stylesheet: String?) throws -> NSAttributedString
|
||||
}
|
||||
|
||||
public extension DownAttributedStringRenderable {
|
||||
/**
|
||||
Generates an `NSAttributedString` from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- parameter stylesheet: a `String` to use as the CSS stylesheet when rendering, defaulting to a style that uses the `NSAttributedString` default font
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: An `NSAttributedString`
|
||||
*/
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// DownCommonMarkRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownCommonMarkRenderable: DownRenderable {
|
||||
/**
|
||||
Generates a CommonMark Markdown string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
- parameter width: The width to break on
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: CommonMark Markdown string
|
||||
*/
|
||||
|
||||
func toCommonMark(_ options: DownOptions, width: Int32) throws -> String
|
||||
}
|
||||
|
||||
public extension DownCommonMarkRenderable {
|
||||
/**
|
||||
Generates a CommonMark Markdown string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
- parameter width: The width to break on, defaulting to 0
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: CommonMark Markdown string
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
**Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
- parameter width: The width to break on, defaulting to 0
|
||||
|
||||
- throws: `ASTRenderingError` if the AST could not be converted
|
||||
|
||||
- returns: CommonMark Markdown string
|
||||
*/
|
||||
|
||||
public static func astToCommonMark(_ ast: UnsafeMutablePointer<cmark_node>,
|
||||
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) }
|
||||
|
||||
guard let commonMarkString = String(cString: cCommonMarkString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return commonMarkString
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// DownGroffRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownGroffRenderable: DownRenderable {
|
||||
/**
|
||||
Generates a groff man string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
- parameter width: The width to break on
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: groff man string
|
||||
*/
|
||||
|
||||
func toGroff(_ options: DownOptions, width: Int32) throws -> String
|
||||
}
|
||||
|
||||
public extension DownGroffRenderable {
|
||||
/**
|
||||
Generates a groff man string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
- parameter width: The width to break on, defaulting to 0
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: groff man string
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
**Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
- parameter width: The width to break on, defaulting to 0
|
||||
|
||||
- throws: `ASTRenderingError` if the AST could not be converted
|
||||
|
||||
- returns: groff man string
|
||||
*/
|
||||
|
||||
public static func astToGroff(_ ast: UnsafeMutablePointer<cmark_node>,
|
||||
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) }
|
||||
|
||||
guard let groffString = String(cString: cGroffString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return groffString
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
//
|
||||
// DownHTMLRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/28/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownHTMLRenderable: DownRenderable {
|
||||
/**
|
||||
Generates an HTML string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: HTML string
|
||||
*/
|
||||
|
||||
func toHTML(_ options: DownOptions) throws -> String
|
||||
}
|
||||
|
||||
public extension DownHTMLRenderable {
|
||||
/**
|
||||
Generates an HTML string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: HTML string
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
**Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- throws: `ASTRenderingError` if the AST could not be converted
|
||||
|
||||
- returns: HTML string
|
||||
*/
|
||||
|
||||
public static func astToHTML(_ ast: UnsafeMutablePointer<cmark_node>, options: DownOptions = .default) throws -> String {
|
||||
guard let cHTMLString = cmark_render_html(ast, options.rawValue) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cHTMLString) }
|
||||
|
||||
guard let htmlString = String(cString: cHTMLString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return htmlString
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// DownLaTeXRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownLaTeXRenderable: DownRenderable {
|
||||
/**
|
||||
Generates a LaTeX string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
- parameter width: The width to break on
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: LaTeX string
|
||||
*/
|
||||
|
||||
func toLaTeX(_ options: DownOptions, width: Int32) throws -> String
|
||||
}
|
||||
|
||||
public extension DownLaTeXRenderable {
|
||||
/**
|
||||
Generates a LaTeX string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
- parameter width: The width to break on, defaulting to 0
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: LaTeX string
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
**Note:** caller is responsible for calling `cmark_node_free(ast)` after this returns
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
- parameter width: The width to break on, defaulting to 0
|
||||
|
||||
- throws: `ASTRenderingError` if the AST could not be converted
|
||||
|
||||
- returns: LaTeX string
|
||||
*/
|
||||
|
||||
public static func astToLaTeX(_ ast: UnsafeMutablePointer<cmark_node>,
|
||||
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) }
|
||||
|
||||
guard let latexString = String(cString: cLatexString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return latexString
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
//
|
||||
// DownXMLRenderable.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 5/31/16.
|
||||
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public protocol DownXMLRenderable: DownRenderable {
|
||||
/**
|
||||
Generates an XML string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: XML string
|
||||
*/
|
||||
|
||||
func toXML(_ options: DownOptions) throws -> String
|
||||
}
|
||||
|
||||
public extension DownXMLRenderable {
|
||||
/**
|
||||
Generates an XML string from the `markdownString` property
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- throws: `DownErrors` depending on the scenario
|
||||
|
||||
- returns: XML string
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
|
||||
|
||||
- throws: `ASTRenderingError` if the AST could not be converted
|
||||
|
||||
- returns: XML string
|
||||
*/
|
||||
|
||||
public static func astToXML(_ ast: UnsafeMutablePointer<cmark_node>, options: DownOptions = .default) throws -> String {
|
||||
guard let cXMLString = cmark_render_xml(ast, options.rawValue) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
defer { free(cXMLString) }
|
||||
|
||||
guard let xmlString = String(cString: cXMLString, encoding: String.Encoding.utf8) else {
|
||||
throw DownErrors.astRenderingError
|
||||
}
|
||||
|
||||
return xmlString
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
//
|
||||
// DownView.swift
|
||||
// Down
|
||||
//
|
||||
// Created by Rob Phillips on 6/1/16.
|
||||
// Copyright © 2016 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
|
||||
|
||||
- parameter frame: The frame size of the web view
|
||||
- parameter markdownString: A string containing CommonMark Markdown
|
||||
- parameter openLinksInBrowser: Whether or not to open links using an external browser
|
||||
- parameter templateBundle: Optional custom template bundle. Leaving this as `nil` will use the bundle included with Down.
|
||||
- parameter didLoadSuccessfully: Optional callback for when the web content has loaded successfully
|
||||
|
||||
- returns: An instance of Self
|
||||
*/
|
||||
public init(frame: CGRect, markdownString: String, openLinksInBrowser: Bool = true, templateBundle: Bundle? = 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: WKWebViewConfiguration())
|
||||
|
||||
if openLinksInBrowser || didLoadSuccessfully != nil { navigationDelegate = self }
|
||||
try loadHTMLView(markdownString)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - API
|
||||
|
||||
/**
|
||||
Renders the given CommonMark Markdown string into HTML and updates the DownView while keeping the style intact
|
||||
|
||||
- parameter markdownString: A string containing CommonMark Markdown
|
||||
- parameter 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
|
||||
|
||||
fileprivate lazy var baseURL: URL = {
|
||||
return self.bundle.url(forResource: "index", withExtension: "html")!
|
||||
}()
|
||||
|
||||
fileprivate var didLoadSuccessfully: DownViewClosure?
|
||||
}
|
||||
|
||||
// MARK: - Private API
|
||||
|
||||
private extension DownView {
|
||||
|
||||
func loadHTMLView(_ markdownString: String) throws {
|
||||
let htmlString = try markdownString.toHTML()
|
||||
let pageHTMLString = try htmlFromTemplate(htmlString)
|
||||
loadHTMLString(pageHTMLString, baseURL: baseURL)
|
||||
}
|
||||
|
||||
func htmlFromTemplate(_ htmlString: String) throws -> String {
|
||||
let template = try NSString(contentsOf: baseURL, encoding: String.Encoding.utf8.rawValue)
|
||||
return template.replacingOccurrences(of: "DOWN_HTML", with: htmlString)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - WKNavigationDelegate
|
||||
|
||||
extension DownView: WKNavigationDelegate {
|
||||
|
||||
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||
guard let url = navigationAction.request.url else { return }
|
||||
|
||||
switch navigationAction.navigationType {
|
||||
case .linkActivated:
|
||||
decisionHandler(.cancel)
|
||||
#if os(iOS)
|
||||
UIApplication.shared.openURL(url)
|
||||
#elseif os(OSX)
|
||||
NSWorkspace.shared.open(url)
|
||||
#endif
|
||||
default:
|
||||
decisionHandler(.allow)
|
||||
}
|
||||
}
|
||||
|
||||
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
didLoadSuccessfully?()
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef CMARK_VERSION_H
|
||||
#define CMARK_VERSION_H
|
||||
|
||||
#define CMARK_VERSION ((0 << 16) | (25 << 8) | 2)
|
||||
#define CMARK_VERSION_STRING "0.25.2"
|
||||
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef CMARK_DEBUG_H
|
||||
#define CMARK_DEBUG_H
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define debug(M, ...)
|
||||
#else
|
||||
#define debug(M, ...) \
|
||||
fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define log_err(M, ...) \
|
||||
fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \
|
||||
clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_warn(M, ...) \
|
||||
fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \
|
||||
clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, \
|
||||
__LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define check(A, M, ...) \
|
||||
if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||
|
||||
#define sentinel(M, ...) \
|
||||
{ log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||
|
||||
#define check_debug(A, M, ...) \
|
||||
if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
#ifndef CMARK_INLINES_H
|
||||
#define CMARK_INLINES_H
|
||||
|
||||
#import "references.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
cmark_chunk cmark_clean_url(cmark_chunk *url);
|
||||
cmark_chunk cmark_clean_title(cmark_chunk *title);
|
||||
|
||||
void cmark_parse_inlines(cmark_node *parent, cmark_reference_map *refmap,
|
||||
int options);
|
||||
|
||||
bufsize_t cmark_parse_reference_inline(cmark_strbuf *input,
|
||||
cmark_reference_map *refmap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
-21263
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// BlockQuote.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Code.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// CodeBlock.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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.
|
||||
///
|
||||
/// For example:
|
||||
/// ```
|
||||
/// '''<fence info>
|
||||
/// <literal>
|
||||
/// '''
|
||||
/// ```
|
||||
///
|
||||
|
||||
public private(set) lazy var fenceInfo: String? = cmarkNode.fenceInfo
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension CodeBlock: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
let content = (literal ?? "nil").replacingOccurrences(of: "\n", with: "\\n")
|
||||
return "Code Block - fenceInfo: \(fenceInfo ?? "nil"), content: \(content)"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// CustomBlock.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// CustomInline.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Document.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Document: BaseNode {
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
deinit {
|
||||
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"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Emphasis.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Emphasis: BaseNode {}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Emphasis: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Emphasis"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Heading.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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)"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// HtmlBlock.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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 {
|
||||
let content = (literal ?? "nil").replacingOccurrences(of: "\n", with: "\\n")
|
||||
return "Html Block - content: \(content)"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// HtmlInline.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Image.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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
|
||||
/// bottom. `<text>` is literal text belonging to children nodes. The title occurs
|
||||
/// after the url and is optional.
|
||||
///
|
||||
/// ```
|
||||
/// ![<text>][<id>]
|
||||
/// ...
|
||||
/// [<id>]: <url> "<title>"
|
||||
/// ```
|
||||
|
||||
public private(set) lazy var title: String? = cmarkNode.title
|
||||
|
||||
/// The url of the image, if present.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```
|
||||
/// 
|
||||
/// ```
|
||||
|
||||
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"))"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Item.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Item: BaseNode {}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Item: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Item"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// LineBreak.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class LineBreak: BaseNode {}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension LineBreak: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Line Break"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Link.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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
|
||||
/// bottom. `<text>` is literal text belonging to children nodes. The title occurs
|
||||
/// after the url and is optional.
|
||||
///
|
||||
/// ```
|
||||
/// [<text>][<id>]
|
||||
/// ...
|
||||
/// [<id>]: <url> "<title>"
|
||||
/// ```
|
||||
|
||||
public private(set) lazy var title: String? = cmarkNode.title
|
||||
|
||||
/// The url of the link, if present.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```
|
||||
/// [<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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// Node.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 07.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
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 CMarkNode {
|
||||
|
||||
/// Wraps the cmark node referred to by this pointer.
|
||||
|
||||
func wrap() -> Node? {
|
||||
switch type {
|
||||
case CMARK_NODE_DOCUMENT: return Document(cmarkNode: self)
|
||||
case CMARK_NODE_BLOCK_QUOTE: return BlockQuote(cmarkNode: self)
|
||||
case CMARK_NODE_LIST: return List(cmarkNode: self)
|
||||
case CMARK_NODE_ITEM: return Item(cmarkNode: self)
|
||||
case CMARK_NODE_CODE_BLOCK: return CodeBlock(cmarkNode: self)
|
||||
case CMARK_NODE_HTML_BLOCK: return HtmlBlock(cmarkNode: self)
|
||||
case CMARK_NODE_CUSTOM_BLOCK: return CustomBlock(cmarkNode: self)
|
||||
case CMARK_NODE_PARAGRAPH: return Paragraph(cmarkNode: self)
|
||||
case CMARK_NODE_HEADING: return Heading(cmarkNode: self)
|
||||
case CMARK_NODE_THEMATIC_BREAK: return ThematicBreak(cmarkNode: self)
|
||||
case CMARK_NODE_TEXT: return Text(cmarkNode: self)
|
||||
case CMARK_NODE_SOFTBREAK: return SoftBreak(cmarkNode: self)
|
||||
case CMARK_NODE_LINEBREAK: return LineBreak(cmarkNode: self)
|
||||
case CMARK_NODE_CODE: return Code(cmarkNode: self)
|
||||
case CMARK_NODE_HTML_INLINE: return HtmlInline(cmarkNode: self)
|
||||
case CMARK_NODE_CUSTOM_INLINE: return CustomInline(cmarkNode: self)
|
||||
case CMARK_NODE_EMPH: return Emphasis(cmarkNode: self)
|
||||
case CMARK_NODE_STRONG: return Strong(cmarkNode: self)
|
||||
case CMARK_NODE_LINK: return Link(cmarkNode: self)
|
||||
case CMARK_NODE_IMAGE: return Image(cmarkNode: self)
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Paragraph.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Paragraph: BaseNode {}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Paragraph: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Paragraph"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// SoftBreak.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class SoftBreak: BaseNode {}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension SoftBreak: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Soft Break"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Strong.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
public class Strong: BaseNode {}
|
||||
|
||||
// MARK: - Debug
|
||||
|
||||
extension Strong: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
return "Strong"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Text.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
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")"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// ThematicBreak.swift
|
||||
// Down
|
||||
//
|
||||
// Created by John Nguyen on 09.04.19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libcmark
|
||||
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user