Skip to content

Commit 36c1b54

Browse files
committed
Add heading transclusions and rename extensions
1 parent b2779c9 commit 36c1b54

File tree

4 files changed

+97
-25
lines changed

4 files changed

+97
-25
lines changed

MANUAL.txt

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6221,29 +6221,37 @@ or
62216221

62226222
Oxygen is O~2.
62236223

6224-
### Extension: `block_ids` ###
6224+
### Extension: `wikilink_transclusions` ###
62256225

6226-
Follows the [Obsidan-style block identifiers] syntax. For example add `^ref` at the end of a paragraph:
6226+
Follows [Obsidan-style transclusions] using wikilink syntax to embed one file in another. For example to transclude the file "Title":
62276227

6228-
Text ^ref
6228+
![[Title]]
62296229

6230-
[Obsidan-style block identifiers]: https://help.obsidian.md/links#Link+to+a+block+in+a+note
6230+
[Obsidan-style transclusions]: https://help.obsidian.md/embeds
6231+
6232+
### Extension: `wilikink_heading_transclusions` ###
6233+
6234+
Follows the [Obsidan-style heading transclusions] syntax. For example to transclude a heading within the file "Title":
62316235

6232-
### Extension: `block_transclusions` ###
6236+
![[Title#Heading]]
6237+
6238+
[Obsidan-style heading transclusions]: https://help.obsidian.md/links#Link+to+a+heading+in+a+note
6239+
6240+
### Extension: `wilikink_block_transclusions` ###
62336241

62346242
Follows the [Obsidan-style block transclusions] syntax. For example to transclude block ID ^ref within the file "Title":
62356243

62366244
![[Title#^ref]]
62376245

62386246
[Obsidan-style block transclusions]: https://help.obsidian.md/links#Link+to+a+block+in+a+note
62396247

6240-
### Extension: `wikilink_transclusions` ###
6248+
### Extension: `block_ids` ###
62416249

6242-
Follows [Obsidan-style transclusions] using wikilink syntax to embed one file in another. For example to transclude the file "Title":
6250+
Follows the [Obsidan-style block identifiers] syntax. For example add `^ref` at the end of a paragraph:
62436251

6244-
![[Title]]
6252+
Text ^ref
62456253

6246-
[Obsidan-style transclusions]: https://help.obsidian.md/embeds
6254+
[Obsidan-style block identifiers]: https://help.obsidian.md/links#Link+to+a+block+in+a+note
62476255

62486256
### Extension: `wikilinks_title_after_pipe` ###
62496257

src/Text/Pandoc/Extensions.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ data Extension =
5858
| Ext_blank_before_blockquote -- ^ Require blank line before a blockquote
5959
| Ext_blank_before_header -- ^ Require blank line before a header
6060
| Ext_block_ids -- ^ Block identifiers, used by Obsidian
61-
| Ext_block_transclusion -- ^ Block transclusions, used by Obsidian
6261
| Ext_bracketed_spans -- ^ Bracketed spans with attributes
6362
| Ext_citations -- ^ Pandoc/citeproc citations
6463
| Ext_comments -- ^ Percent wrapped %%comments%%
@@ -144,7 +143,9 @@ data Extension =
144143
-- [[target|title]]
145144
| Ext_wikilinks_title_before_pipe -- ^ Support wikilinks of style
146145
-- [[title|target]]
147-
| Ext_wikilink_transclusion -- ^ Wikilink transclusion e.g. ![[title]]
146+
| Ext_wikilink_transclusions -- ^ Wikilink transclusion e.g. ![[title]]
147+
| Ext_wikilink_heading_transclusions -- ^ Wikilink heading transclusion e.g. ![[title#heading]] in Obsidian
148+
| Ext_wikilink_block_transclusions -- ^ Wikilink block transclusions, e.g. ![[title#^id]] in Obsidian
148149
| Ext_xrefs_name -- ^ Use xrefs with names
149150
| Ext_xrefs_number -- ^ Use xrefs with numbers
150151
| Ext_yaml_metadata_block -- ^ YAML metadata block
@@ -413,7 +414,6 @@ getDefaultExtensions "obsidian" = extensionsFromList
413414
[ Ext_alerts
414415
, Ext_autolink_bare_uris
415416
, Ext_block_ids
416-
, Ext_block_transclusion
417417
, Ext_comments
418418
, Ext_footnotes
419419
, Ext_mark
@@ -423,7 +423,9 @@ getDefaultExtensions "obsidian" = extensionsFromList
423423
, Ext_task_lists
424424
, Ext_tex_math_dollars
425425
, Ext_wikilinks_title_after_pipe
426-
, Ext_wikilink_transclusion
426+
, Ext_wikilink_transclusions
427+
, Ext_wikilink_block_transclusions
428+
, Ext_wikilink_heading_transclusions
427429
, Ext_yaml_metadata_block
428430
]
429431
getDefaultExtensions "commonmark" = extensionsFromList

src/Text/Pandoc/Readers/Markdown.hs

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ addBlockId (id', classes, kvs) st =
469469

470470
blockTransclusion :: PandocMonad m => MarkdownParser m (F Blocks)
471471
blockTransclusion = try $ do
472-
guardEnabled Ext_block_transclusion
472+
guardEnabled Ext_wikilink_block_transclusions
473473
char '!'
474474
res <- wikilink B.linkWith
475475
return $ B.divWith ("", ["block-transclusion"], []) . B.para <$> res
@@ -2050,20 +2050,34 @@ wikilinkTransclusion = try $ do
20502050
(before, after)
20512051
| titleAfter -> (T.drop 1 after, before)
20522052
| otherwise -> (before, T.drop 1 after)
2053-
let (url, blockRef) = T.break (== '#') target'
2053+
let (url, fragment) = T.break (== '#') target'
20542054
guard $ T.all (`notElem` ['\n','\r','\f','\t']) url
2055-
if T.null blockRef
2055+
if T.null fragment
20562056
then do
2057-
guardEnabled Ext_wikilink_transclusion
2057+
guardEnabled Ext_wikilink_transclusions
20582058
currentDir <- takeDirectory . sourceName <$> getPosition
2059-
let filename = T.unpack url <> ".md" -- Assume .md extension
2059+
let filename = T.unpack url
2060+
-- Support relative paths like "Folder/File" by using currentDir as base
20602061
insertIncludedFile (fmap B.toInlines <$> parseBlocks) toSources [currentDir] filename Nothing Nothing
20612062
else do
2062-
guardEnabled Ext_block_transclusion
2063-
currentDir <- takeDirectory . sourceName <$> getPosition
2064-
let filename = T.unpack url <> ".md" -- Assume .md extension
2065-
let blockId = T.drop 1 blockRef -- Remove the '^' prefix
2066-
insertIncludedFile (extractBlockById blockId <$> parseBlocks) toSources [currentDir] filename Nothing Nothing
2063+
let fragmentContent = T.drop 1 fragment -- Remove the '#' prefix
2064+
if T.take 1 fragmentContent == "^"
2065+
then do
2066+
-- Block ID transclusion: ![[File#^block-id]]
2067+
guardEnabled Ext_wikilink_block_transclusions
2068+
currentDir <- takeDirectory . sourceName <$> getPosition
2069+
let filename = T.unpack url <> ".md" -- Assume .md extension for block transclusion
2070+
let blockId = T.drop 1 fragmentContent -- Remove the '^' prefix
2071+
-- Support relative paths like "Folder/File" by using currentDir as base
2072+
insertIncludedFile (extractBlockById blockId <$> parseBlocks) toSources [currentDir] filename Nothing Nothing
2073+
else do
2074+
-- Heading transclusion: ![[File#Heading]]
2075+
guardEnabled Ext_wikilink_heading_transclusions
2076+
currentDir <- takeDirectory . sourceName <$> getPosition
2077+
let filename = T.unpack url <> ".md" -- Assume .md extension for heading transclusion
2078+
let headingText = fragmentContent
2079+
-- Support relative paths like "Folder/File" by using currentDir as base
2080+
insertIncludedFile (extractHeadingById headingText <$> parseBlocks) toSources [currentDir] filename Nothing Nothing
20672081

20682082
note :: PandocMonad m => MarkdownParser m (F Inlines)
20692083
note = try $ do
@@ -2391,6 +2405,40 @@ findBlockById targetId = go
23912405
Header _ (bid, _, _) _ | bid == targetId -> Just block
23922406
_ -> go rest
23932407

2408+
-- | Extract content under a specific heading from a list of blocks
2409+
extractHeadingById :: Text -> Blocks -> F Inlines
2410+
extractHeadingById targetHeading blocks =
2411+
case extractContentUnderHeading targetHeading (B.toList blocks) of
2412+
[] -> return mempty
2413+
content -> return $ B.toInlines $ B.fromList content
2414+
2415+
-- | Extract all content under a heading until the next heading of same or higher level
2416+
extractContentUnderHeading :: Text -> [Block] -> [Block]
2417+
extractContentUnderHeading targetHeading = go False 0
2418+
where
2419+
go _found _level [] = []
2420+
go found level (block:rest) =
2421+
case block of
2422+
Header lvl _ inlines
2423+
| stringify inlines == targetHeading ->
2424+
-- Found target heading, start collecting content
2425+
block : go True lvl rest
2426+
| found && lvl <= level ->
2427+
-- Found heading of same or higher level, stop collecting
2428+
[]
2429+
| found ->
2430+
-- Collecting content under target heading
2431+
block : go True level rest
2432+
| otherwise ->
2433+
-- Haven't found target heading yet
2434+
go False level rest
2435+
_ | found ->
2436+
-- Collecting content under target heading
2437+
block : go True level rest
2438+
| otherwise ->
2439+
-- Haven't found target heading yet
2440+
go False level rest
2441+
23942442
blockId :: PandocMonad m => MarkdownParser m (F Inlines)
23952443
blockId = try $ do
23962444
guardEnabled Ext_block_ids

test/command/obsidian.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,28 @@ A block transclusion: ![[myfile#^my-id]]
4343
```
4444

4545
```
46-
% pandoc -f obsidian-wikilink_transclusion -t native
46+
% pandoc -f obsidian -t native
47+
A heading transclusion: ![[myfile#Introduction]]
48+
^D
49+
[ Para [ Str "A" , Space , Str "heading" , Space , Str "transclusion:" , Space ] ]
50+
```
51+
52+
```
53+
% pandoc -f obsidian-wikilink_transclusions -t native
4754
A wikilink transclusion: ![[my-wikilink]]
4855
^D
4956
[ Para [ Str "A" , Space , Str "wikilink" , Space , Str "transclusion:" , Space , Str "!" , Link ( "" , [ "wikilink" ] , [] ) [ Str "my-wikilink" ] ( "my-wikilink" , "" ) ] ]
5057
```
5158

5259
```
53-
% pandoc -f obsidian-block_transclusion -t native
60+
% pandoc -f obsidian-wikilink_heading_transclusions -t native
61+
A heading transclusion: ![[myfile#Introduction]]
62+
^D
63+
[ Para [ Str "A" , Space , Str "heading" , Space , Str "transclusion:" , Space , Str "!" , Link ( "" , [ "wikilink" ] , [] ) [ Str "myfile#Introduction" ] ( "myfile#Introduction" , "" ) ] ]
64+
```
65+
66+
```
67+
% pandoc -f obsidian-wikilink_block_transclusions -t native
5468
A block transclusion: ![[myfile#^my-id]]
5569
^D
5670
[ Para [ Str "A" , Space , Str "block" , Space , Str "transclusion:" , Space , Str "!" , Link ( "" , [ "wikilink" ] , [] ) [ Str "myfile#^my-id" ] ( "myfile#^my-id" , "" ) ] ]

0 commit comments

Comments
 (0)