معالجة Markdown في Swift لنظامي iOS و macOS: من التحليل إلى العرض
\n\nMarkdown هي واحدة من أشهر لغات الترميز لتنسيق النص. في نظام Swift البيئي (iOS/macOS)، توجد عدة مكتبات قوية تسمح بتحليل Markdown وتحويله وعرضه. في هذه المقالة، سنستعرض مكتبتين رئيسيتين: Down (سريعة ومرنة) و SwiftMarkdown (المكتبة الرسمية من Apple). ستتعلم كيفية دمجهما في مشاريعك، وتحويل Markdown إلى NSAttributedString و HTML، وعرضه في SwiftUI.
1. مكتبة Down (مبنية على cmark)
\n\nDown هي غلاف حول المحلل C الشهير cmark، مكتوبة بلغة Swift. توفر أداءً عاليًا وتدعم جميع عناصر Markdown الأساسية (العناوين، القوائم، الكود، الروابط، الصور، الجداول، إلخ).
التثبيت
\nأضف الحزمة عبر Swift Package Manager:
\n// Package.swift\ndependencies: [\n .package(url: "https://github.com/johnxnguyen/Down.git", from: "0.11.0")\n]\n\nمثال: تحويل Markdown إلى HTML
\nimport Down\n\nlet markdownString = "# مرحبًا، أيها العالم!\\n\\nهذا **نص غامق** و *مائل*."\nlet down = Down(markdownString: markdownString)\nlet html = try? down.toHTML()\nprint(html ?? "")\n// الإخراج: <h1>مرحبًا، أيها العالم!</h1>\\n<p>هذا <strong>نص غامق</strong> و <em>مائل</em>.</p>\n\nالعرض في NSAttributedString
\nيمكن لـ Down إنشاء NSAttributedString مباشرة للعرض في UILabel أو UITextView أو NSTextView:
let attributedString = try? down.toAttributedString()\n// استخدمه في UITextView:\ntextView.attributedText = attributedString\n\nدعم SwiftUI
\nلـ SwiftUI، يمكنك إنشاء غلاف يعرض AttributedString (iOS 15+):
struct MarkdownView: View {\n let markdown: String\n\n var body: some View {\n if let nsAttr = try? Down(markdownString: markdown).toAttributedString() {\n Text(AttributedString(nsAttr))\n } else {\n Text(markdown)\n }\n }\n}\n\n2. SwiftMarkdown (من Apple)
\n\nSwiftMarkdown هي المكتبة الرسمية من Apple، المضمنة في swift-markdown. توفر محلل Markdown كامل مع إمكانية التخصيص وتوليد تنسيقات مختلفة (HTML، CommonMark، AST).
التثبيت
\n// Package.swift\ndependencies: [\n .package(url: "https://github.com/apple/swift-markdown.git", branch: "main")\n]\n\nالتحليل والعمل مع AST
\nتقوم المكتبة ببناء شجرة نحوية مجردة (AST) يمكن تحليلها وتعديلها:
\nimport Markdown\n\nlet source = """\n# التوثيق\n\nقائمة الوظائف:\n- `foo()` — الوظيفة الأولى\n- `bar()` — الوظيفة الثانية\n"""\n\nlet document = Document(parsing: source)\nlet heading = document.child(at: 0) as? Heading\nprint(heading?.plainText ?? "") // "التوثيق"\n\n// اجتياز جميع العناصر\nfor child in document.children {\n if let list = child as? UnorderedList {\n for item in list.children {\n print((item as? ListItem)?.plainText ?? "")\n }\n }\n}\n\nتوليد HTML
\nlet html = document.format(options: [.unsafeTags])\nprint(html)\n// الإخراج: <h1>التوثيق</h1>...<ul><li><code>foo()</code> — الوظيفة الأولى</li>...\n\nالعرض عبر AttributedString (iOS 15+)
\nيدعم SwiftMarkdown التحويل المباشر إلى AttributedString باستخدام الأنماط:
import Markdown\nimport SwiftUI\n\nstruct ContentView: View {\n let markdown = "**هام**: انقر *هنا*."\n\n var body: some