Skip to content

Instantly share code, notes, and snippets.

@lericson
Last active August 29, 2015 13:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lericson/9761314 to your computer and use it in GitHub Desktop.
Save lericson/9761314 to your computer and use it in GitHub Desktop.
Assignment PDF creator tool automator
#!/usr/bin/env python
# encoding: utf-8
"""Make an assignment pdf file from assignment.md + src directory
First run this:
sudo easy_install markdown pygments
Also, you have to have a title in the markdown file, i.e. a line starting with #
"""
import os
import sys
import optparse
import pygments
from pygments.lexers import guess_lexer_for_filename
from pygments.lexers.special import TextLexer
from pygments.formatters.html import HtmlFormatter
from markdown import markdown as html_markdown
p = optparse.OptionParser()
p.add_option('--readme', '-r', help="README file, guessed automatically")
p.add_option('--sources', '-s', default='src')
opts, args = p.parse_args()
if not opts.readme:
for fn in ('assignment.md', 'README.md'):
if os.path.isfile(fn):
opts.readme = fn
break
else:
raise RuntimeError('no readme file found! use --readme to set a non-standard README filenames')
with open(opts.readme) as fp:
body = html_markdown(fp.read().decode('utf-8'), output_format='html5')
title = body.split('<h1>', 1)[1].split('</h1>', 1)[0]
print u"""
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
line-height: 1.125em;
margin: 0.5em 0 1em 0;
padding: 0;
}
img {
max-width: 100%;
/*max-height: 105mm;*/
}
* {
tab-size: 2;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
width: 170mm;
padding: 0 20mm;
}
@media only screen {
body {
margin: 0 auto;
}
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
}
h1 {
font-size: 30px;
line-height: 1.125em;
text-align: center;
}
h2 {
font-size: 24px;
line-height: 1.125em;
}
h3 {
font-size: 18px;
line-height: 1.125em;
}
h4 {
font-size: 16px;
line-height: 1.125em;
}
h5 {
font-size: 14px;
line-height: 1.125em;
}
h6 {
font-size: 13px;
line-height: 1.125em;
}
p {
line-height: 1.25em;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
h1, h2, h3, h4, blockquote {
page-break-before: avoid;
page-break-inside: avoid;
page-break-after: avoid;
}
table, .attachment {
page-break-inside: avoid;
overflow: hidden;
}
}
.sourcetable .linenos {
padding: 0 5px 0 0;
}
.sourcetable pre {
font: 13px monospace;
line-height: 13px;
word-wrap: normal;
white-space: pre;
margin: 0;
padding: 0;
border: 0;
}
.sourcetable td, .sourcetable th, .sourcetable div {
border: 0;
padding: 0;
}
.source .c { color: #408080; font-style: italic } /* Comment */
.source .err { border: 1px solid #FF0000 } /* Error */
.source .k { color: #008000; font-weight: bold } /* Keyword */
.source .o { color: #666666 } /* Operator */
.source .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.source .cp { color: #BC7A00 } /* Comment.Preproc */
.source .c1 { color: #408080; font-style: italic } /* Comment.Single */
.source .cs { color: #408080; font-style: italic } /* Comment.Special */
.source .gd { color: #A00000 } /* Generic.Deleted */
.source .ge { font-style: italic } /* Generic.Emph */
.source .gr { color: #FF0000 } /* Generic.Error */
.source .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.source .gi { color: #00A000 } /* Generic.Inserted */
.source .go { color: #808080 } /* Generic.Output */
.source .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.source .gs { font-weight: bold } /* Generic.Strong */
.source .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.source .gt { color: #0040D0 } /* Generic.Traceback */
.source .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.source .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.source .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.source .kp { color: #008000 } /* Keyword.Pseudo */
.source .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.source .kt { color: #B00040 } /* Keyword.Type */
.source .m { color: #666666 } /* Literal.Number */
.source .s { color: #BA2121 } /* Literal.String */
.source .na { color: #7D9029 } /* Name.Attribute */
.source .nb { color: #008000 } /* Name.Builtin */
.source .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.source .no { color: #880000 } /* Name.Constant */
.source .nd { color: #AA22FF } /* Name.Decorator */
.source .ni { color: #999999; font-weight: bold } /* Name.Entity */
.source .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.source .nf { color: #0000FF } /* Name.Function */
.source .nl { color: #A0A000 } /* Name.Label */
.source .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.source .nt { color: #008000; font-weight: bold } /* Name.Tag */
.source .nv { color: #19177C } /* Name.Variable */
.source .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.source .w { color: #bbbbbb } /* Text.Whitespace */
.source .mf { color: #666666 } /* Literal.Number.Float */
.source .mh { color: #666666 } /* Literal.Number.Hex */
.source .mi { color: #666666 } /* Literal.Number.Integer */
.source .mo { color: #666666 } /* Literal.Number.Oct */
.source .sb { color: #BA2121 } /* Literal.String.Backtick */
.source .sc { color: #BA2121 } /* Literal.String.Char */
.source .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.source .s2 { color: #BA2121 } /* Literal.String.Double */
.source .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.source .sh { color: #BA2121 } /* Literal.String.Heredoc */
.source .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.source .sx { color: #008000 } /* Literal.String.Other */
.source .sr { color: #BB6688 } /* Literal.String.Regex */
.source .s1 { color: #BA2121 } /* Literal.String.Single */
.source .ss { color: #19177C } /* Literal.String.Symbol */
.source .bp { color: #008000 } /* Name.Builtin.Pseudo */
.source .vc { color: #19177C } /* Name.Variable.Class */
.source .vg { color: #19177C } /* Name.Variable.Global */
.source .vi { color: #19177C } /* Name.Variable.Instance */
.source .il { color: #666666 } /* Literal.Number.Integer.Long */
</style>
<script type="text/x-mathjax-config">MathJax.Hub.Config({tex2jax:{inlineMath:[['$$$','$$$']]}});</script><script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
""".encode('utf-8')
print u'<title>{title}</title>'.format(title=title).encode('utf-8')
print u'</head><body>{body}'.format(body=body).encode('utf-8')
formatter = HtmlFormatter(cssclass="source", linenos=True, encoding='utf-8')
def print_code_file(fn):
with open(fn) as fp:
try:
contents = fp.read().decode('utf-8')
except:
print >>sys.stderr, 'failed reading', fn
raise
try:
lexer = guess_lexer_for_filename(fn, contents)
except pygments.util.ClassNotFound:
lexer = TextLexer()
print '<div class="attachment">'
print '<h3>' + fn + ' (' + lexer.name + ')</h3>'
pygments.highlight(contents, lexer, formatter, outfile=sys.stdout)
print '</div>'
if not args:
args = [os.path.join(root, fn) for root, dns, fns in os.walk(opts.sources) for fn in fns]
if args:
print u'<h2>Bilagor</h2>'.encode('utf-8')
for arg in args:
print_code_file(arg)
print u"</body></html>".encode('utf-8')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment