First time poster.
I've been trying to work out how to combine the answers presented to these questions: Directory tree on multiple pages using Forest package
How to insert folder icon in root node with forest package
And a few other related variations on these questions on SE. The end goal is to be able to produce filesystem trees / directory trees in larger PDF documents by transforming the XML output of the tree command (as tree -X directory
) using the following set of pipes:
sed '1,2d' tree-output.xml |tac | sed '1,5d' | tac | sed 's/<file name=\"/[/g' | sed 's/\"><\/file>/]/g' | sed 's/<directory name=\"/[/g' | sed 's/\">//g' | sed 's/<\/directory>/]/g' >> transformed-tree.tex
And to then include the transformed tree in a TeX file using \include{transformed-tree}
So far the set of pipes work...and it seems to output things correctly for forest to parse into a folder tree. The transformation is included just as background information. I know the output differs from that found in the code below (was manually tinkering with the [ filename, file]
notation from Making a directory tree of folders and files
and from How to insert folder icon in root node with forest package)
What I am having trouble with is with having that tree display correctly when the tree must span multiple pages.
I do not yet know TeX enough to know where I'm going wrong. Here is a (non)working example. It compiles, but the page-breaks make the folder/file icons stop working, and the vertical spacing is all out of whack:
% from https://tex.stackexchange.com/questions/405192/how-to-insert-folder-icon-in-root-node-with-forest-package/405253#405253
% and https://tex.stackexchange.com/questions/356749/directory-tree-on-multiple-pages-using-forest-package
\documentclass[border=10pt,multi,tikz]{article}
\usepackage[edges]{forest}
\definecolor{folderbg}{RGB}{124,166,198}
\definecolor{folderborder}{RGB}{110,144,169}
\newlength\Size
\setlength\Size{4pt}
\tikzset{%
folder/.pic={%
\filldraw [draw=folderborder, top color=folderbg!50, bottom color=folderbg] (-1.05*\Size,0.2\Size+5pt) rectangle ++(.75*\Size,-0.2\Size-5pt);
\filldraw [draw=folderborder, top color=folderbg!50, bottom color=folderbg] (-1.15*\Size,-\Size) rectangle (1.15*\Size,\Size);
},
file/.pic={%
\filldraw [draw=folderborder, top color=folderbg!5, bottom color=folderbg!10] (-\Size,.4*\Size+5pt) coordinate (a) |- (\Size,-1.2*\Size) coordinate (b) -- ++(0,1.6*\Size) coordinate (c) -- ++(-5pt,5pt) coordinate (d) -- cycle (d) |- (c) ;
},
}
\forestset{%
declare autowrapped toks={pic me}{},
declare boolean register={pic root},
pic root=0,
pic dir tree/.style={%
for tree={%
folder,
font=\ttfamily,
grow'=0,
},
before typesetting nodes={%
for tree={%
edge label+/.option={pic me},
},
if pic root={
tikz+={
\pic at ([xshift=\Size].west) {folder};
},
align={l}
}{},
},
},
pic me set/.code n args=2{%
\forestset{%
#1/.style={%
inner xsep=2\Size,
pic me={pic {#2}},
}
}
},
pic me set={directory}{folder},
pic me set={file}{file},
}
%begin from https://tex.stackexchange.com/questions/356749/directory-tree-on-multiple-pages-using-forest-package
\def\hiddenparcommand{\par}
\newcommand\otherhiddenparcommand{\par\noindent}
\newcommand\hiddencommacommand{, }
\forestset{%
declare keylist register={split here ids},% the list of nodes to split the tree at
split here ids={},
declare keylist register={split here interjects},% the list of comments to put in between the tree parts
split here interjects={},
declare keylist={split here auto siblings}{},% a list to hold the siblings which need edge restoration
declare toks register=split here toks,
declare dimen register=tmpdima,
tmpdima'=0pt,
declare dimen register=tmpdimb,
tmpdimb'=0pt,
declare dimen register=tmpdimc,
tmpdimc'=0pt,
to widest/.style={
tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});},
},
hide commas/.style={%
split here toks+={\hiddencommacommand},
split here toks+={#1},
},
split dir tree pre/.style={%
label={[text=gray, anchor=north, font=\scriptsize]below:{[cont.]}{}},
},
split dir tree post/.style={%
label={[font=\scriptsize, anchor=south, text=gray]above:{[cont.]}{}},
},
split dir tree auto post/.style={% this gets applied to the first node after a break
split dir tree post,
tempkeylistc'={},
tmpdimb/.option=y,
for nodewalk={
while={
> ORw2+d _+d < On=! & {y}{tmpdimb}{##2-##1} {\textheight-#1} {n'}{1}%
}{
next,
tempkeylistc/.option=name
}%
}{},
% save the list
split here auto siblings/.register=tempkeylistc,
tikz+/.process={% this tries to redraw the edges to the following siblings
OOw2{edge}{id}%
{%
\path [##1] (!u.parent anchor |- .north) ++(\forestregister{folder indent},1ex) coordinate (before ##2) |- (.child anchor);
\edef\tempa{\foresteoption{split here auto siblings}}
\foreach \i in \tempa \path [##1] (before ##2) |- ({forest cs:\i.child anchor});
}%
},
},
split dir tree/.code={%
\forestset{%
draw tree stage/.style={
for root'={
tempdima/.min={%
>OOw2+d{x}{min x}{####1+####2}%
}{tree},
tempdimb/.max={%
>OOw2+d{x}{max x}{####1+####2}%
}{tree},
for tree={%
to widest,
},
},
tempcountb'=-1,
do until={%
strequal((split_here_ids),"")
}{%
tempkeylistb'={},
tempkeylista'={},
split register={split here ids}{,}{tempcounta,tempkeylistb+},
split register={split here interjects}{,}{temptoksa,tempkeylista+},
split here ids'/.register=tempkeylistb,
split here interjects'/.register=tempkeylista,
% Sašo Živanović: http://chat.stackexchange.com/transcript/message/28484520#28484520
for nodewalk={%
draw tree processing order/.style={%
filter={tree}{> ORw+n< OR> & {id}{tempcounta}{########1+1}{id}{tempcountb}}%
}%
}{},
for root'={draw tree},
TeX/.process={Rw{temptoksa}{\otherhiddenparcommand ####1\hiddenparcommand}},
tempcountb'/.register=tempcounta,
},
for nodewalk={%
draw tree processing order/.style={%
filter={tree}{>OR>{id}{tempcountb}}%
}%
}{},
for root'={draw tree},
},
}%
},
split dir here auto/.style n args=2{%
split dir tree pre,
!next node.split dir tree auto post=#2,
split here ids+/.option=id,
% !next node.split resume here ids+/.option=id,
split={#1}{,}{split here toks,hide commas},
split here interjects/.register=split here toks,
},
split dir tree auto/.style={%
split dir tree,
before drawing tree={%
tempdima/.max={y}{tree},
tempdimc/.register=tempdima,
tempdimd/.min={y}{tree},
tempdima-/.register=tempdimd,
tempdimb'=\textheight,
tmpdima'=10ex,
tmpdimc'=\pagetotal,
while={%
>RR>{tempdima}{tempdimb}%
}{%
for nodewalk={%
root',
until={%
> ROw2+d RRw2+d > {tempdimc}{y}{##1-##2} {tmpdima}{tmpdimc}{\textheight-##2-##1}%
}{next node},
previous node,
split dir here auto/.process={R_w2{tmpdima}{continued}{{##2}{##1}}},
next node,
tempdima/.option=y,
tempdimc/.register=tempdima,
tempdima-/.register=tempdimd,
tmpdima'=15ex,
tmpdimc'=0pt
}{},
},
},
},
}
%end from https://tex.stackexchange.com/questions/356749/directory-tree-on-multiple-pages-using-forest-package
\begin{document}
\begin{forest}
pic dir tree,
pic root,
for tree={% folder icons by default; override using file for file icons
directory,
folder,% this and next 2 lines from https://tex.stackexchange.com/questions/356749/directory-tree-on-multiple-pages-using-forest-package
grow'=0,
fit=band
},
split dir tree auto, % line from https://tex.stackexchange.com/questions/339669/automatic-page-break-with-forest-spanning-a-tree-over-multiple-pages
[ .
[ 1.txt, file ]
[ MyShelve, file ]
[ Pipfile, file ]
[ Pipfile.lock, file ]
[ cl.py, file ]
[ clasync.py, file ]
[ ex1.py, file ]
[ ex10-2.py, file ]
[ ex11-3.py, file ]
[ ex12-4.py, file ]
[ ex12-4a.py, file ]
[ ex13.py, file ]
[ ex14.py, file ]
[ ex15.py, file ]
[ ex16.py, file ]
[ ex17-loops.py, file ]
[ ex17.py, file ]
[ ex18.py, file ]
[ freewrite
[ devel
[ fwprompt.py, file ]
[ makephrases.py, file ]
[ prompt2.py, file ]
]
[ makephrases.py, file ]
[ phraseprompt.py, file ]
[ phrases.txt, file ]
]
[ jt.py, file ]
[ jt1.py, file ]
[ jt2.py, file ]
[ jt2a.py, file ]
[ jt3.py, file ]
[ jt4.py, file ]
[ jt5.py, file ]
[ jt6.py, file ]
[ jt7.py, file ]
[ jt8.py, file ]
[ python-script-examples
[ README.md , file]
[ Vagrantfile , file]
[ automate-ssh-with-netmiko
[ collect-cdp-information.py, file ]
[ result.html, file ]
]
[ cisco-ios-config-parameter-extraction
]
[ cisco-nx-api-example
[ interface-description-cleaner.py, file ]
]
[ config-generator-with-custom-filters
[ config-generator-with-custom-filter.py, file ]
[ ip-interface-config.jinja2, file ]
[ parameters.json, file ]
]
[ config-generator-with-python-and-jinja2
[ parameters.csv, file ]
[ parameters.json, file ]
[ switch.j2, file ]
]
[ create-hsrp-interface-configuration
[ create-hsrp-interface-configuration.py, file ]
]
[ json-code-example
[ cl.py, file ]
[ cl1.py, file ]
[ cl2.py, file ]
]
[ jupyter-config
[ 10-nb-import-hook.py, file ]
[ about.ipynb, file ]
[ jupyter-notebook.upstart, file ]
]
[ migrate-static-arp-entries
[ create-migration-templates.py, file ]
]
[ notebooks
[ Introduction to the ipaddress module with IPv4.ipynb, file ]
[ Introduction to the ipaddress module with IPv6.ipynb, file ]
[ pandas
[ Merge DataFrames in Pandas.ipynb, file ]
]
]
[ parse-show-inventory-with-textfsm
]
[ requirements.txt, file ]
[ setup.yaml, file ]
]
]
[ shellsets.txt , file]
[ skele-cli
[ MANIFEST.in , file]
[ README.rst , file]
[ setup.cfg , file]
[ setup.py , file]
[ skele
[ cli.py , file]
[ commands
[ base.py , file]
[ hello.py, file ]
]
]
[ tests
[ commands
]
]
]
[ test
[ a
[ boo, file ]
[ boo123, file ]
]
[ b
[ boo12, file ]
[ boo123 , file]
[ c
[ boot, file ]
[ boot1, file ]
[ boot13, file ]
]
]
[ boo ]
[ boo1 ]
[ boo12 ]
[ boo123 ]
]
[ todo.txt, file ]
[ treestuff
[ dirtree.pl , file]
[ familytree.pdf , file]
[ familytree.tex , file]
[ forest-close.tex , file]
[ forest-example-2.aux, file ]
[ forest-example-2.dvi, file ]
[ forest-example-2.fls, file ]
[ forest-example-2.log , file]
[ forest-example-2.pdf, file ]
[ forest-example-2.tex, file ]
[ forest-header.tex, file ]
[ forest-standalone-frame.tex, file ]
[ forest-start.tex, file ]
[ forest.ex.tex, file ]
[ forest.ex1.tex, file ]
[ fortt.pdf, file ]
[ fortt.tex, file ]
[ fortt1.tex, file ]
[ fortt2.pdf, file ]
[ fortt2.tex, file ]
[ fortt3.pdf, file ]
[ fortt3.tex, file ]
[ fortt4.pdf, file ]
[ fortt4.tex, file ]
[ fortt5.pdf, file ]
[ fortt5.tex, file ]
[ testtree.xml, file ]
[ textree.pdf, file ]
[ textree.tex, file ]
[ tikz-tree-sample.tex, file ]
[ tree.forest.tex, file ]
[ tree.json, file ]
[ tree.xml, file ]
[ tree1.xml, file ]
[ tree1.xml.forest, file ]
[ tree2.xml.tex, file ]
[ treedir.tex, file ]
[ treetest.tex, file ]
[ xmltree.to.forest.txt, file ]
]
\end{forest}
\end{document}
This is what the output looks like (output pdf burst into single pages using ghostscript, each page exported as PNG using Preview.app):
You may have noticed dirtree.pl
listed among the files in the example tree above. Trying to use forest
instead of dirtree
because I cannot read dirtree as easily as forest trees and am aiming to generate good looking directory structure trees.
EDITS BEGIN HERE
Followup Q: Would an answer to my question be different if there was need to arbitrarily include trees in a document via ~~\include{}
s?~~ \input{}
?
I ask because I noticed that these uses of the forest
package seem to require code (\forestset{}
) before and after \begin{document}
and I was thinking of generating documents using snippets of code where preambles and code would be put together using a bash script...with the actual forest generated by a variation of the pipeline above...
An alternative solution might be to generate the forest tree graphic as a standalone pdf using this code...
\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage[edges]{forest}
\definecolor{folderbg}{RGB}{124,166,198}
\definecolor{folderborder}{RGB}{110,144,169}
\newlength\Size
\setlength\Size{4pt}
\tikzset{%
folder/.pic={%
\filldraw [draw=folderborder, top color=folderbg!50, bottom color=folderbg] (-1.05*\Size,0.2\Size+5pt) rectangle ++ (.75*\Size,-0.2\Size-5pt);
\filldraw [draw=folderborder, top color=folderbg!50, bottom color=folderbg] (-1.15*\Size,-\Size) rectangle (1.15*\Size,\Size);
},
file/.pic={%
\filldraw [draw=folderborder, top color=folderbg!5, bottom color=folderbg!10] (-\Size,.4*\Size+5pt) coordinate (a) |- (\Size,-1.2*\Size) coordinate (b) -- ++(0,1.6*\Size) coordinate (c) -- ++ (-5pt,5pt) coordinate (d) -- cycle (d) |- (c) ;
},
}
\forestset{%
declare autowrapped toks={pic me}{},
declare boolean register={pic root},
pic root=0,
pic dir tree/.style={%
for tree={%
folder,
font=\ttfamily,
grow'=0,
},
before typesetting nodes={%
for tree={%
edge label+/.option={pic me},
},
if pic root={
tikz+={
\pic at ([xshift=\Size].west) {folder};
},
align={l}
}{},
},
},
pic me set/.code n args=2{%
\forestset{%
#1/.style={%
inner xsep=2\Size,
pic me={pic {#2}},
}
}
},
pic me set={directory}{folder},
pic me set={file}{file},
}
\begin{document}
\begin{forest}
pic dir tree,
pic root,
for tree={% folder icons by default; override using file for file icons
directory,
},
\input{transformed-tree}
\end{forest}
\end{document}
Where transformed-tree
refers to a transformed-tree.tex
(as above in transformation pipeline).
And I was able to break it up into multiple pages using this code:
\documentclass[letterpaper]{minimal}
\usepackage[pdftex,letterpaper]{geometry}
\usepackage{graphicx}
\begin{document}
\includegraphics[viewport={0 3030pt 400pt 2525pt},clip]{ftrn2a.pdf}
\newpage
\includegraphics[viewport={0 2525pt 400pt 2020pt},clip]{ftrn2a.pdf}
\newpage
\includegraphics[viewport={0 2020pt 400pt 1515pt},clip]{ftrn2a.pdf}
\newpage
\includegraphics[viewport={0 1515pt 400pt 1010pt},clip]{ftrn2a.pdf}
\newpage
\includegraphics[viewport={0 1010pt 400pt 505pt},clip]{ftrn2a.pdf}
\newpage
\includegraphics[viewport={0 505pt 400pt 0},clip]{ftrn2a.pdf}
\end{document}
I first had to figure out the total size of the standalone tree pdf... I did that with this:
pdfinfo -box ftrn2a.pdf | grep "Page size" | cut -d ' ' -f 8,10 | echo "
cut -d ' ' -f 2/ 750" | bc -l | cut -d '.' -f 1
and then used a calculator after figuring out that about 500pt would look OK per page...
The output from this has its own issues...such as cutting across words and icons...
While this might work in a pinch, I believe lots of time might need to be spent tweaking the viewport settings to avoid cutting across any text.
\includepdf
? or some similar approach?\include{}
here at all. That's for things like entire chapters. You probably want\input{}
or similar instead. I don't understand the question about arbitrary\include{}
anyway. What do you mean by this exactly? Why would it be a problem if you needed code before and after\begin{document}
? I can't imagine why you'd need\forestset{}
before and after\begin{document}
. Can you give an example? Why do you think this is required? That is: I can't see why that's required but, if it is, I don't see why that's a problem, but using\include{}
here is anyway wrong.pic
stuff out, I can't compile it at all. Can you post the working version you have without the icons?\include{}
and\input{}
The aim was to be able to cobble together trees using multiple files and *nix shell utilities to automate the creation of trees.\include{}
is wrong and not at all like\input{}
. Why can't you use\input
?