{"id":31557972,"url":"https://github.com/sergeikriukov/markdowntoattributedstring","last_synced_at":"2026-04-11T08:03:01.260Z","repository":{"id":317997134,"uuid":"1064149547","full_name":"SergeiKriukov/MarkdownToAttributedString","owner":"SergeiKriukov","description":"A powerful Swift library for converting Markdown text to NSAttributedString with full formatting support. Cross-platform compatible for iOS, macOS, tvOS, and watchOS.","archived":false,"fork":false,"pushed_at":"2025-10-04T11:20:32.000Z","size":70,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-04T12:27:58.073Z","etag":null,"topics":["attributedstring","formatting","ios","macos","markdown","rtf","swift","text-processing","vibe-coding"],"latest_commit_sha":null,"homepage":"https://lawmatic.ru","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SergeiKriukov.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-25T15:59:21.000Z","updated_at":"2025-10-04T11:20:35.000Z","dependencies_parsed_at":"2025-10-04T12:28:03.555Z","dependency_job_id":"4e91b21a-eb41-445d-9546-b5e5987f9698","html_url":"https://github.com/SergeiKriukov/MarkdownToAttributedString","commit_stats":null,"previous_names":["sergeikriukov/markdowntoattributedstring"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/SergeiKriukov/MarkdownToAttributedString","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergeiKriukov%2FMarkdownToAttributedString","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergeiKriukov%2FMarkdownToAttributedString/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergeiKriukov%2FMarkdownToAttributedString/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergeiKriukov%2FMarkdownToAttributedString/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SergeiKriukov","download_url":"https://codeload.github.com/SergeiKriukov/MarkdownToAttributedString/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergeiKriukov%2FMarkdownToAttributedString/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278391399,"owners_count":25978981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attributedstring","formatting","ios","macos","markdown","rtf","swift","text-processing","vibe-coding"],"created_at":"2025-10-05T00:10:29.081Z","updated_at":"2026-04-11T08:03:01.254Z","avatar_url":"https://github.com/SergeiKriukov.png","language":"Swift","readme":"# MarkdownToAttributedString\n\n[![Swift](https://img.shields.io/badge/Swift-5.9+-orange.svg)](https://swift.org)\n[![Platform](https://img.shields.io/badge/Platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS-blue.svg)](https://developer.apple.com/swift/)\n[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n\nA powerful Swift library for converting Markdown text to `NSAttributedString` with full formatting support. Perfect for iOS, macOS, tvOS, and watchOS applications that need to display rich text from Markdown sources.\n\n\u003cimg width=\"826\" height=\"804\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ea839987-82b4-443c-a431-fbf7117e235f\" /\u003e\n\n\n## ✨ Features\n\n- 🎯 **Complete Markdown Support** - Headers, bold, italic, strikethrough, code, lists, links, images, blockquotes\n- 🎨 **Customizable Styling** - Configure fonts, sizes, colors, and weights for each element\n- 📱 **Cross-Platform** - Works on iOS, macOS, tvOS, and watchOS\n- 🚀 **High Performance** - Optimized parsing and conversion\n- 🔧 **Easy Integration** - Simple API with Swift Package Manager support\n- 📝 **RTF Export** - Convert to Rich Text Format for document sharing\n- 📄 **Plain Text Export** - Extract clean text without formatting\n\n## 🚀 Quick Start\n\n### Installation\n\nAdd MarkdownToAttributedString to your project using Swift Package Manager:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/SergeiKriukov/MarkdownToAttributedString.git\", from: \"1.0.0\")\n]\n```\n\n### Basic Usage\n\n```swift\nimport MarkdownToAttributedString\n\nlet markdown = \"\"\"\n# Welcome to MarkdownToAttributedString\n\nThis is **bold** and *italic* text with `inline code`.\nYou can also use ~~strikethrough~~ formatting.\n\n## Features\n- Easy to use\n- Highly customizable\n- Cross-platform support\n\n\u003e This is a blockquote with **bold** text inside.\n\"\"\"\n\n// Convert with default styling\nlet attributedString = markdown.toAttributedString()\n\n// Or use custom configuration\nlet customConfig = MarkdownConfiguration(\n    h1: .init(fontSize: 28, fontWeight: .bold),\n    bold: .init(fontWeight: .bold, isItalic: false)\n)\nlet customAttributedString = markdown.toAttributedString(configuration: customConfig)\n```\n\n## 🎨 Customization\n\n### Styling Configuration\n\n```swift\nlet config = MarkdownConfiguration(\n    // Header styles\n    h1: .init(fontSize: 24, fontWeight: .bold),\n    h2: .init(fontSize: 20, fontWeight: .semibold),\n    h3: .init(fontSize: 18, fontWeight: .medium),\n\n    // Text formatting\n    bold: .init(fontWeight: .bold),\n    italic: .init(isItalic: true),\n    strikethrough: .init(),\n    code: .init(fontSize: 14, fontWeight: .regular),\n\n    // List and blockquote styling\n    listPrefix: .init(fontWeight: .semibold),\n    blockquote: .init()\n)\n\nlet attributedString = markdown.toAttributedString(configuration: config)\n```\n\n### Available Style Properties\n\n- `fontSize` - Text size in points\n- `fontWeight` - Font weight (regular, bold, semibold, light)\n- `isItalic` - Italic text styling\n- `foregroundColor` - Text color (iOS/macOS)\n\n## 📋 Supported Markdown Elements\n\n| Element | Example | Status |\n|---------|---------|--------|\n| Headers | `# H1`, `## H2`, `### H3` | ✅ |\n| Bold | `**bold text**` | ✅ |\n| Italic | `*italic text*` | ✅ |\n| Strikethrough | `~~strikethrough~~` | ✅ |\n| Inline Code | `` `code` `` | ✅ |\n| Code Blocks | ```` ```code``` ```` | ✅ |\n| Links | `[text](url)` | ✅ |\n| Images | `![alt](url)` | ✅ |\n| Lists | `- item`, `1. item` | ✅ |\n| Blockquotes | `\u003e quote text` | ✅ |\n| Line Breaks | `\\n` | ✅ |\n\n## 🔧 Advanced Usage\n\n### Manual Conversion\n\n```swift\nimport MarkdownToAttributedString\n\nlet parser = MarkdownParser()\nlet converter = AttributedStringConverter()\n\n// Parse markdown into elements\nlet elements = parser.parse(markdown)\n\n// Convert to attributed string\nlet attributedString = converter.convert(elements)\n```\n\n### Export to RTF\n\n```swift\nlet attributedString = markdown.toAttributedString()\n\n// Export to RTF data\nlet rtfData = try attributedString.data(\n    from: NSRange(location: 0, length: attributedString.length),\n    documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf]\n)\n\n// Save to file\ntry rtfData.write(to: fileURL)\n```\n\n### Extract Plain Text\n\n```swift\nlet attributedString = markdown.toAttributedString()\nlet plainText = attributedString.string\n// Result: \"Welcome to MarkdownToAttributedString\\nThis is bold and italic text...\"\n```\n\n## 📱 Platform Support\n\n| Platform | Minimum Version | Status |\n|----------|----------------|--------|\n| iOS | 15.0+ | ✅ |\n| macOS | 12.0+ | ✅ |\n| tvOS | 15.0+ | ✅ |\n| watchOS | 8.0+ | ✅ |\n\n## 🧪 Testing\n\nThe library includes comprehensive tests for all supported Markdown elements:\n\n```bash\nswift test\n```\n\n## 📖 Examples\n\n### iOS App Integration\n\n```swift\nimport SwiftUI\nimport MarkdownToAttributedString\n\nstruct ContentView: View {\n    @State private var markdown = \"# Hello World\\nThis is **bold** text\"\n    \n    var body: some View {\n        VStack {\n            TextEditor(text: $markdown)\n                .frame(height: 200)\n            \n            Text(AttributedString(markdown.toAttributedString()))\n                .frame(maxWidth: .infinity, alignment: .leading)\n        }\n    }\n}\n```\n\n### macOS App with Export\n\n```swift\nimport AppKit\nimport MarkdownToAttributedString\n\nclass DocumentController: NSDocumentController {\n    func exportToRTF(_ markdown: String) {\n        let attributedString = markdown.toAttributedString()\n        \n        let savePanel = NSSavePanel()\n        savePanel.allowedContentTypes = [.rtf]\n        \n        savePanel.begin { response in\n            if response == .OK, let url = savePanel.url {\n                do {\n                    let rtfData = try attributedString.data(\n                        from: NSRange(location: 0, length: attributedString.length),\n                        documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf]\n                    )\n                    try rtfData.write(to: url)\n                } catch {\n                    print(\"Export failed: \\(error)\")\n                }\n            }\n        }\n    }\n}\n```\n\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.\n\n### Development Setup\n\n1. Clone the repository\n2. Open in Xcode or use Swift Package Manager\n3. Run tests: `swift test`\n4. Build the example: `swift build`\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🗺️ **Roadmap \u0026 Future Features**\n\n### 🚀 **Version 2.1.0 - Typography \u0026 Accessibility (Q2 2025)**\n\n#### ✨ Dynamic Type Support\nАвтоматическая адаптация размера шрифта под системные настройки пользователя.\n\n```swift\n// Будущий API\nlet config = MarkdownConfiguration.dynamicType(\n    h1: .init(fontWeight: .bold),\n    body: .init(fontSize: .body) // .largeTitle, .title1, .body, .caption etc.\n)\n\nlet attributedString = markdown.toAttributedString(\n    configuration: config,\n    traitCollection: UITraitCollection(preferredContentSizeCategory: .extraLarge)\n)\n```\n\n**Реализация:**\n- Расширение `MarkdownStyle` с `FontSize` enum\n- Добавление метода `dynamicType()` в `MarkdownConfiguration`\n- Интеграция с `UITraitCollection` для автоматической адаптации\n\n#### 🎯 Custom Bullets for Lists\nВозможность использовать кастомные маркеры вместо стандартных.\n\n```swift\nlet config = MarkdownConfiguration(\n    listPrefix: .init(\n        unorderedSymbols: [\"🍎\", \"🍌\", \"🍇\"], // Для разных уровней вложенности\n        orderedStyle: .circledNumbers // .numbers, .letters, .roman, .circledNumbers\n    )\n)\n\n// Markdown: - Item 1\\n  - Item 2\\n    - Item 3\n// Результат: 🍎 Item 1\\n  🍌 Item 2\\n    🍇 Item 3\n```\n\n**Реализация:**\n- Добавление `unorderedSymbols` и `orderedStyle` в `MarkdownConfiguration`\n- Расширение `MarkdownElementType.unorderedList` с уровнем вложенности\n- Логика выбора символа по уровню в `AttributedStringConverter`\n\n### 🔮 **Version 2.2.0 - Advanced Markdown (Q3 2025)**\n\n#### 📝 Front Matter / YAML Support\nПоддержка метаданных в начале Markdown файлов.\n\n```yaml\n---\ntitle: \"My Document\"\nauthor: \"John Doe\"\ndate: \"2025-10-04\"\ntags: [\"markdown\", \"swift\"]\n---\n\n# Document Content\nThis is the actual content...\n```\n\n```swift\nif let frontMatter = markdown.frontMatter {\n    print(\"Title: \\(frontMatter[\"title\"] ?? \"\")\")\n    print(\"Author: \\(frontMatter[\"author\"] ?? \"\")\")\n}\n\n// Или получение чистого контента без метаданных\nlet cleanContent = markdown.contentWithoutFrontMatter\n```\n\n**Реализация:**\n- Класс `FrontMatterParser` для парсинга YAML\n- Расширение `String` с методами `frontMatter` и `contentWithoutFrontMatter`\n- Поддержка различных форматов разделителей (---, +++)\n\n#### 🔗 Referenced Links \u0026 Images\nРасширенный синтаксис для ссылок и изображений.\n\n```markdown\nThis is a [referenced link][1] and ![referenced image][2].\n\n[1]: https://example.com \"Optional title\"\n[2]: /path/to/image.png \"Alt text\"\n```\n\n**Реализация:**\n- Парсинг ссылок в конце документа\n- Создание словаря соответствий\n- Замена referenced синтаксиса на стандартный\n\n#### 📏 Line \u0026 Paragraph Spacing\nТочный контроль типографики.\n\n```swift\nlet config = MarkdownConfiguration(\n    h1: .init(lineSpacing: 8, paragraphSpacing: 16),\n    body: .init(lineSpacing: 4, paragraphSpacing: 8),\n    blockquote: .init(lineSpacing: 2, paragraphSpacing: 12)\n)\n```\n\n**Реализация:**\n- Добавление `lineSpacing` и `paragraphSpacing` в `MarkdownStyle`\n- Применение `NSMutableParagraphStyle` в `AttributedStringConverter`\n\n### 🌟 **Version 2.3.0 - Rich Content (Q4 2025)**\n\n#### 🖼️ Bundle Images Support\nПоддержка изображений из app bundle.\n\n```markdown\n![App Icon](\u003cAppIcon\u003e)\n![Custom Asset](\u003cmy-custom-image\u003e)\n```\n\n```swift\nlet config = MarkdownConfiguration(\n    image: .init(\n        bundle: Bundle.main,\n        placeholder: \"🖼️\" // Для изображений, которые не найдены\n    )\n)\n```\n\n**Реализация:**\n- Расширение `MarkdownElementType.image` с bundle поддержкой\n- Использование `NSTextAttachment` для встраивания изображений\n- Fallback на placeholder для отсутствующих изображений\n\n#### 📊 Tables Support\nБазовая поддержка таблиц Markdown.\n\n```markdown\n| Header 1 | Header 2 | Header 3 |\n|----------|----------|----------|\n| Cell 1   | Cell 2   | Cell 3   |\n| Cell 4   | Cell 5   | Cell 6   |\n```\n\n```swift\nlet config = MarkdownConfiguration(\n    table: .init(\n        headerStyle: .bold,\n        borderColor: .gray,\n        cellPadding: 8\n    )\n)\n```\n\n**Реализация:**\n- Парсер для table синтаксиса\n- Создание `NSTextTable` для табличного представления\n- Кастомизация стилей заголовков и ячеек\n\n### 🎨 **Version 3.0.0 - Advanced Customization (Q1 2026)**\n\n#### 🎭 Rules-Based Engine\nРасширяемая система правил для кастомных элементов.\n\n```swift\n// Создание кастомного правила\nlet mentionRule = CharacterRule(\n    pattern: \"@(\\\\w+)\",\n    style: .foregroundColor(.blue)\n)\n\n// Добавление в конфигурацию\nlet config = MarkdownConfiguration(\n    customRules: [mentionRule]\n)\n\n// Markdown: Hello @username!\n// Результат: Hello @username! (с синим цветом)\n```\n\n**Реализация:**\n- Протокол `MarkdownRule` для кастомных правил\n- Интеграция в основной парсер\n- Поддержка регулярных выражений и стилей\n\n#### 🎨 Font Style Enum\nБолее точный контроль стилей шрифтов.\n\n```swift\nlet config = MarkdownConfiguration(\n    h1: .init(fontStyle: .boldItalic, fontSize: 24),\n    code: .init(fontStyle: .monospaced),\n    link: .init(fontStyle: .underlined)\n)\n```\n\n**Реализация:**\n- Enum `FontStyle` (.normal, .bold, .italic, .boldItalic, .monospaced, .underlined)\n- Расширение `MarkdownStyle` с `fontStyle` свойством\n- Применение через `UIFontDescriptor` и `NSFontDescriptor`\n\n#### 🌙 Dark Mode \u0026 Theme Support\nПолная поддержка тем и цветовых схем.\n\n```swift\nlet lightConfig = MarkdownConfiguration.lightTheme()\nlet darkConfig = MarkdownConfiguration.darkTheme()\n\n// Или кастомная тема\nlet customTheme = MarkdownTheme(\n    background: .systemBackground,\n    text: .label,\n    accent: .systemBlue\n)\n```\n\n**Реализация:**\n- Класс `MarkdownTheme` для цветовых схем\n- Методы `lightTheme()` и `darkTheme()` в `MarkdownConfiguration`\n- Интеграция с `UITraitCollection` и `NSAppearance`\n\n---\n\n## 🔗 **Similar Projects**\n\nIf you're looking for alternative Swift Markdown libraries, check out these excellent projects:\n\n### [SwiftyMarkdown](https://github.com/SimonFairbairn/SwiftyMarkdown) ⭐ 1.7k\n- **Author**: Simon Fairbairn\n- **Focus**: Comprehensive Markdown parsing with advanced customization\n- **Key Features**:\n  - Rules-based processing engine\n  - Front Matter / YAML support\n  - Dynamic Type support\n  - SpriteKit integration\n  - Extensive styling options\n- **Platforms**: iOS, macOS, tvOS, watchOS\n\n### [MarkdownKit](https://github.com/bmoliveira/MarkdownKit) ⭐ 871\n- **Author**: Bruno Oliveira\n- **Focus**: Lightweight and extensible Markdown parser\n- **Key Features**:\n  - Regular expression-based parsing\n  - Custom element support\n  - CocoaPods, Carthage, and SPM support\n  - Extensible architecture\n- **Platforms**: iOS, macOS\n\n### https://github.com/apparata/Markin\n\n\u003e **Note**: MarkdownToAttributedString was inspired by studying these projects and aims to provide a modern, Swift-first approach with comprehensive cross-platform support and detailed customization options.\n\n### https://github.com/LiYanan2004/MarkdownView\n\n---\n\n## 🙏 Acknowledgments\n\n- Inspired by the need for easy Markdown to NSAttributedString conversion\n- Built with Swift's powerful string processing capabilities\n- Thanks to the Swift community for excellent documentation and examples\n\n## 📞 Support\n\n- 🐛 **Bug Reports**: [GitHub Issues](https://github.com/SergeiKriukov/MarkdownToAttributedString/issues)\n- 💡 **Feature Requests**: [GitHub Discussions](https://github.com/SergeiKriukov/MarkdownToAttributedString/discussions)\n- 📧 **Contact**: [GitHub Profile](https://github.com/SergeiKriukov)\n\n---\n\nMade with ❤️ for the Swift community\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergeikriukov%2Fmarkdowntoattributedstring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsergeikriukov%2Fmarkdowntoattributedstring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergeikriukov%2Fmarkdowntoattributedstring/lists"}