apex-ruby 1.0.18 → 1.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/ext/apex_ext/apex_ext.c +260 -91
- data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
- data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
- data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
- data/ext/apex_ext/apex_src/Package.swift +15 -4
- data/ext/apex_ext/apex_src/README.md +94 -35
- data/ext/apex_ext/apex_src/VERSION +1 -1
- data/ext/apex_ext/apex_src/apex-debug.log +4 -0
- data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
- data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
- data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
- data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
- data/ext/apex_ext/apex_src/cli/main.c +262 -33
- data/ext/apex_ext/apex_src/debug.log +7 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
- data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
- data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
- data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
- data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
- data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
- data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
- data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
- data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
- data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
- data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
- data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
- data/ext/apex_ext/apex_src/include/apexc.h +1 -0
- data/ext/apex_ext/apex_src/man/apex.1 +82 -78
- data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
- data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
- data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
- data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
- data/ext/apex_ext/apex_src/output.html +87 -0
- data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
- data/ext/apex_ext/apex_src/src/_README.md +85 -32
- data/ext/apex_ext/apex_src/src/apex.c +770 -200
- data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
- data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
- data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
- data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
- data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
- data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
- data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
- data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
- data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
- data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
- data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
- data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
- data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
- data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
- data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
- data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
- data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
- data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
- data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
- data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
- data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
- data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
- data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
- data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
- data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
- data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
- data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
- data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
- data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
- data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
- data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
- data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
- data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
- data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
- data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
- data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
- data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
- data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
- data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
- data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
- data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
- data/ext/apex_ext/extconf.rb +35 -0
- data/lib/apex/version.rb +2 -2
- metadata +117 -2
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApexPlugins.swift
|
|
3
|
+
* Swift API for plugin catalog and installation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Foundation
|
|
7
|
+
@_exported import ApexObjC
|
|
8
|
+
|
|
9
|
+
/// Metadata for one Apex plugin (available or installed).
|
|
10
|
+
public struct ApexPluginInfo: Identifiable, Hashable, Sendable {
|
|
11
|
+
public let id: String
|
|
12
|
+
public let title: String?
|
|
13
|
+
public let description: String?
|
|
14
|
+
public let author: String?
|
|
15
|
+
public let homepage: String?
|
|
16
|
+
public let repo: String?
|
|
17
|
+
|
|
18
|
+
init(_ objc: ApexObjC.ApexPluginInfo) {
|
|
19
|
+
self.id = objc.pluginId
|
|
20
|
+
self.title = objc.title
|
|
21
|
+
self.description = objc.pluginDescription
|
|
22
|
+
self.author = objc.author
|
|
23
|
+
self.homepage = objc.homepage
|
|
24
|
+
self.repo = objc.repo
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Fetch, list, install, and uninstall Apex plugins from app code.
|
|
29
|
+
public enum ApexPluginManager {
|
|
30
|
+
/// Default `apex-plugins.json` URL.
|
|
31
|
+
public static var defaultDirectoryURL: String {
|
|
32
|
+
ApexPluginCatalog.defaultDirectoryURL
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// User-global plugins directory (`~/.config/apex/plugins` or XDG equivalent).
|
|
36
|
+
public static var globalPluginsDirectory: String? {
|
|
37
|
+
ApexPluginCatalog.globalPluginsDirectory()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Fetch plugins from the central Apex directory.
|
|
41
|
+
public static func fetchAvailable() throws -> [ApexPluginInfo] {
|
|
42
|
+
let items = try ApexPluginCatalog.fetchAvailablePlugins()
|
|
43
|
+
return items.map(ApexPluginInfo.init)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// Fetch plugins from a custom directory JSON URL.
|
|
47
|
+
public static func fetchAvailable(from url: String) throws -> [ApexPluginInfo] {
|
|
48
|
+
let items = try ApexPluginCatalog.fetchAvailablePlugins(fromURL: url)
|
|
49
|
+
return items.map(ApexPluginInfo.init)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// List installed plugins (project-scoped + user-global).
|
|
53
|
+
public static func installed(baseDirectory: String? = nil) -> [ApexPluginInfo] {
|
|
54
|
+
ApexPluginCatalog.installedPlugins(withBaseDirectory: baseDirectory)
|
|
55
|
+
.map(ApexPluginInfo.init)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Install a curated plugin by id from the central directory.
|
|
59
|
+
public static func install(id: String) throws {
|
|
60
|
+
try install(idOrRepository: id, allowUntrustedSource: false)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Install by directory id, Git URL, or GitHub `user/repo` shorthand.
|
|
64
|
+
public static func install(idOrRepository: String, allowUntrustedSource: Bool = false) throws {
|
|
65
|
+
if allowUntrustedSource {
|
|
66
|
+
try ApexPluginCatalog.installPlugin(
|
|
67
|
+
fromRepository: idOrRepository,
|
|
68
|
+
allowUntrustedSource: true
|
|
69
|
+
)
|
|
70
|
+
} else {
|
|
71
|
+
try ApexPluginCatalog.installPlugin(withId: idOrRepository)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Remove a plugin from the user-global plugins directory.
|
|
76
|
+
public static func uninstall(id: String) throws {
|
|
77
|
+
try ApexPluginCatalog.uninstallPlugin(withId: id)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -16,6 +16,7 @@ extern NSString * const ApexModeGFM;
|
|
|
16
16
|
extern NSString * const ApexModeMultiMarkdown;
|
|
17
17
|
extern NSString * const ApexModeKramdown;
|
|
18
18
|
extern NSString * const ApexModeUnified;
|
|
19
|
+
extern NSString * const ApexModeQuarto;
|
|
19
20
|
|
|
20
21
|
@interface NSString (Apex)
|
|
21
22
|
|
|
@@ -40,7 +41,7 @@ extern NSString * const ApexModeUnified;
|
|
|
40
41
|
/**
|
|
41
42
|
* Convert Markdown to HTML using Apex with specific processor mode
|
|
42
43
|
* @param inputString The markdown text to convert
|
|
43
|
-
* @param mode Processor mode: Use ApexMode* constants (ApexModeCommonmark, ApexModeGFM, ApexModeMultiMarkdown, ApexModeKramdown, or
|
|
44
|
+
* @param mode Processor mode: Use ApexMode* constants (ApexModeCommonmark, ApexModeGFM, ApexModeMultiMarkdown, ApexModeKramdown, ApexModeUnified, or ApexModeQuarto) or string values: "commonmark", "gfm", "multimarkdown", "kramdown", "unified", or "quarto"
|
|
44
45
|
* @return HTML string
|
|
45
46
|
*/
|
|
46
47
|
+ (NSString *)convertWithApex:(NSString *)inputString mode:(NSString *)mode;
|
|
@@ -86,7 +87,10 @@ extern NSString * const ApexModeUnified;
|
|
|
86
87
|
* - @"headerAnchors": NSNumber (BOOL) - Generate anchor tags instead of IDs
|
|
87
88
|
* - @"obfuscateEmails": NSNumber (BOOL) - Obfuscate email links
|
|
88
89
|
* - @"embedImages": NSNumber (BOOL) - Embed images as base64 data URLs
|
|
89
|
-
* @
|
|
90
|
+
* - @"enablePlugins": NSNumber (BOOL) - Enable external plugin processing
|
|
91
|
+
* - @"enableAutolink": NSNumber (BOOL) - Autolink bare URLs and emails
|
|
92
|
+
* - @"outputFormat": NSString - @"html" (default) or @"rtf"
|
|
93
|
+
* @return HTML or RTF string depending on outputFormat
|
|
90
94
|
*/
|
|
91
95
|
+ (NSString *)convertWithApex:(NSString *)inputString
|
|
92
96
|
mode:(NSString *)mode
|
|
@@ -104,9 +108,30 @@ extern NSString * const ApexModeUnified;
|
|
|
104
108
|
*/
|
|
105
109
|
+ (NSString *)convertWithApex:(NSString *)inputString
|
|
106
110
|
mode:(NSString *)mode
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
generateHeaderIDs:(BOOL)generateHeaderIDs
|
|
112
|
+
hardBreaks:(BOOL)hardBreaks
|
|
113
|
+
pretty:(BOOL)pretty;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Convert Markdown to HTML using Apex with source file URL for includes.
|
|
117
|
+
* Does not embed local images (callers may embed after security-scoped access).
|
|
118
|
+
* @param inputString The markdown text to convert
|
|
119
|
+
* @param mode Processor mode
|
|
120
|
+
* @param sourceURL File URL used for include resolution and base directory
|
|
121
|
+
* @return HTML string
|
|
122
|
+
*/
|
|
123
|
+
+ (NSString *)convertWithApex:(NSString *)inputString
|
|
124
|
+
mode:(NSString *)mode
|
|
125
|
+
sourceURL:(NSURL *)sourceURL;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Same as convertWithApex:mode:sourceURL: with explicit autolink control.
|
|
129
|
+
* Disabling autolink avoids a costly scan on large URL-heavy documents.
|
|
130
|
+
*/
|
|
131
|
+
+ (NSString *)convertWithApex:(NSString *)inputString
|
|
132
|
+
mode:(NSString *)mode
|
|
133
|
+
sourceURL:(NSURL *)sourceURL
|
|
134
|
+
enableAutolink:(BOOL)enableAutolink;
|
|
110
135
|
|
|
111
136
|
/**
|
|
112
137
|
* Convert this string (as Markdown) to HTML using Apex in unified mode
|
|
@@ -123,6 +148,59 @@ extern NSString * const ApexModeUnified;
|
|
|
123
148
|
*/
|
|
124
149
|
- (NSString *)apexHTMLWithMode:(NSString *)mode;
|
|
125
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Convert this string (as Markdown) to RTF using Apex in unified mode.
|
|
153
|
+
*/
|
|
154
|
+
- (NSString *)apexRTF;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Convert this string (as Markdown) to RTF using Apex with specific mode.
|
|
158
|
+
*/
|
|
159
|
+
- (NSString *)apexRTFWithMode:(NSString *)mode;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Convert this string (as Markdown) to RTF with mode and options dictionary.
|
|
163
|
+
* Sets outputFormat to rtf automatically.
|
|
164
|
+
*/
|
|
165
|
+
- (NSString *)apexRTFWithMode:(NSString *)mode
|
|
166
|
+
options:(NSDictionary<NSString *, id> * _Nullable)options;
|
|
167
|
+
|
|
168
|
+
#if __has_include(<AppKit/AppKit.h>) || __has_include(<UIKit/UIKit.h>)
|
|
169
|
+
/**
|
|
170
|
+
* Build an NSAttributedString from Markdown via Apex RTF output (preferred).
|
|
171
|
+
*/
|
|
172
|
+
- (NSAttributedString * _Nullable)apexAttributedString;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Build an NSAttributedString from Markdown using RTF or HTML document type.
|
|
176
|
+
* @param useHTML If YES, use NSHTMLTextDocumentType; if NO, use NSRTFTextDocumentType.
|
|
177
|
+
*/
|
|
178
|
+
- (NSAttributedString * _Nullable)apexAttributedStringUsingHTML:(BOOL)useHTML;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Build an NSAttributedString with mode/options, preferring RTF unless useHTML is YES.
|
|
182
|
+
*/
|
|
183
|
+
- (NSAttributedString * _Nullable)apexAttributedStringWithMode:(NSString *)mode
|
|
184
|
+
options:(NSDictionary<NSString *, id> * _Nullable)options
|
|
185
|
+
usingHTML:(BOOL)useHTML;
|
|
186
|
+
#endif
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Extract a flat table of contents for outline / table-view UIs.
|
|
190
|
+
* Each dictionary has keys: @"level" (NSNumber 1-6), @"text", @"id".
|
|
191
|
+
* Nesting for collapsible sections is derived from level (same rules as -t toc).
|
|
192
|
+
*/
|
|
193
|
+
+ (NSArray<NSDictionary<NSString *, id> *> *)tableOfContentsWithApex:(NSString *)inputString;
|
|
194
|
+
|
|
195
|
+
+ (NSArray<NSDictionary<NSString *, id> *> *)tableOfContentsWithApex:(NSString *)inputString
|
|
196
|
+
mode:(NSString *)mode
|
|
197
|
+
options:(NSDictionary<NSString *, id> * _Nullable)options;
|
|
198
|
+
|
|
199
|
+
- (NSArray<NSDictionary<NSString *, id> *> *)apexTableOfContents;
|
|
200
|
+
|
|
201
|
+
- (NSArray<NSDictionary<NSString *, id> *> *)apexTableOfContentsWithMode:(NSString *)mode
|
|
202
|
+
options:(NSDictionary<NSString *, id> * _Nullable)options;
|
|
203
|
+
|
|
126
204
|
@end
|
|
127
205
|
|
|
128
206
|
NS_ASSUME_NONNULL_END
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
#import "NSString+Apex.h"
|
|
7
7
|
#import <apex/apex.h>
|
|
8
8
|
|
|
9
|
+
#if __has_include(<AppKit/AppKit.h>)
|
|
10
|
+
#import <AppKit/AppKit.h>
|
|
11
|
+
#elif __has_include(<UIKit/UIKit.h>)
|
|
12
|
+
#import <UIKit/UIKit.h>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
9
15
|
/**
|
|
10
16
|
* Apex mode constants
|
|
11
17
|
*/
|
|
@@ -14,6 +20,7 @@ NSString *const ApexModeGFM = @"gfm";
|
|
|
14
20
|
NSString *const ApexModeMultiMarkdown = @"multimarkdown";
|
|
15
21
|
NSString *const ApexModeKramdown = @"kramdown";
|
|
16
22
|
NSString *const ApexModeUnified = @"unified";
|
|
23
|
+
NSString *const ApexModeQuarto = @"quarto";
|
|
17
24
|
|
|
18
25
|
@implementation NSString (Apex)
|
|
19
26
|
|
|
@@ -41,6 +48,8 @@ NSString *const ApexModeUnified = @"unified";
|
|
|
41
48
|
return APEX_MODE_MULTIMARKDOWN;
|
|
42
49
|
} else if ([mode isEqualToString:@"kramdown"]) {
|
|
43
50
|
return APEX_MODE_KRAMDOWN;
|
|
51
|
+
} else if ([mode isEqualToString:@"quarto"]) {
|
|
52
|
+
return APEX_MODE_QUARTO;
|
|
44
53
|
} else {
|
|
45
54
|
return APEX_MODE_UNIFIED; /* Default to unified */
|
|
46
55
|
}
|
|
@@ -267,9 +276,32 @@ NSString *const ApexModeUnified = @"unified";
|
|
|
267
276
|
if (embedImagesValue && [embedImagesValue isKindOfClass:[NSNumber class]]) {
|
|
268
277
|
options.embed_images = [embedImagesValue boolValue];
|
|
269
278
|
}
|
|
279
|
+
|
|
280
|
+
/* Plugins */
|
|
281
|
+
id enablePluginsValue = optionsDict[@"enablePlugins"];
|
|
282
|
+
if (enablePluginsValue && [enablePluginsValue isKindOfClass:[NSNumber class]]) {
|
|
283
|
+
options.enable_plugins = [enablePluginsValue boolValue];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Autolink bare URLs / emails */
|
|
287
|
+
id enableAutolinkValue = optionsDict[@"enableAutolink"];
|
|
288
|
+
if (enableAutolinkValue && [enableAutolinkValue isKindOfClass:[NSNumber class]]) {
|
|
289
|
+
options.enable_autolink = [enableAutolinkValue boolValue];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* Output format: html (default) or rtf */
|
|
293
|
+
id outputFormatValue = optionsDict[@"outputFormat"];
|
|
294
|
+
if (outputFormatValue && [outputFormatValue isKindOfClass:[NSString class]]) {
|
|
295
|
+
NSString *fmt = [(NSString *)outputFormatValue lowercaseString];
|
|
296
|
+
if ([fmt isEqualToString:@"rtf"]) {
|
|
297
|
+
options.output_format = APEX_OUTPUT_RTF;
|
|
298
|
+
} else {
|
|
299
|
+
options.output_format = APEX_OUTPUT_HTML;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
270
302
|
}
|
|
271
303
|
|
|
272
|
-
/* Convert to HTML */
|
|
304
|
+
/* Convert to HTML or RTF */
|
|
273
305
|
char *html_c = apex_markdown_to_html(markdown, strlen(markdown), &options);
|
|
274
306
|
|
|
275
307
|
if (!html_c) {
|
|
@@ -324,6 +356,69 @@ NSString *const ApexModeUnified = @"unified";
|
|
|
324
356
|
return html ? html : @"";
|
|
325
357
|
}
|
|
326
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Convert Markdown to HTML using Apex with source file URL for includes.
|
|
361
|
+
* Leaves local images as paths; sandboxed callers (e.g. Marked Quick Look)
|
|
362
|
+
* embed after security-scoped folder grants.
|
|
363
|
+
*/
|
|
364
|
+
+ (NSString *)convertWithApex:(NSString *)inputString
|
|
365
|
+
mode:(NSString *)modeString
|
|
366
|
+
sourceURL:(NSURL *)sourceURL {
|
|
367
|
+
return [self convertWithApex:inputString
|
|
368
|
+
mode:modeString
|
|
369
|
+
sourceURL:sourceURL
|
|
370
|
+
enableAutolink:YES];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
+ (NSString *)convertWithApex:(NSString *)inputString
|
|
374
|
+
mode:(NSString *)modeString
|
|
375
|
+
sourceURL:(NSURL *)sourceURL
|
|
376
|
+
enableAutolink:(BOOL)enableAutolink {
|
|
377
|
+
if (!inputString || [inputString length] == 0) {
|
|
378
|
+
return @"";
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const char *markdown = [inputString UTF8String];
|
|
382
|
+
if (!markdown) {
|
|
383
|
+
return @"";
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
apex_mode_t mode = [self apexModeFromString:modeString];
|
|
387
|
+
apex_options options = apex_options_for_mode(mode);
|
|
388
|
+
|
|
389
|
+
options.unsafe = true;
|
|
390
|
+
options.generate_header_ids = true;
|
|
391
|
+
options.enable_critic_markup = true;
|
|
392
|
+
options.critic_mode = 2; /* CRITIC_MARKUP: show markup with classes */
|
|
393
|
+
/* Do not embed images here: fopen/stat under Dropbox/CloudStorage can stall
|
|
394
|
+
* sandboxed Quick Look. Callers (Marked Quick Look) embed after security-scoped
|
|
395
|
+
* folder grants with a non-blocking Swift pass. */
|
|
396
|
+
options.embed_images = false;
|
|
397
|
+
options.enable_autolink = enableAutolink;
|
|
398
|
+
|
|
399
|
+
if (sourceURL && sourceURL.isFileURL) {
|
|
400
|
+
NSString *path = sourceURL.path;
|
|
401
|
+
if (path.length > 0) {
|
|
402
|
+
options.input_file_path = [path UTF8String];
|
|
403
|
+
NSString *baseDir = [path stringByDeletingLastPathComponent];
|
|
404
|
+
if (baseDir.length > 0) {
|
|
405
|
+
options.base_directory = [baseDir UTF8String];
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
char *html_c = apex_markdown_to_html(markdown, strlen(markdown), &options);
|
|
411
|
+
|
|
412
|
+
if (!html_c) {
|
|
413
|
+
return @"";
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
NSString *html = [NSString stringWithUTF8String:html_c];
|
|
417
|
+
apex_free_string(html_c);
|
|
418
|
+
|
|
419
|
+
return html ? html : @"";
|
|
420
|
+
}
|
|
421
|
+
|
|
327
422
|
/**
|
|
328
423
|
* Convert this string (as Markdown) to HTML using Apex in unified mode
|
|
329
424
|
*/
|
|
@@ -338,4 +433,152 @@ NSString *const ApexModeUnified = @"unified";
|
|
|
338
433
|
return [NSString convertWithApex:self mode:mode];
|
|
339
434
|
}
|
|
340
435
|
|
|
436
|
+
- (NSString *)apexRTF {
|
|
437
|
+
return [self apexRTFWithMode:ApexModeUnified options:nil];
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
- (NSString *)apexRTFWithMode:(NSString *)mode {
|
|
441
|
+
return [self apexRTFWithMode:mode options:nil];
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
- (NSString *)apexRTFWithMode:(NSString *)mode
|
|
445
|
+
options:(NSDictionary<NSString *, id> *_Nullable)options {
|
|
446
|
+
NSMutableDictionary *dict =
|
|
447
|
+
options ? [options mutableCopy] : [NSMutableDictionary dictionary];
|
|
448
|
+
dict[@"outputFormat"] = @"rtf";
|
|
449
|
+
return [NSString convertWithApex:self mode:mode options:dict];
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
#if __has_include(<AppKit/AppKit.h>) || __has_include(<UIKit/UIKit.h>)
|
|
453
|
+
- (NSAttributedString *)apexAttributedString {
|
|
454
|
+
return [self apexAttributedStringWithMode:ApexModeUnified options:nil usingHTML:NO];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
- (NSAttributedString *)apexAttributedStringUsingHTML:(BOOL)useHTML {
|
|
458
|
+
return [self apexAttributedStringWithMode:ApexModeUnified options:nil usingHTML:useHTML];
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
- (NSAttributedString *)apexAttributedStringWithMode:(NSString *)mode
|
|
462
|
+
options:(NSDictionary<NSString *, id> *_Nullable)options
|
|
463
|
+
usingHTML:(BOOL)useHTML {
|
|
464
|
+
NSString *source = nil;
|
|
465
|
+
NSAttributedStringDocumentType docType;
|
|
466
|
+
if (useHTML) {
|
|
467
|
+
source = [NSString convertWithApex:self mode:mode options:options];
|
|
468
|
+
docType = NSHTMLTextDocumentType;
|
|
469
|
+
} else {
|
|
470
|
+
source = [self apexRTFWithMode:mode options:options];
|
|
471
|
+
docType = NSRTFTextDocumentType;
|
|
472
|
+
}
|
|
473
|
+
if (!source || [source length] == 0) {
|
|
474
|
+
return [[NSAttributedString alloc] initWithString:@""];
|
|
475
|
+
}
|
|
476
|
+
NSData *data = [source dataUsingEncoding:NSUTF8StringEncoding];
|
|
477
|
+
if (!data) {
|
|
478
|
+
return nil;
|
|
479
|
+
}
|
|
480
|
+
NSDictionary *attrs = @{
|
|
481
|
+
NSDocumentTypeDocumentAttribute : docType,
|
|
482
|
+
NSCharacterEncodingDocumentAttribute : @(NSUTF8StringEncoding)
|
|
483
|
+
};
|
|
484
|
+
NSError *error = nil;
|
|
485
|
+
NSAttributedString *attr =
|
|
486
|
+
[[NSAttributedString alloc] initWithData:data options:attrs documentAttributes:nil error:&error];
|
|
487
|
+
(void)error;
|
|
488
|
+
return attr;
|
|
489
|
+
}
|
|
490
|
+
#endif
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Extract a flat table of contents as dictionaries suitable for Swift OutlineGroup.
|
|
494
|
+
* Each entry: @{ @"level": NSNumber, @"text": NSString, @"id": NSString }
|
|
495
|
+
* Optional options keys: @"idFormat" (@"gfm"/@"mmd"/@"kramdown"),
|
|
496
|
+
* @"tocMinMax" (@"2,4" or @[@2, @4]).
|
|
497
|
+
*/
|
|
498
|
+
+ (NSArray<NSDictionary<NSString *, id> *> *)tableOfContentsWithApex:(NSString *)inputString
|
|
499
|
+
mode:(NSString *)modeString
|
|
500
|
+
options:(NSDictionary<NSString *, id> *_Nullable)optionsDict {
|
|
501
|
+
if (!inputString || [inputString length] == 0) {
|
|
502
|
+
return @[];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const char *markdown = [inputString UTF8String];
|
|
506
|
+
if (!markdown) {
|
|
507
|
+
return @[];
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
apex_mode_t mode = [self apexModeFromString:modeString ?: ApexModeUnified];
|
|
511
|
+
apex_options options = apex_options_for_mode(mode);
|
|
512
|
+
|
|
513
|
+
if (optionsDict) {
|
|
514
|
+
id idFormatVal = optionsDict[@"idFormat"];
|
|
515
|
+
if ([idFormatVal isKindOfClass:[NSString class]]) {
|
|
516
|
+
NSString *fmt = [(NSString *)idFormatVal lowercaseString];
|
|
517
|
+
if ([fmt isEqualToString:@"mmd"]) {
|
|
518
|
+
options.id_format = 1;
|
|
519
|
+
} else if ([fmt isEqualToString:@"kramdown"]) {
|
|
520
|
+
options.id_format = 2;
|
|
521
|
+
} else {
|
|
522
|
+
options.id_format = 0;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
id tocMinMaxVal = optionsDict[@"tocMinMax"];
|
|
526
|
+
if ([tocMinMaxVal isKindOfClass:[NSString class]]) {
|
|
527
|
+
int min = 0, max = 0;
|
|
528
|
+
if (sscanf([(NSString *)tocMinMaxVal UTF8String], "%d,%d", &min, &max) == 2 &&
|
|
529
|
+
min >= 1 && max <= 6 && min <= max) {
|
|
530
|
+
options.toc_min = min;
|
|
531
|
+
options.toc_max = max;
|
|
532
|
+
}
|
|
533
|
+
} else if ([tocMinMaxVal isKindOfClass:[NSArray class]] &&
|
|
534
|
+
[(NSArray *)tocMinMaxVal count] >= 2) {
|
|
535
|
+
int min = [[(NSArray *)tocMinMaxVal objectAtIndex:0] intValue];
|
|
536
|
+
int max = [[(NSArray *)tocMinMaxVal objectAtIndex:1] intValue];
|
|
537
|
+
if (min >= 1 && max <= 6 && min <= max) {
|
|
538
|
+
options.toc_min = min;
|
|
539
|
+
options.toc_max = max;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
size_t count = 0;
|
|
545
|
+
apex_toc_entry *entries =
|
|
546
|
+
apex_markdown_to_toc_entries(markdown, strlen(markdown), &options, &count);
|
|
547
|
+
if (!entries || count == 0) {
|
|
548
|
+
apex_toc_entries_free(entries, count);
|
|
549
|
+
return @[];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
NSMutableArray<NSDictionary<NSString *, id> *> *result =
|
|
553
|
+
[NSMutableArray arrayWithCapacity:count];
|
|
554
|
+
for (size_t i = 0; i < count; i++) {
|
|
555
|
+
NSString *text = entries[i].text
|
|
556
|
+
? [NSString stringWithUTF8String:entries[i].text]
|
|
557
|
+
: @"";
|
|
558
|
+
NSString *ident = entries[i].id
|
|
559
|
+
? [NSString stringWithUTF8String:entries[i].id]
|
|
560
|
+
: @"";
|
|
561
|
+
[result addObject:@{
|
|
562
|
+
@"level" : @(entries[i].level),
|
|
563
|
+
@"text" : text ?: @"",
|
|
564
|
+
@"id" : ident ?: @""
|
|
565
|
+
}];
|
|
566
|
+
}
|
|
567
|
+
apex_toc_entries_free(entries, count);
|
|
568
|
+
return result;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
+ (NSArray<NSDictionary<NSString *, id> *> *)tableOfContentsWithApex:(NSString *)inputString {
|
|
572
|
+
return [self tableOfContentsWithApex:inputString mode:ApexModeUnified options:nil];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
- (NSArray<NSDictionary<NSString *, id> *> *)apexTableOfContents {
|
|
576
|
+
return [NSString tableOfContentsWithApex:self];
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
- (NSArray<NSDictionary<NSString *, id> *> *)apexTableOfContentsWithMode:(NSString *)mode
|
|
580
|
+
options:(NSDictionary<NSString *, id> *_Nullable)options {
|
|
581
|
+
return [NSString tableOfContentsWithApex:self mode:mode options:options];
|
|
582
|
+
}
|
|
583
|
+
|
|
341
584
|
@end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NSString+ApexPlugins.h
|
|
3
|
+
* Objective-C API for Apex plugin catalog and installation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#import <Foundation/Foundation.h>
|
|
7
|
+
|
|
8
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
9
|
+
|
|
10
|
+
/** Metadata for one plugin (catalog or installed). */
|
|
11
|
+
@interface ApexPluginInfo : NSObject
|
|
12
|
+
|
|
13
|
+
@property (nonatomic, copy, readonly) NSString *pluginId;
|
|
14
|
+
@property (nonatomic, copy, readonly, nullable) NSString *title;
|
|
15
|
+
@property (nonatomic, copy, readonly, nullable) NSString *pluginDescription;
|
|
16
|
+
@property (nonatomic, copy, readonly, nullable) NSString *author;
|
|
17
|
+
@property (nonatomic, copy, readonly, nullable) NSString *homepage;
|
|
18
|
+
@property (nonatomic, copy, readonly, nullable) NSString *repo;
|
|
19
|
+
|
|
20
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
21
|
+
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
/** Plugin catalog and install helpers for app UIs. */
|
|
25
|
+
@interface ApexPluginCatalog : NSObject
|
|
26
|
+
|
|
27
|
+
/** Default apex-plugins.json URL. */
|
|
28
|
+
@property (class, nonatomic, readonly) NSString *defaultDirectoryURL;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fetch available plugins from the central directory.
|
|
32
|
+
* @param error Set on failure (network, parse, curl missing).
|
|
33
|
+
*/
|
|
34
|
+
+ (nullable NSArray<ApexPluginInfo *> *)fetchAvailablePlugins:(NSError **)error;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fetch available plugins from a custom directory JSON URL.
|
|
38
|
+
*/
|
|
39
|
+
+ (nullable NSArray<ApexPluginInfo *> *)fetchAvailablePluginsFromURL:(NSString *)url
|
|
40
|
+
error:(NSError **)error;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* List installed plugins (project + user-global, same order as runtime loading).
|
|
44
|
+
* @param baseDirectory Optional document base for .apex/plugins lookup.
|
|
45
|
+
*/
|
|
46
|
+
+ (NSArray<ApexPluginInfo *> *)installedPluginsWithBaseDirectory:(NSString * _Nullable)baseDirectory;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Install a plugin by directory id into ~/.config/apex/plugins.
|
|
50
|
+
*/
|
|
51
|
+
+ (BOOL)installPluginWithId:(NSString *)pluginId error:(NSError **)error;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Install from a Git URL or GitHub shorthand (user/repo). Requires explicit opt-in.
|
|
55
|
+
*/
|
|
56
|
+
+ (BOOL)installPluginFromRepository:(NSString *)idOrRepo
|
|
57
|
+
allowUntrustedSource:(BOOL)allowUntrusted
|
|
58
|
+
error:(NSError **)error;
|
|
59
|
+
|
|
60
|
+
/** Remove a plugin from the user-global plugins directory. */
|
|
61
|
+
+ (BOOL)uninstallPluginWithId:(NSString *)pluginId error:(NSError **)error;
|
|
62
|
+
|
|
63
|
+
/** User-global plugins directory path. */
|
|
64
|
+
+ (nullable NSString *)globalPluginsDirectory;
|
|
65
|
+
|
|
66
|
+
@end
|
|
67
|
+
|
|
68
|
+
FOUNDATION_EXPORT NSErrorDomain const ApexPluginErrorDomain;
|
|
69
|
+
|
|
70
|
+
typedef NS_ERROR_ENUM(ApexPluginErrorDomain, ApexPluginError) {
|
|
71
|
+
ApexPluginErrorFetchFailed = 1,
|
|
72
|
+
ApexPluginErrorInstallFailed = 2,
|
|
73
|
+
ApexPluginErrorUninstallFailed = 3,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
NS_ASSUME_NONNULL_END
|