*! version 1.5.4
*! Doug Hemken
*! 27 March 2018
// ISSUES
// ======
// wrapper with dyndoc, pandoc
// better, more extensive preamble, e.g. linesize, other options?
// NOGRaph option
// ignore executable code within non-executable fence
capture program drop stmd2dyn
capture mata: mata clear
program define stmd2dyn, rclass
syntax anything(name=infile), [SAVing(string) replace]
local infile = ustrtrim(usubinstr(`"`infile'"', `"""', "", .))
*display `"infile is `infile'"'
confirm file `"`infile'"'
*display "infile confirmed"
if ("`saving'" == "" ) {
mata:(void)pathchangesuffix("`infile'", "dyn", "saving", 0)
mata: (void)st_local("saving", pathjoin("`c(pwd)'", `"`saving'"'))
}
mata: (void)pathresolve("`c(pwd)'", `"`saving'"', "saving")
*display `"saving `saving'"'
local issame = 0
mata: (void)filesarethesame("`infile'", "`saving'", "issame")
if ("`issame'" == "1") {
display in error "target file can not be the same as the source file"
exit 602
}
if ("`replace'"=="") {
confirm new file "`saving'"
}
* Read in file
mata: X=docread("`infile'")
* Then identify code blocks and tags
mata: fenceinfo = _fence_info(X) // fences
mata: infotags = _info_tags(X) // retrieve infotags
mata: tagmatchs = _tag_match(infotags) // parse infotags
mata: dotags = _dd_do(fenceinfo, tagmatchs) // generate <>
* Identify display directives
mata: X = _inline_code(X)
* assemble pieces of a dyndoc
mata: document = _stitch(X, fenceinfo, dotags)
* Write out the result
mata: saving = st_local("saving")
mata: docwrite(saving, document)
display " {text:Output saved as {it:`saving'}}"
* Finish up
return local outfile "`saving'"
end
mata
string colvector docread(string scalar filename) {
fh = fopen(filename, "r")
string colvector document
document= J(0,1,"")
while ((line=fget(fh))!=J(0,0,"")) {
document = (document\line)
}
fclose(fh)
return(document)
}
void function docwrite(string scalar filename, ///
string colvector document) {
unlink(filename)
fh = fopen(filename, "w")
for (i=1; i<=length(document); i++) {
fput(fh, document[i])
}
fclose(fh)
}
real matrix function _fence_info(string colvector X) {
codefence = "^( ? ? ?)(```+|~~~+)([ ]*)$"
infofence = "^( ? ? ?)(```+|~~~+)\{?s(tata)?\/?(,.*)?\}?$"
fence = ustrregexm(X, codefence)
codebegin = ustrregexm(X, infofence)
fence = fence + codebegin
prespace = J(rows(X),1,.)
fencel = J(rows(X),1,.)
cb = 0
cbfl = 0
for (i=1; i<=rows(X); i++) {
if (ustrregexm(X[i,1], infofence)) {
prespace[i] = ustrlen(ustrregexs(1))
fencel[i] = ustrlen(ustrregexs(2))
cb = 1
cbfl = fencel[i]
}
else if (ustrregexm(X[i,1], codefence)) {
prespace[i] = ustrlen(ustrregexs(1))
fencel[i] = ustrlen(ustrregexs(2))
if (cb & fencel[i]>=cbfl) {
codebegin[i] = -1
cb = 0
cbfl = 0
}
}
}
return(fence,codebegin,prespace,fencel)
}
string colvector function _info_tags(string colvector X) {
infofence = "^( ? ? ?)(```+|~~~+)\{?s(tata)?\/?(,.*)?\}?$"
//infofence
infotags = J(rows(X),1,"")
for (i=1; i<=rows(X); i++) {
if (ustrregexm(X[i,1], infofence)) {
infotags[i] = ustrregexs(4)
}
}
return(infotags)
}
real matrix function _tag_match(string colvector infotags) {
codeopts = ustrregexm(infotags, ",")
noeval = ustrregexm(infotags, "eval=FALSE")
noecho1 = ustrregexm(infotags, "echo=FALSE")
noecho2 = ustrregexm(infotags, "\/")
noecho = noecho1+noecho2
noresults = ustrregexm(infotags, "results=FALSE")
noprompt = ustrregexm(infotags, "noprompt=TRUE")
return(codeopts, noeval, noecho, noresults, noprompt)
}
string colvector function _dd_do(real matrix fenceinfo, real matrix tagmatch) {
dotags = J(rows(fenceinfo),1,"")
for (i=1; i<=rows(fenceinfo); i++) {
if (fenceinfo[i,2]==1) {
if (sum(tagmatch[i,.])==0) dotags[i,1]=("<>")
else if (tagmatch[i,3]==1) {
if (tagmatch[i,4]==0) dotags[i,1]=("<>")
else if (tagmatch[i,4]==1) dotags[i,1]=("<>")
}
else if (tagmatch[i,3]==0 & tagmatch[i,4]==1) dotags[i,1]=("<>")
else if (tagmatch[i,5]==1) dotags[i,1]=("<>")
}
else if (fenceinfo[i,2]==-1) dotags[i,1]=("<>")
else dotags[i,1]=("")
}
return(dotags)
}
string colvector function _gr_preamble() {
GR = "<>"\
"capture graph describe Graph"\
"tempname gdate"\
`"local \`gdate' = "\`r(command_date)' \`r(command_time)'" "'\
"<>"
return(GR)
}
string colvector function _gr_link() {
GL = `"<>"' \
`"capture graph describe Graph"' \
`"local checkdate = "\`r(command_date)' \`r(command_time)'" "' \
`"<>"' \
`"<>"' \
`"<>"' \
`"<>"' \
`"<>"' \
`"local \`gdate' = "\`r(command_date)' \`r(command_time)'""' \
`"<>"'
return(GL)
}
string colvector function _stitch(string colvector X,
real matrix fenceinfo, string colvector dotags) {
lce = 0
Y = _gr_preamble()
for (i=1; i<=rows(X); i++) {
//X[i,.]
if (fenceinfo[i,2]==1) {
Y = Y \ X[(lce+1)..i,.]\dotags[i,.]
lce = i
}
else if (fenceinfo[i,2]==-1) {
Y= Y \X[(lce+1)..(i-1),.]\dotags[i,.]\X[i,.]\_gr_link()
lce = i
}
}
return(Y)
}
string colvector function _inline_code(string colvector X) {
for (i=1; i<=rows(X); i++) {
dispdir = ustrregexm(X[i,1], "(`|~)\{?s(tata)?(.*)(`)")
while (dispdir) {
X[i,1] = ustrregexra(X[i,1], "(`|~)\{?s(tata)?", "<>")
dispdir = ustrregexm(X[i,1], "(`|~)\{?s(tata)?(.*)(`)")
}
}
return(X)
}
end