I'm working on a piece of software that outputs IPython Notebooks as tex documents. One of my requirements is to be able to draw code input output blocks that look like the Notebook's UI.
Disclaimer: For a long time I was using MDFRAMED to draw the cells. Unfortunately the vertical spacing of the MDFRAMED differs between versions, and I absolutely cannot force users to use a specific version of MDFRAMED. I looked into distributing MDFRAMED along with the software and found that it could not be done without modifications to MDFRAMED
So I bit the bullet and started writing my own custom framing logic in TIKz. My only requirements were to have rounded edges, a small border, support for multiple pages, and support for pygments output (fancyvrb Verbatim).
After a couple hours, I had completely met my goal:
BUT! When I try to use the Sphinx templates to produce my output:
The majority of the tikz code is this http://www.texample.net/tikz/examples/framed-tikz/ example modified
EDIT: After David's suggestion:
EDIT: MWE, with suggested solution(s). Produces same output as above.
% Make sure that the sphinx doc style knows who it inherits from.
\def\sphinxdocclass{article}
% Declare the document class
\documentclass[letterpaper,10pt,english]{/usr/local/lib/python2.7/dist-packages/Sphinx-1.2predev_20130207-py2.7.egg/sphinx/texinputs/sphinxhowto}
\usepackage[Bjarne]{/usr/local/lib/python2.7/dist-packages/Sphinx-1.2predev_20130207-py2.7.egg/sphinx/texinputs/fncychap}
\usepackage{/usr/local/lib/python2.7/dist-packages/Sphinx-1.2predev_20130207-py2.7.egg/sphinx/texinputs/sphinx}
\usepackage{graphicx} % Used to insert images
\usepackage{adjustbox} % Used to constrain images to a maximum size
\usepackage{color} % Allow colors to be defined
\usepackage{enumerate} % Needed for markdown enumerations to work
\usepackage{geometry} % Used to adjust the document margins
\usepackage{amsmath} % Equations
\usepackage{amssymb} % Equations
\usepackage[utf8]{inputenc} % Allow utf-8 characters in the tex document
\usepackage{ucs} % Extended unicode (utf-8) support
\usepackage{fancyvrb} % verbatim replacement that allows latex
\usepackage{grffile} % extends the file name processing of package graphics
%to support a larger range
% The hyperref package gives us a pdf with properly built
% internal navigation ('pdf bookmarks' for the table of contents,
% internal cross-reference links, web links for URLs, etc.)
\usepackage{hyperref}
\usepackage{tikz} % Needed to box output/input
\usepackage{scrextend} % Used to indent output
\usepackage{needspace} % Make prompts follow contents
\usepackage{framed} % Used to draw output that spans multiple pages
\definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
\definecolor{darkorange}{rgb}{.71,0.21,0.01}
\definecolor{darkgreen}{rgb}{.12,.54,.11}
\definecolor{myteal}{rgb}{.26, .44, .56}
\definecolor{gray}{gray}{0.45}
\definecolor{lightgray}{gray}{.95}
\definecolor{mediumgray}{gray}{.8}
\definecolor{inputbackground}{rgb}{.95, .95, .85}
\definecolor{outputbackground}{rgb}{.95, .95, .95}
\definecolor{traceback}{rgb}{1, .95, .95}
% new ansi colors
\definecolor{brown}{rgb}{0.54,0.27,0.07}
\definecolor{purple}{rgb}{0.5,0.0,0.5}
\definecolor{darkgray}{gray}{0.25}
\definecolor{lightred}{rgb}{1.0,0.39,0.28}
\definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
\definecolor{lightblue}{rgb}{0.53,0.81,0.92}
\definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
\definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
% Define a nice break command that doesn't care if a line doesn't already
% exist.
\def\br{\hspace*{\fill} \\* }
% Document parameters
\title{simpletest}
% Pygments definitions
\makeatletter
\def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax%
\let\PY@ul=\relax \let\PY@tc=\relax%
\let\PY@bc=\relax \let\PY@ff=\relax}
\def\PY@tok#1{\csname PY@tok@#1\endcsname}
\def\PY@toks#1+{\ifx\relax#1\empty\else%
\PY@tok{#1}\expandafter\PY@toks\fi}
\def\PY@do#1{\PY@bc{\PY@tc{\PY@ul{%
\PY@it{\PY@bf{\PY@ff{#1}}}}}}}
\def\PY#1#2{\PY@reset\PY@toks#1+\relax+\PY@do{#2}}
\expandafter\def\csname PY@tok@gd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
\expandafter\def\csname PY@tok@gu\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
\expandafter\def\csname PY@tok@gt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.25,0.82}{##1}}}
\expandafter\def\csname PY@tok@gs\endcsname{\let\PY@bf=\textbf}
\expandafter\def\csname PY@tok@gr\endcsname{\def\PY@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
\expandafter\def\csname PY@tok@cm\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@vg\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@m\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@mh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@go\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.50,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@ge\endcsname{\let\PY@it=\textit}
\expandafter\def\csname PY@tok@vc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@il\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@cs\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@cp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.74,0.48,0.00}{##1}}}
\expandafter\def\csname PY@tok@gi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
\expandafter\def\csname PY@tok@gh\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
\expandafter\def\csname PY@tok@ni\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.60,0.60,0.60}{##1}}}
\expandafter\def\csname PY@tok@nl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.63,0.00}{##1}}}
\expandafter\def\csname PY@tok@nn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
\expandafter\def\csname PY@tok@no\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.00,0.00}{##1}}}
\expandafter\def\csname PY@tok@na\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.49,0.56,0.16}{##1}}}
\expandafter\def\csname PY@tok@nb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@nc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
\expandafter\def\csname PY@tok@nd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
\expandafter\def\csname PY@tok@ne\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.82,0.25,0.23}{##1}}}
\expandafter\def\csname PY@tok@nf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
\expandafter\def\csname PY@tok@si\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
\expandafter\def\csname PY@tok@s2\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@vi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@nt\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@nv\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@s1\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@sh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@sc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@sx\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@bp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@c1\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@kc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@c\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
\expandafter\def\csname PY@tok@mf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@err\endcsname{\def\PY@bc##1{\setlength{\fboxsep}{0pt}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}
\expandafter\def\csname PY@tok@kd\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@ss\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
\expandafter\def\csname PY@tok@sr\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
\expandafter\def\csname PY@tok@mo\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@kn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@mi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@gp\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
\expandafter\def\csname PY@tok@o\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\expandafter\def\csname PY@tok@kr\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@s\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@kp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@w\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
\expandafter\def\csname PY@tok@kt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.69,0.00,0.25}{##1}}}
\expandafter\def\csname PY@tok@ow\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
\expandafter\def\csname PY@tok@sb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\expandafter\def\csname PY@tok@k\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\expandafter\def\csname PY@tok@se\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.13}{##1}}}
\expandafter\def\csname PY@tok@sd\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
\def\PYZbs{\char`\\}
\def\PYZus{\char`\_}
\def\PYZob{\char`\{}
\def\PYZcb{\char`\}}
\def\PYZca{\char`\^}
\def\PYZam{\char`\&}
\def\PYZlt{\char`\<}
\def\PYZgt{\char`\>}
\def\PYZsh{\char`\#}
\def\PYZpc{\char`\%}
\def\PYZdl{\char`\$}
\def\PYZti{\char`\~}
% for compatibility with earlier versions
\def\PYZat{@}
\def\PYZlb{[}
\def\PYZrb{]}
\makeatother
% NB prompt colors
\definecolor{nbframe-border}{rgb}{0.867,0.867,0.867}
\definecolor{nbframe-bg}{rgb}{0.969,0.969,0.969}
\definecolor{nbframe-in-prompt}{rgb}{0.0,0.0,0.502}
\definecolor{nbframe-out-prompt}{rgb}{0.545,0.0,0.0}
% NB prompt lengths
\newlength{\inputpadding}
\setlength{\inputpadding}{0.5em}
\newlength{\cellleftmargin}
\setlength{\cellleftmargin}{0.15\linewidth}
\newlength{\borderthickness}
\setlength{\borderthickness}{0.4pt}
\newlength{\smallerfontscale}
\setlength{\smallerfontscale}{9.5pt}
% NB prompt font size
\def\smaller{\fontsize{\smallerfontscale}{\smallerfontscale}\selectfont}
% Define a background layer, in which the nb prompt shape is drawn
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}
\usetikzlibrary{calc}
% define styles for the normal border and the torn border
\tikzset{
normal border/.style={draw=nbframe-border, fill=nbframe-bg,
rectangle, rounded corners=2.5pt, line width=\borderthickness},
torn border/.style={draw=white, fill=white, line width=\borderthickness}}
% Macro to draw the shape behind the text, when it fits completly in the
% page
\def\notebookcellframe#1{%
\tikz{%
\node[inner sep=\inputpadding] (A) {#1};% Draw the text of the node
\begin{pgfonlayer}{background}% Draw the shape behind
\fill[normal border]%
(A.south east) -- ($(A.south west)+(\cellleftmargin,0)$) --
($(A.north west)+(\cellleftmargin,0)$) -- (A.north east) -- cycle;
\end{pgfonlayer}}}%
% Macro to draw the shape, when the text will continue in next page
\def\notebookcellframetop#1{%
\tikz{%
\node[inner sep=\inputpadding] (A) {#1}; % Draw the text of the node
\begin{pgfonlayer}{background}
\fill[normal border] % Draw the ``complete shape'' behind
(A.south east) -- ($(A.south west)+(\cellleftmargin,0)$) --
($(A.north west)+(\cellleftmargin,0)$) -- (A.north east) -- cycle;
\fill[torn border] % Add the torn lower border
($(A.south east)-(0,.1)$) -- ($(A.south west)+(\cellleftmargin,-.1)$) --
($(A.south west)+(\cellleftmargin,.1)$) -- ($(A.south east)+(0,.1)$) -- cycle;
\end{pgfonlayer}}}
% Macro to draw the shape, when the text continues from previous page
\def\notebookcellframebottom#1{%
\tikz{%
\node[inner sep=\inputpadding] (A) {#1}; % Draw the text of the node
\begin{pgfonlayer}{background}
\fill[normal border] % Draw the ``complete shape'' behind
(A.south east) -- ($(A.south west)+(\cellleftmargin,0)$) --
($(A.north west)+(\cellleftmargin,0)$) -- (A.north east) -- cycle;
\fill[torn border] % Add the torn upper border
($(A.north east)-(0,.1)$) -- ($(A.north west)+(\cellleftmargin,-.1)$) --
($(A.north west)+(\cellleftmargin,.1)$) -- ($(A.north east)+(0,.1)$) -- cycle;
\end{pgfonlayer}}}
% Macro to draw the shape, when both the text continues from previous page
% and it will continue in next page
\def\notebookcellframemiddle#1{%
\tikz{%
\node[inner sep=\inputpadding] (A) {#1}; % Draw the text of the node
\begin{pgfonlayer}{background}
\fill[normal border] % Draw the ``complete shape'' behind
(A.south east) -- ($(A.south west)+(\cellleftmargin,0)$) --
($(A.north west)+(\cellleftmargin,0)$) -- (A.north east) -- cycle;
\fill[torn border] % Add the torn lower border
($(A.south east)-(0,.1)$) -- ($(A.south west)+(\cellleftmargin,-.1)$) --
($(A.south west)+(\cellleftmargin,.1)$) -- ($(A.south east)+(0,.1)$) -- cycle;
\fill[torn border] % Add the torn upper border
($(A.north east)-(0,.1)$) -- ($(A.north west)+(\cellleftmargin,-.1)$) --
($(A.north west)+(\cellleftmargin,.1)$) -- ($(A.north east)+(0,.1)$) -- cycle;
\end{pgfonlayer}}}
% Define the environment which puts the frame
% In this case, the environment also accepts an argument with an optional
% title (which defaults to ``Example'', which is typeset in a box overlaid
% on the top border
\newenvironment{notebookcell}[1][0]{%
\def\FrameCommand{\notebookcellframe}%
\def\FirstFrameCommand{\notebookcellframetop}%
\def\LastFrameCommand{\notebookcellframebottom}%
\def\MidFrameCommand{\notebookcellframemiddle}%
\par\vspace{1\baselineskip}%
\MakeFramed {\FrameRestore}%
\noindent\tikz\node[inner sep=0em] at ($(A.north west)-(0,0)$) {%
\begin{minipage}{\cellleftmargin}%
\hfill%
{\smaller%
\tt%
\color{nbframe-in-prompt}%
In [#1]:}%
\hspace{\inputpadding}%
\hspace{2pt}%
\hspace{3pt}%
\end{minipage}%%
}; \par}%
{\endMakeFramed}
\sloppy % Prevent overflowing lines due to hard-to-break entities
% Setup hyperref package
\hypersetup{
breaklinks=true, % so long urls are correctly broken across lines
colorlinks=true,
urlcolor=blue,
linkcolor=darkorange,
citecolor=darkgreen,
}
% Slightly bigger margins than the latex defaults
\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
% Override to specify your own logo
\newcommand{\sphinxlogo}{}
% Make the index page of the document.
\makeindex
\begin{document}
\maketitle
This is a \emph{simple} notebook
% Add contents below.
{\par%
\vspace{-1\baselineskip}%
\needspace{4\baselineskip}}%
\begin{notebookcell}[1]%
\begin{addmargin}[\cellleftmargin]{0em}% left, right
{\smaller%
\par%
%
\vspace{-1\smallerfontscale}%
\begin{Verbatim}[commandchars=\\\{\}]
\PY{k}{print}\PY{p}{(}\PY{l+s}{"}\PY{l+s}{Which has a simple task}\PY{l+s+se}{\PYZbs{}n}\PY{l+s}{Seriously...}\PY{l+s}{"}\PY{p}{)}
\PY{k}{print}\PY{p}{(}\PY{l+s}{"}\PY{l+s}{Cool!}\PY{l+s}{"}\PY{p}{)}
\end{Verbatim}
%
\par%
\vspace{-1\smallerfontscale}}%
\end{addmargin}
\end{notebookcell}
\par\vspace{1\smallerfontscale}%
% Only render the prompt if the cell is pyout. Note, the outputs prompt
% block isn't used since we need to check each indiviual output and only
% add prompts to the pyout ones.
%
%
\begin{addmargin}[\cellleftmargin]{0em}% left, right
{\smaller%
\vspace{-1\smallerfontscale}%
\begin{Verbatim}[commandchars=\\\{\}]
Which has a simple task
Seriously...
Cool!
\end{Verbatim}
}%
\end{addmargin}%
% Add contents below.
{\par%
\vspace{-1\baselineskip}%
\needspace{4\baselineskip}}%
\begin{notebookcell}[2]%
\begin{addmargin}[\cellleftmargin]{0em}% left, right
{\smaller%
\par%
%
\vspace{-1\smallerfontscale}%
\begin{Verbatim}[commandchars=\\\{\}]
\PY{l+s}{"}\PY{l+s}{To print hello world}\PY{l+s+se}{\PYZbs{}n}\PY{l+s}{Multiple lines}\PY{l+s}{"}
\end{Verbatim}
%
\par%
\vspace{-1\smallerfontscale}}%
\end{addmargin}
\end{notebookcell}
\par\vspace{1\smallerfontscale}%
% Only render the prompt if the cell is pyout. Note, the outputs prompt
% block isn't used since we need to check each indiviual output and only
% add prompts to the pyout ones.
{\par%
\vspace{-1\smallerfontscale}%
\noindent%
\begin{minipage}{\cellleftmargin}%
\hfill%
{\smaller%
\tt%
\color{nbframe-out-prompt}%
Out[2]:}%
\hspace{\inputpadding}%
\hspace{0em}%
\hspace{3pt}%
\end{minipage}%%
}%
%
%
\begin{addmargin}[\cellleftmargin]{0em}% left, right
{\smaller%
\vspace{-1\smallerfontscale}%
\begin{verbatim}
'To print hello world\nMultiple lines'
\end{verbatim}
}%
\end{addmargin}%
\end{document}
def\notebookcellframe#1{
and similar definitions missing a%
after the{
which will typically offset the contents by one word space.