Compare commits

..

No commits in common. "master" and "0.30" have entirely different histories.
master ... 0.30

7 changed files with 102 additions and 333 deletions

55
git.py
View File

@ -6,7 +6,6 @@ command line tool directly, so please be careful with using untrusted
parameters.
"""
import functools
import sys
import io
import subprocess
@ -200,8 +199,7 @@ class Repo:
"""Returns a GitCommand() on our path."""
return GitCommand(self.path, cmd)
@functools.lru_cache
def _for_each_ref(self, pattern=None, sort=None, count=None):
def for_each_ref(self, pattern=None, sort=None, count=None):
"""Returns a list of references."""
cmd = self.cmd("for-each-ref")
if sort:
@ -211,25 +209,26 @@ class Repo:
if pattern:
cmd.arg(pattern)
refs = []
for l in cmd.run():
obj_id, obj_type, ref = l.split()
refs.append((obj_id, obj_type, ref))
return refs
yield obj_id, obj_type, ref
def branches(self, sort="-authordate"):
"""Get the (name, obj_id) of the branches."""
refs = self.for_each_ref(pattern="refs/heads/", sort=sort)
for obj_id, _, ref in refs:
yield ref[len("refs/heads/") :], obj_id
@functools.cache
def branch_names(self):
"""Get the names of the branches."""
refs = self._for_each_ref(pattern="refs/heads/", sort="-authordate")
return [ref[len("refs/heads/") :] for _, _, ref in refs]
return (name for name, _ in self.branches())
@functools.cache
def tags(self, sort="-taggerdate"):
"""Get the (name, obj_id) of the tags."""
refs = self._for_each_ref(pattern="refs/tags/", sort=sort)
return [(ref[len("refs/tags/") :], obj_id) for obj_id, _, ref in refs]
refs = self.for_each_ref(pattern="refs/tags/", sort=sort)
for obj_id, _, ref in refs:
yield ref[len("refs/tags/") :], obj_id
@functools.lru_cache
def commit_ids(self, ref, limit=None):
"""Generate commit ids."""
cmd = self.cmd("rev-list")
@ -239,9 +238,9 @@ class Repo:
cmd.arg(ref)
cmd.arg("--")
return [l.rstrip("\n") for l in cmd.run()]
for l in cmd.run():
yield l.rstrip("\n")
@functools.lru_cache
def commit(self, commit_id):
"""Return a single commit."""
cs = list(self.commits(commit_id, limit=1))
@ -249,10 +248,10 @@ class Repo:
return None
return cs[0]
@functools.lru_cache
def commits(self, ref, limit, offset=0):
def commits(self, ref, limit=None, offset=0):
"""Generate commit objects for the ref."""
cmd = self.cmd("rev-list")
if limit:
cmd.max_count = limit + offset
cmd.header = None
@ -262,7 +261,6 @@ class Repo:
info_buffer = ""
count = 0
commits = []
for l in cmd.run():
if "\0" in l:
pre, post = l.split("\0", 1)
@ -270,7 +268,7 @@ class Repo:
count += 1
if count > offset:
commits.append(Commit.from_str(self, info_buffer))
yield Commit.from_str(self, info_buffer)
# Start over.
info_buffer = post
@ -280,11 +278,8 @@ class Repo:
if info_buffer:
count += 1
if count > offset:
commits.append(Commit.from_str(self, info_buffer))
yield Commit.from_str(self, info_buffer)
return commits
@functools.lru_cache
def diff(self, ref):
"""Return a Diff object for the ref."""
cmd = self.cmd("diff-tree")
@ -300,7 +295,6 @@ class Repo:
return Diff.from_str(cmd.run())
@functools.lru_cache
def refs(self):
"""Return a dict of obj_id -> ref."""
cmd = self.cmd("show-ref")
@ -314,12 +308,10 @@ class Repo:
return r
@functools.lru_cache
def tree(self, ref):
"""Returns a Tree instance for the given ref."""
return Tree(self, ref)
@functools.lru_cache
def blob(self, path, ref):
"""Returns a Blob instance for the given path."""
cmd = self.cmd("cat-file")
@ -337,10 +329,9 @@ class Repo:
return Blob(out.read()[: int(head)])
@functools.cache
def last_commit_timestamp(self):
"""Return the timestamp of the last commit."""
refs = self._for_each_ref(
refs = self.for_each_ref(
pattern="refs/heads/", sort="-committerdate", count=1
)
for obj_id, _, _ in refs:
@ -524,13 +515,12 @@ class Diff:
class Tree:
"""A git tree."""
""" A git tree."""
def __init__(self, repo: Repo, ref: str):
self.repo = repo
self.ref = ref
@functools.lru_cache
def ls(
self, path, recursive=False
) -> Iterable[Tuple[str, smstr, Optional[int]]]:
@ -547,7 +537,6 @@ class Tree:
else:
cmd.arg(path)
files = []
for l in cmd.run():
_mode, otype, _oid, size, name = l.split(None, 4)
if size == "-":
@ -564,9 +553,7 @@ class Tree:
# We use a smart string for the name, as it's often tricky to
# manipulate otherwise.
files.append((otype, smstr(name), size))
return files
yield otype, smstr(name), size
class Blob:

View File

@ -1,53 +1,15 @@
/*
* git-arr style sheet
*/
:root {
--body-bg: white;
--text-fg: black;
--h1-bg: #ddd;
--hr-bg: #e3e3e3;
--text-lowcontrast-fg: grey;
--a-fg: #800;
--a-explicit-fg: #038;
--table-hover-bg: #eee;
--head-bg: #88ff88;
--tag-bg: #ffff88;
--age-fg0: darkgreen;
--age-fg1: green;
--age-fg2: seagreen;
--diff-added-fg: green;
--diff-deleted-fg: red;
}
@media (prefers-color-scheme: dark) {
:root {
--body-bg: #121212;
--text-fg: #c9d1d9;
--h1-bg: #2f2f2f;
--hr-bg: #e3e3e3;
--text-lowcontrast-fg: grey;
--a-fg: #d4b263;
--a-explicit-fg: #44b4ec;
--table-hover-bg: #313131;
--head-bg: #020;
--tag-bg: #333000;
--age-fg0: #51a552;
--age-fg1: #468646;
--age-fg2: #2f722f;
--diff-added-fg: #00A000;
--diff-deleted-fg: #A00000;
}
}
body {
font-family: sans-serif;
padding: 0 1em 1em 1em;
color: var(--text-fg);
background: var(--body-bg);
}
h1 {
background: var(--h1-bg);
background: #ddd;
padding: 0.3em;
}
@ -59,29 +21,26 @@ h2, h3 {
hr {
border: none;
background-color: var(--hr-bg);
background-color: #e3e3e3;
height: 1px;
}
/* By default, use implied links, more discrete for increased readability. */
a {
text-decoration: none;
color: var(--text-fg);
color: black;
}
a:hover {
color: var(--a-fg);
text-decoration: underline;
color: #800;
}
/* Explicit links */
a.explicit {
color: var(--a-explicit-fg);
color: #038;
}
a.explicit:hover, a.explicit:active {
color: var(--a-fg);
color: #880000;
}
@ -89,27 +48,22 @@ a.explicit:hover, a.explicit:active {
table.nice {
text-align: left;
}
table.nice td {
padding: 0.15em 0.5em;
}
table.nice td.links {
}
table.nice td.main {
min-width: 10em;
}
table.nice tr:hover {
background: var(--table-hover-bg);
background: #eee;
}
/* Table for commits. */
table.commits td.date {
font-style: italic;
color: var(--text-lowcontrast-fg);
color: gray;
}
@media (min-width: 600px) {
@ -117,134 +71,106 @@ table.commits td.date {
min-width: 32em;
}
}
table.commits td.author {
color: var(--text-lowcontrast-fg);
color: gray;
}
/* Table for commit information. */
table.commit-info tr:hover {
background: inherit;
}
table.commit-info td {
vertical-align: top;
}
table.commit-info span.date, span.email {
color: var(--text-lowcontrast-fg);
color: gray;
}
/* Reference annotations. */
span.refs {
margin: 0px 0.5em;
padding: 0px 0.25em;
border: solid 1px var(--text-lowcontrast-fg);
border: solid 1px gray;
}
span.head {
background-color: var(--head-bg);
background-color: #88ff88;
}
span.tag {
background-color: var(--tag-bg);
background-color: #ffff88;
}
/* Projects table */
table.projects td.name a {
color: var(--a-explicit-fg);
color: #038;
}
/* Age of an object.
* Note this is hidden by default as we rely on javascript to show it. */
span.age {
display: none;
color: var(--text-lowcontrast-fg);
color: gray;
font-size: smaller;
}
span.age-band0 {
color: var(--age-fg0);
color: darkgreen;
}
span.age-band1 {
color: var(--age-fg1);
color: green;
}
span.age-band2 {
color: var(--age-fg2);
color: seagreen;
}
/* Toggable titles */
div.toggable-title {
font-weight: bold;
margin-bottom: 0.3em;
}
pre {
/* Sometimes, <pre> elements (commit messages, diffs, blobs) have very
* long lines. In those case, use automatic overflow, which will
* introduce a horizontal scroll bar for this element only (more
* comfortable than stretching the page, which is the default). */
overflow: auto;
}
/* Commit message and diff. */
pre.commit-message {
font-size: large;
padding: 0.2em 0.5em;
padding: 0.2em 2em;
}
pre.diff-body {
/* Note this is only used as a fallback if pygments is not available. */
}
table.changed-files {
font-family: monospace;
}
table.changed-files span.lines-added {
color: var(--diff-added-fg);
color: green;
}
table.changed-files span.lines-deleted {
color: var(--diff-deleted-fg);
color: red;
}
/* Pagination. */
div.paginate {
padding-bottom: 1em;
}
div.paginate span.inactive {
color: var(--text-lowcontrast-fg);
color: gray;
}
/* Directory listing. */
@media (min-width: 600px) {
table.ls td.name {
min-width: 20em;
}
}
table.ls {
font-family: monospace;
font-size: larger;
}
table.ls tr.blob td.size {
color: var(--text-lowcontrast-fg);
color: gray;
}
/* Blob. */
pre.blob-body {
/* Note this is only used as a fallback if pygments is not available. */
@ -258,79 +184,60 @@ table.blob-binary pre {
table.blob-binary .offset {
text-align: right;
font-size: x-small;
color: var(--text-lowcontrast-fg);
border-right: 1px solid var(--text-lowcontrast-fg);
color: darkgray;
border-right: 1px solid #eee;
}
table.blob-binary tr.etc {
text-align: center;
}
/* Pygments overrides. */
div.colorized-src {
font-size: larger;
}
div.colorized-src .source_code {
/* Ignore pygments style's background. */
background: var(--body-bg);
}
td.code > div.source_code {
/* This is a workaround, in pygments 2.11 there's a bug where the wrapper
* div is inside the table, so we need to override the descendant (because
* the style sets it on ".source_code" and the most specific value wins).
* Once we no longer support 2.11, we can remove this. */
background: var(--body-bg);
}
div.linenodiv {
padding-right: 0.5em;
font-size: larger; /* must match div.source_code */
}
div.linenodiv a {
color: var(--text-lowcontrast-fg);
color: gray;
}
div.source_code {
background: inherit;
font-size: larger;
}
/* Repository information table. */
table.repo_info tr:hover {
background: inherit;
}
table.repo_info td.category {
font-weight: bold;
/* So we can copy-paste rows and preserve spaces, useful for the row:
* git clone | url */
* git clone | url
*/
white-space: pre-wrap;
}
table.repo_info td {
vertical-align: top;
}
span.ctrlchr {
color: var(--text-lowcontrast-fg);
color: gray;
padding: 0 0.2ex 0 0.1ex;
margin: 0 0.2ex 0 0.1ex;
}
/*
* Markdown overrides
*/
/* Colored links (same as explicit links above) */
div.markdown a {
color: var(--a-explicit-fg);
color: #038;
}
div.markdown a:hover, div.markdown a:active {
color: var(--a-fg);
color: #880000;
}
/* Restrict max width for readability */
div.markdown {
max-width: 55em;

View File

@ -1,37 +1,30 @@
/* CSS for syntax highlighting.
* Generated by pygments (what we use for syntax highlighting).
* Generated by pygments (what we use for syntax highlighting):
*
* Light mode: pygmentize -S default -f html -a .source_code
* $ pygmentize -S default -f html -a .source_code
*/
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.source_code .hll { background-color: #ffffcc }
.source_code { background: #f8f8f8; }
.source_code .c { color: #3D7B7B; font-style: italic } /* Comment */
.source_code .c { color: #408080; font-style: italic } /* Comment */
.source_code .err { border: 1px solid #FF0000 } /* Error */
.source_code .k { color: #008000; font-weight: bold } /* Keyword */
.source_code .o { color: #666666 } /* Operator */
.source_code .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
.source_code .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
.source_code .cp { color: #9C6500 } /* Comment.Preproc */
.source_code .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
.source_code .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
.source_code .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
.source_code .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.source_code .cp { color: #BC7A00 } /* Comment.Preproc */
.source_code .c1 { color: #408080; font-style: italic } /* Comment.Single */
.source_code .cs { color: #408080; font-style: italic } /* Comment.Special */
.source_code .gd { color: #A00000 } /* Generic.Deleted */
.source_code .ge { font-style: italic } /* Generic.Emph */
.source_code .gr { color: #E40000 } /* Generic.Error */
.source_code .gr { color: #FF0000 } /* Generic.Error */
.source_code .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.source_code .gi { color: #008400 } /* Generic.Inserted */
.source_code .go { color: #717171 } /* Generic.Output */
.source_code .gi { color: #00A000 } /* Generic.Inserted */
.source_code .go { color: #808080 } /* Generic.Output */
.source_code .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.source_code .gs { font-weight: bold } /* Generic.Strong */
.source_code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.source_code .gt { color: #0044DD } /* Generic.Traceback */
.source_code .gt { color: #0040D0 } /* Generic.Traceback */
.source_code .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.source_code .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.source_code .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
@ -40,139 +33,38 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
.source_code .kt { color: #B00040 } /* Keyword.Type */
.source_code .m { color: #666666 } /* Literal.Number */
.source_code .s { color: #BA2121 } /* Literal.String */
.source_code .na { color: #687822 } /* Name.Attribute */
.source_code .na { color: #7D9029 } /* Name.Attribute */
.source_code .nb { color: #008000 } /* Name.Builtin */
.source_code .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.source_code .no { color: #880000 } /* Name.Constant */
.source_code .nd { color: #AA22FF } /* Name.Decorator */
.source_code .ni { color: #717171; font-weight: bold } /* Name.Entity */
.source_code .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
.source_code .ni { color: #999999; font-weight: bold } /* Name.Entity */
.source_code .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.source_code .nf { color: #0000FF } /* Name.Function */
.source_code .nl { color: #767600 } /* Name.Label */
.source_code .nl { color: #A0A000 } /* Name.Label */
.source_code .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.source_code .nt { color: #008000; font-weight: bold } /* Name.Tag */
.source_code .nv { color: #19177C } /* Name.Variable */
.source_code .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.source_code .w { color: #bbbbbb } /* Text.Whitespace */
.source_code .mb { color: #666666 } /* Literal.Number.Bin */
.source_code .mf { color: #666666 } /* Literal.Number.Float */
.source_code .mh { color: #666666 } /* Literal.Number.Hex */
.source_code .mi { color: #666666 } /* Literal.Number.Integer */
.source_code .mo { color: #666666 } /* Literal.Number.Oct */
.source_code .sa { color: #BA2121 } /* Literal.String.Affix */
.source_code .sb { color: #BA2121 } /* Literal.String.Backtick */
.source_code .sc { color: #BA2121 } /* Literal.String.Char */
.source_code .dl { color: #BA2121 } /* Literal.String.Delimiter */
.source_code .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.source_code .s2 { color: #BA2121 } /* Literal.String.Double */
.source_code .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
.source_code .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.source_code .sh { color: #BA2121 } /* Literal.String.Heredoc */
.source_code .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
.source_code .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.source_code .sx { color: #008000 } /* Literal.String.Other */
.source_code .sr { color: #A45A77 } /* Literal.String.Regex */
.source_code .sr { color: #BB6688 } /* Literal.String.Regex */
.source_code .s1 { color: #BA2121 } /* Literal.String.Single */
.source_code .ss { color: #19177C } /* Literal.String.Symbol */
.source_code .bp { color: #008000 } /* Name.Builtin.Pseudo */
.source_code .fm { color: #0000FF } /* Name.Function.Magic */
.source_code .vc { color: #19177C } /* Name.Variable.Class */
.source_code .vg { color: #19177C } /* Name.Variable.Global */
.source_code .vi { color: #19177C } /* Name.Variable.Instance */
.source_code .vm { color: #19177C } /* Name.Variable.Magic */
.source_code .il { color: #666666 } /* Literal.Number.Integer.Long */
/*
* Dark mode: pygmentize -S native -f html -a .source_code
*/
@media (prefers-color-scheme: dark) {
pre { line-height: 125%; }
td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.source_code .hll { background-color: #404040 }
.source_code { background: #202020; color: #d0d0d0 }
.source_code .c { color: #ababab; font-style: italic } /* Comment */
.source_code .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.source_code .esc { color: #d0d0d0 } /* Escape */
.source_code .g { color: #d0d0d0 } /* Generic */
.source_code .k { color: #6ebf26; font-weight: bold } /* Keyword */
.source_code .l { color: #d0d0d0 } /* Literal */
.source_code .n { color: #d0d0d0 } /* Name */
.source_code .o { color: #d0d0d0 } /* Operator */
.source_code .x { color: #d0d0d0 } /* Other */
.source_code .p { color: #d0d0d0 } /* Punctuation */
.source_code .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */
.source_code .cm { color: #ababab; font-style: italic } /* Comment.Multiline */
.source_code .cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */
.source_code .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */
.source_code .c1 { color: #ababab; font-style: italic } /* Comment.Single */
.source_code .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
.source_code .gd { color: #d22323 } /* Generic.Deleted */
.source_code .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
.source_code .gr { color: #d22323 } /* Generic.Error */
.source_code .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
.source_code .gi { color: #589819 } /* Generic.Inserted */
.source_code .go { color: #cccccc } /* Generic.Output */
.source_code .gp { color: #aaaaaa } /* Generic.Prompt */
.source_code .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */
.source_code .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */
.source_code .gt { color: #d22323 } /* Generic.Traceback */
.source_code .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */
.source_code .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */
.source_code .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */
.source_code .kp { color: #6ebf26 } /* Keyword.Pseudo */
.source_code .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */
.source_code .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */
.source_code .ld { color: #d0d0d0 } /* Literal.Date */
.source_code .m { color: #51b2fd } /* Literal.Number */
.source_code .s { color: #ed9d13 } /* Literal.String */
.source_code .na { color: #bbbbbb } /* Name.Attribute */
.source_code .nb { color: #2fbccd } /* Name.Builtin */
.source_code .nc { color: #71adff; text-decoration: underline } /* Name.Class */
.source_code .no { color: #40ffff } /* Name.Constant */
.source_code .nd { color: #ffa500 } /* Name.Decorator */
.source_code .ni { color: #d0d0d0 } /* Name.Entity */
.source_code .ne { color: #bbbbbb } /* Name.Exception */
.source_code .nf { color: #71adff } /* Name.Function */
.source_code .nl { color: #d0d0d0 } /* Name.Label */
.source_code .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */
.source_code .nx { color: #d0d0d0 } /* Name.Other */
.source_code .py { color: #d0d0d0 } /* Name.Property */
.source_code .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */
.source_code .nv { color: #40ffff } /* Name.Variable */
.source_code .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */
.source_code .w { color: #666666 } /* Text.Whitespace */
.source_code .mb { color: #51b2fd } /* Literal.Number.Bin */
.source_code .mf { color: #51b2fd } /* Literal.Number.Float */
.source_code .mh { color: #51b2fd } /* Literal.Number.Hex */
.source_code .mi { color: #51b2fd } /* Literal.Number.Integer */
.source_code .mo { color: #51b2fd } /* Literal.Number.Oct */
.source_code .sa { color: #ed9d13 } /* Literal.String.Affix */
.source_code .sb { color: #ed9d13 } /* Literal.String.Backtick */
.source_code .sc { color: #ed9d13 } /* Literal.String.Char */
.source_code .dl { color: #ed9d13 } /* Literal.String.Delimiter */
.source_code .sd { color: #ed9d13 } /* Literal.String.Doc */
.source_code .s2 { color: #ed9d13 } /* Literal.String.Double */
.source_code .se { color: #ed9d13 } /* Literal.String.Escape */
.source_code .sh { color: #ed9d13 } /* Literal.String.Heredoc */
.source_code .si { color: #ed9d13 } /* Literal.String.Interpol */
.source_code .sx { color: #ffa500 } /* Literal.String.Other */
.source_code .sr { color: #ed9d13 } /* Literal.String.Regex */
.source_code .s1 { color: #ed9d13 } /* Literal.String.Single */
.source_code .ss { color: #ed9d13 } /* Literal.String.Symbol */
.source_code .bp { color: #2fbccd } /* Name.Builtin.Pseudo */
.source_code .fm { color: #71adff } /* Name.Function.Magic */
.source_code .vc { color: #40ffff } /* Name.Variable.Class */
.source_code .vg { color: #40ffff } /* Name.Variable.Global */
.source_code .vi { color: #40ffff } /* Name.Variable.Instance */
.source_code .vm { color: #40ffff } /* Name.Variable.Magic */
.source_code .il { color: #51b2fd } /* Literal.Number.Integer.Long */
/* Dark mode - my overrides, because the defaults are too bright. */
.source_code .gh { color: rgb(189, 193, 198); }
.source_code .gu { color: rgb(189, 193, 198); }
}

View File

@ -9,14 +9,6 @@ try:
from pygments import highlight # type: ignore
from pygments import lexers # type: ignore
from pygments.formatters import HtmlFormatter # type: ignore
_html_formatter = HtmlFormatter(
encoding="utf-8",
cssclass="source_code",
linenos="table",
anchorlinenos=True,
lineanchors="line",
)
except ImportError:
pygments = None
@ -27,7 +19,6 @@ except ImportError:
markdown = None
import base64
import functools
import mimetypes
import string
import os.path
@ -41,7 +32,6 @@ def shorten(s: str, width=60):
return s[:57] + "..."
@functools.lru_cache
def can_colorize(s: str):
"""True if we can colorize the string, False otherwise."""
if pygments is None:
@ -87,7 +77,6 @@ def can_embed_image(repo, fname):
)
@functools.lru_cache
def colorize_diff(s: str) -> str:
lexer = lexers.DiffLexer(encoding="utf-8")
formatter = HtmlFormatter(encoding="utf-8", cssclass="source_code")
@ -95,7 +84,6 @@ def colorize_diff(s: str) -> str:
return highlight(s, lexer, formatter)
@functools.lru_cache
def colorize_blob(fname, s: str) -> str:
try:
lexer = lexers.guess_lexer_for_filename(fname, s, encoding="utf-8")
@ -110,7 +98,24 @@ def colorize_blob(fname, s: str) -> str:
except lexers.ClassNotFound:
pass
return highlight(s, lexer, _html_formatter)
formatter = HtmlFormatter(
encoding="utf-8",
cssclass="source_code",
linenos="table",
anchorlinenos=True,
lineanchors="line",
)
return highlight(s, lexer, formatter)
def markdown_blob(s: str) -> str:
extensions = [
"markdown.extensions.fenced_code",
"markdown.extensions.tables",
RewriteLocalLinksExtension(),
]
return markdown.markdown(s, extensions=extensions)
def embed_image_blob(fname: str, image_data: bytes) -> str:
@ -121,13 +126,11 @@ def embed_image_blob(fname: str, image_data: bytes) -> str:
)
@functools.lru_cache
def is_binary(b: bytes):
# Git considers a blob binary if NUL in first ~8KB, so do the same.
return b"\0" in b[:8192]
@functools.lru_cache
def hexdump(s: bytes):
graph = string.ascii_letters + string.digits + string.punctuation + " "
b = s.decode("latin1")
@ -174,23 +177,7 @@ if markdown:
tag.set("href", new_target)
class RewriteLocalLinksExtension(markdown.Extension):
def extendMarkdown(self, md):
md.treeprocessors.register(
RewriteLocalLinks(), "RewriteLocalLinks", 1000
def extendMarkdown(self, md, md_globals):
md.treeprocessors.add(
"RewriteLocalLinks", RewriteLocalLinks(), "_end"
)
_md_extensions = [
"markdown.extensions.fenced_code",
"markdown.extensions.tables",
RewriteLocalLinksExtension(),
]
@functools.lru_cache
def markdown_blob(s: str) -> str:
return markdown.markdown(s, extensions=_md_extensions)
else:
@functools.lru_cache
def markdown_blob(s: str) -> str:
raise RuntimeError("markdown_blob() called without markdown support")

View File

@ -77,9 +77,7 @@
{{!markdown_blob(blob.utf8_content)}}
</div>
% elif can_colorize(blob.utf8_content):
<div class="colorized-src">
{{!colorize_blob(fname.raw, blob.utf8_content)}}
</div>
% else:
<pre class="blob-body">
{{blob.utf8_content}}

View File

@ -56,9 +56,7 @@
<hr/>
% if can_colorize(c.diff.body):
<div class="colorized-src">
{{!colorize_diff(c.diff.body)}}
</div>
% else:
<pre class="diff-body">
{{c.diff.body}}