11# NTangle - Basic tangling of Org documents
22# https://github.com/OrgTangle/ntangle
33
4- import os, strformat, strutils, tables, terminal, sequtils
4+ import os, strformat, strutils, tables, terminal, sequtils, options
55
66type
77 DebugVerbosity = enum dvNone, dvLow, dvHigh
4343 UserError = object of Exception
4444 OrgError = object of Exception
4545 HeaderArgs = object
46- tangle: string
46+ tangle: Option [ string ]
4747 padline: bool
4848 shebang: string
4949 mkdirp: bool
@@ -85,7 +85,7 @@ proc resetStateVars() =
8585 fileHeaderArgs.clear ()
8686 headerArgsDefaults.clear ()
8787 # Default tangle header args for all Org levels and languages.
88- headerArgsDefaults[(0 .Natural , " " )] = HeaderArgs (tangle : " no" ,
88+ headerArgsDefaults[(0 .Natural , " " )] = HeaderArgs (tangle : some ( " no" ) ,
8989 padline : true ,
9090 shebang : " " ,
9191 mkdirp : false ,
@@ -113,7 +113,8 @@ proc parseFilePermissions(octals: string): set[FilePermission] =
113113proc parseTangleHeaderProperties (hdrArgs: seq [string ], lnum: int , lang: string , onBeginSrc: bool ) =
114114 # # Org header arguments related to tangling. See (org) Extracting Source Code.
115115 # # ``hdrArgs`` is a sequence like @["KEY1 VAL1", "KEY2 VAL2", ..].
116- let (dir, basename, _) = splitFile (orgFile)
116+ let
117+ (dir, basename, _) = splitFile (orgFile)
117118 dbg " Org file = {orgFile}, dir={dir}, base name={basename}" , dvHigh
118119 dbg (" " , prefix= " " ) # blank line
119120 dbg " Line {lnum}, Lang {lang} - hdrArgs: {hdrArgs}"
@@ -140,12 +141,16 @@ proc parseTangleHeaderProperties(hdrArgs: seq[string], lnum: int, lang: string,
140141 dbg " Line {lnum} - Using only Org level {orgLevel} scope, now hArgs = {hArgs}"
141142
142143 # If hArgs already specifies the tangled file path, use that!
143- if (hArgs.tangle != " yes" ) and (hArgs.tangle != " no" ):
144- dbg " ** Line {lnum} - Old outfile={outfile}, overriding it to {hArgs.tangle}"
145- if (not hArgs.tangle.startsWith " /" ): # if relative path
146- outfile = dir / hArgs.tangle
144+ if hArgs.tangle.isSome () and
145+ (hArgs.tangle.get () != " yes" ) and
146+ (hArgs.tangle.get () != " no" ):
147+ let
148+ tangledPath = hArgs.tangle.get ()
149+ dbg " ** Line {lnum} - Old outfile={outfile}, overriding it to {tangledPath}"
150+ if (not tangledPath.startsWith " /" ): # if relative path
151+ outfile = dir / tangledPath
147152 else :
148- outfile = hArgs.tangle
153+ outfile = tangledPath
149154
150155 for hdrArg in hdrArgs:
151156 let
@@ -155,7 +160,7 @@ proc parseTangleHeaderProperties(hdrArgs: seq[string], lnum: int, lang: string,
155160 dbg " arg={arg}, argval={argval}, onBeginSrc={onBeginSrc}, outfile={outfile}"
156161 case arg
157162 of " tangle" :
158- hArgs.tangle = argval
163+ hArgs.tangle = some ( argval)
159164 case argval
160165 of " yes" :
161166 discard
@@ -235,24 +240,35 @@ proc parseTangleHeaderProperties(hdrArgs: seq[string], lnum: int, lang: string,
235240 discard
236241
237242 # Update the default HeaderArgs for the current orgLevel+lang
238- # scope.
239- if (not onBeginSrc): # global or subtree property
243+ # scope, but only using the header args set using property keyword
244+ # or the drawer property.
245+ if (not onBeginSrc):
246+ dbg " ** Line {lnum}: Updating headerArgsDefaults[({orgLevel}, {lang})] to {hArgs}"
240247 headerArgsDefaults[(orgLevel, lang)] = hArgs
241248
242249 dbg " [after] Line {lnum} - hArgs = {hArgs}"
243- # Save the updated hArgs to the file-specific HeaderArgs global
244- # value.
245250 if outfile != " " :
251+ # Save the updated hArgs to the file-specific HeaderArgs global
252+ # value.
246253 outFileName = outfile
247- dbg " ** outFileName now set to {outFileName }"
254+ dbg " ** Line {lnum}: Updating fileHeaderArgs[{outFileName}] to {hArgs }"
248255 fileHeaderArgs[outFileName] = hArgs
249256
250- dbg " line={lnum}, onBeginSrc={onBeginSrc}, hArgs.tangle={hArgs.tangle} outfile={outfile} | outFileName={outFileName}"
251- if onBeginSrc and (hArgs.tangle != " no" ):
252- doAssert outFileName != " "
253- dbg " line {lnum}: buffering enabled for `{outFileName}'"
254- bufEnabled = true
255- firstLineSrcBlock = true
257+ dbg " line={lnum}, onBeginSrc={onBeginSrc}, hArgs.tangle={hArgs.tangle} outfile={outfile} | outFileName={outFileName}"
258+ if onBeginSrc:
259+ if hArgs.tangle.isSome () and
260+ hArgs.tangle.get () != " no" :
261+ doAssert outFileName != " "
262+ dbg " line {lnum}: buffering enabled for `{outFileName}'"
263+ bufEnabled = true
264+ firstLineSrcBlock = true
265+
266+ # Don't allow further source blocks to inherit the hArgs.tangle
267+ # value set in begin_src header args.
268+ hArgs.tangle = none (string )
269+
270+ dbg " ** Line {lnum}: Updating fileHeaderArgs[{outFileName}] to {hArgs}"
271+ fileHeaderArgs[outFileName] = hArgs
256272
257273proc orgRemoveEscapeCommas (line: string ): string =
258274 # # Remove only single leading comma if it's followed by "#+" or "*".
0 commit comments