*! version 1.3 16apr2024 Gorkem Aksaray *! Restyle LaTeX tables exported by the collect suite of commands *! *! Changelog *! --------- *! [1.3] *! - Added three size options: pt() for setting the size of the main *! font used in the document, papersize() for setting the paper size, *! and tabsize() for setting the size of the font used in the table. *! [1.2.2] *! - usepackage() option when specified with LaTeX package names that *! do not satisfy the naming convention of Stata (e.g., unicode-math) *! was causing error. This is now fixed. *! [1.2.1] *! - Automatic conversion of hyphens as minus signs to en dashes in math *! mode to ensure proper typographic representation. *! [1.2] *! - Added usepackage() option to add LaTeX packages to the preamble. *! - geometry and lipsum options are removed as they are now redundant *! with the addition of usepackage() option. *! - beforetext() and aftertext() options can now add multiple lines *! delimited by quotation marks. They also automatically define \sq{} *! and \dq{} macros for single and double quotes used within text. *! - Better handling of repeatable options. *! [1.1] *! - Allow for multiple paragraphs of text before and after table. *! - Added lipsum() and geometry() options. *! [1.0] *! - Initial public release. capture program drop styletextab program styletextab, rclass version 18 // Repeatable options local repeated_option_maxcount = 9 // can increase if needed! forvalues i = 0/`repeated_option_maxcount' { local usepackage "`usepackage' USEPackage`i'(string asis)" local beforetext "`beforetext' BEFOREtext`i'(string asis)" local aftertext "`aftertext' AFTERtext`i'(string asis)" } syntax [using/] [, /// SAVing(string asis) /// FRAGment /// TABLEonly /// LScape /// noBOOKtabs /// LABel(string) /// `usepackage' /// `beforetext' /// `aftertext' /// pt(numlist min=1 max=1 >=10 <=12 int) /// PAPERsize(string) /// TABSize(string) /// ] local global_skip = 2 if `"`using'"' == "" { if `"`s(filename)'"' == "" { di as err "last TeX table from {bf: collect export} not found" exit 197 } else { local using `"`s(filename)'"' } } if `"`saving'"' == "" { local saving `"`using'"' local replace "replace" } else if `"`saving'"' != "" { local _using `"`using'"' // protect main `using' local 0 `"using `saving'"' syntax using/ [, replace] local saving `"`using'"' local replace "`replace'" local using `"`_using'"' } mata: suffix = subinstr(pathsuffix(`"`using'"'), ".", "") mata: st_local("suffix", suffix) if `"`suffix'"' == "" { local suffix "tex" local using `"`using'.`suffix'"' } else if `"`suffix'"' != "tex" { di as err "{p 0 0 2}" di as err "incorrect file type specified" di as err "in {bf:using};" di as err "only .tex files allowed" di as err "{p_end}" exit 198 } mata: suffix = subinstr(pathsuffix(`"`saving'"'), ".", "") mata: st_local("suffix", suffix) if `"`suffix'"' == "" { local suffix "tex" local saving `"`saving'.`suffix'"' } else if `"`suffix'"' != "tex" { di as err "{p 0 0 2}" di as err "incorrect file type specified" di as err "in {bf:saving()};" di as err "only .tex files allowed" di as err "{p_end}" exit 198 } capture assert /// inlist("`papersize'", "a0", "a1", "a2", "a3", "a4", "a5", "a6") | /// inlist("`papersize'", "b0", "b1", "b2", "b3", "b4", "b5", "b6") | /// inlist("`papersize'", "c0", "c1", "c2", "c3", "c4", "c5", "c6") | /// inlist("`papersize'", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j") | /// inlist("`papersize'", "ansia", "ansib", "ansic", "ansid", "ansie") | /// inlist("`papersize'", "letter", "executive", "legal", "") if _rc == 9 { di as err "{p 0 0 2}" di as err "incorrect paper size specified" di as err "{p_end}" exit 198 } capture assert /// inlist("`tabsize'", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large", "Large", "LARGE", "huge", "Huge", "") if _rc == 9 { di as err "{p 0 0 2}" di as err "incorrect table size specified" di as err "{p_end}" exit 198 } confirm file `"`using'"' tempname fh tempname tf tempfile tmp file open `fh' using `"`using'"', read file open `tf' using `"`tmp'"', write if "`fragment'" == "" { if "`tableonly'" == "" { * preamble if "`pt'" != "" { local pt "`pt'pt" } if "`papersize'" != "" { local papersize "`papersize'paper" } local docclassopts = subinstr(`"`= strtrim("`pt' `papersize'")'"', " ", ",", .) file write `tf' "\documentclass[`docclassopts']{article}" _n if `"`usepackage0'"' != "" { forvalues i = 0/`repeated_option_maxcount' { if `"`usepackage`i''"' != "" { local 0 `"`usepackage`i''"' syntax anything(name=pkgname id="package name") [, /// opt(string) opts(string) pre Nextlines(string asis)] if "`pre'" == "" { continue } if "`opt'" != "" & "`opts'" != "" { di as err "options opt() and opts() may not be used simultaneously" exit 198 } if "`opt'" == "" & "`opts'" == "" { file write `tf' `"\usepackage{`pkgname'}"' _n } else if "`opt'" != "" { file write `tf' `"\usepackage[`opt']{`pkgname'}"' _n } else if "`opts'" != "" { file write `tf' "\usepackage[" _n tokenize "`opts'", parse(",") if "`1'" == "," { macro shift continue } file write `tf' _skip(`global_skip') "`1'" macro shift while "`1'" != "" { if "`1'" == "," { macro shift continue } file write `tf' "," _n _skip(`global_skip') "`1'" macro shift } file write `tf' _n `"]{`pkgname'}"' _n } tokenize `"`nextlines'"', parse(`"""') while "`1'" != "" { file write `tf' "`1'" _n macro shift } } } } if "`lscape'" != "" { file write `tf' "\usepackage{pdflscape}" _n } if "`booktabs'" != "nobooktabs" { file write `tf' "\usepackage{booktabs}" _n } file write `tf' "\usepackage{multirow}" _n file write `tf' "\usepackage[para,flushleft]{threeparttable}" _n file write `tf' "\usepackage{amsmath}" _n file write `tf' "\usepackage{ulem}" _n file write `tf' "\usepackage[table]{xcolor}" _n if `"`usepackage0'"' != "" { forvalues i = 0/`repeated_option_maxcount' { if `"`usepackage`i''"' != "" { local 0 `"`usepackage`i''"' syntax anything(name=pkgname id="package name") [, /// opt(string) opts(string) pre Nextlines(string asis)] if "`pre'" != "" { continue } if "`opt'" != "" & "`opts'" != "" { di as err "options opt() and opts() may not be used simultaneously" exit 198 } if "`opt'" == "" & "`opts'" == "" { file write `tf' `"\usepackage{`pkgname'}"' _n } else if "`opt'" != "" { file write `tf' `"\usepackage[`opt']{`pkgname'}"' _n } else if "`opts'" != "" { file write `tf' "\usepackage[" _n tokenize "`opts'", parse(",") if "`1'" == "," { macro shift continue } file write `tf' _skip(`global_skip') "`1'" macro shift while "`1'" != "" { if "`1'" == "," { macro shift continue } file write `tf' "," _n _skip(`global_skip') "`1'" macro shift } file write `tf' _n `"]{`pkgname'}"' _n } tokenize `"`nextlines'"', parse(`"""') while "`1'" != "" { file write `tf' "`1'" _n macro shift } } } } if `"`beforetext0'`aftertext0'"' != "" { file write `tf' "\newcommand{\sq}[1]{\`#1'}" _n file write `tf' "\newcommand{\dq}[1]{\`\`#1''}" _n } file write `tf' "\begin{document}" _n * beforetext if `"`beforetext0'"' != "" { forvalues i = 0/`repeated_option_maxcount' { if `"`beforetext`i''"' != "" { file write `tf' _n tokenize `"`beforetext`i''"', parse(`"""') while "`1'" != "" { file write `tf' "`1'" _n macro shift } } } file write `tf' _n } } // tableonly if "`lscape'" != "" { file write `tf' "\begin{landscape}" _n } file write `tf' "\begin{table}[!h]" _n if "`tabsize'" != "" { file write `tf' "\\`tabsize'" _n } * caption file seek `fh' tof file read `fh' line while r(eof) == 0 { if strpos(`"`macval(line)'"', "\caption") != 0 { file write `tf' `"`macval(line)'"' _n if "`label'" != "" { file write `tf' "\label{`label'}" _n } } else if `"`macval(line)'"' == "\centering" { file write `tf' `"`macval(line)'"' _n file seek `fh' eof } file read `fh' line } file write `tf' "\begin{threeparttable}" _n } // fragment * tabular file seek `fh' tof file read `fh' line local keepline = 0 while r(eof) == 0 { if strpos(`"`macval(line)'"', "\begin{tabular}") != 0 { local keepline = 1 } if `keepline' == 1 { if "`booktabs'" == "nobooktabs" & strpos(`"`macval(line)'"', "\cmidrule") != 0 { local newline = subinstr(`"`macval(line)'"', "\cmidrule", "\cline", .) file write `tf' `"`newline'"' _n } else if "`booktabs'" != "nobooktabs" & strpos(`"`macval(line)'"', "\cline") != 0 { local newline = subinstr(`"`macval(line)'"', "\cline", "\cmidrule", .) file write `tf' `"`newline'"' _n } else if regexm(`"`macval(line)'"', "\\multicolumn{([0-9])}{([|]?[clr][|]?)}{-([^\}]*)}") { local newline = /// regexreplaceall(`"`macval(line)'"', /// "\\multicolumn{[0-9]}{[|]?[clr][|]?}{-[^\}]*}", /// "\\multicolumn{"+regexs(1)+"}{"+regexs(2)+"}{\\$-\\$"+regexs(3)+"}") file write `tf' `"`newline'"' _n } else { file write `tf' `"`macval(line)'"' _n } } if strpos(`"`macval(line)'"', "\end{tabular}") != 0 { local keepline = 0 } file read `fh' line } if "`fragment'" == "" { file write `tf' "\begin{tablenotes}" _n * footnotes file seek `fh' tof file read `fh' line local keepline = 0 while r(eof) == 0 { if `"`macval(line)'"' == "\footnotesize{" { local keepline = 1 } if `keepline' == 1 { file write `tf' `"`macval(line)'"' _n } if `"`macval(line)'"' == "}" { local keepline = 0 } file read `fh' line } file write `tf' "\end{tablenotes}" _n file write `tf' "\end{threeparttable}" _n file write `tf' "\end{table}" _n if "`lscape'" != "" { file write `tf' "\end{landscape}" _n } if "`tableonly'" == "" { * aftertext if `"`aftertext0'"' != "" { forvalues i = 0/`repeated_option_maxcount' { if `"`aftertext`i''"' != "" { file write `tf' _n tokenize `"`aftertext`i''"', parse(`"""') while "`1'" != "" { file write `tf' "`1'" _n macro shift } } } file write `tf' _n } file write `tf' "\end{document}" _n } // tableonly } // fragment file close `fh' file close `tf' copy `"`tmp'"' `"`saving'"', `replace' mata: st_local("basename", pathbasename(`"`saving'"')) di as txt `"(LaTeX table saved to file {browse `"`saving'"':`basename'})"' end