diff options
Diffstat (limited to '')
| -rw-r--r-- | CHANGELOG.txt | 152 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | MANUAL.txt | 8 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | Makefile | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | README.txt | 3 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | assets/cgit.css | 25 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | assets/cgit.js | 18 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/syntax-highlight.lua | 45 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.c | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.h | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/html.c | 79 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/html.h | 13 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/ui-blame.c | 18 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/ui-patch.c | 12 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/ui-tree.c | 4 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | tests/extensions/test-syntax-highlight.lua | 29 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rwxr-xr-x | tests/t0005-markup.sh | 23 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rwxr-xr-x | tests/t0104-tree.sh | 60 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rwxr-xr-x | tests/t0109-patch.sh | 10 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rwxr-xr-x | tests/t0502-syntax-highlight.sh | 11 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
19 files changed, 486 insertions, 30 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 67b2670..f1b5ae1 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,6 +5,158 @@ Notable changes to this fork, newest release first. History before v2.0.0 belongs to upstream cgit and is not covered here. +v2.9.1 (2026-10-24) +------------------- + +A bugfix release for the tree and blame pages, whose line numbers had drifted +away from the code since v2.0.0 in Safari and in every browser on a typical +Linux desktop, until the code sat dozens of lines below its number at the end +of a long file. + +Added +..... + +* A character a browser would start a new line at, though git does not, is + shown as an escape sequence in span.escape on the tree and blame pages and + by the syntax highlighter: a carriage return with no line feed after it, a + vertical tab, a form feed, next line and the Unicode line and paragraph + separators. + +Changed +....... + +* Patches end with the cgit version again, written as git writes its own, so + this release signs them "cgit 2.9.1". The footer and the generator tag still + carry no version. + +Fixed +..... + +* The code beside the line numbers was set in the browser's own monospace + font, which made each of its lines a little taller than its number, by a + pixel in Safari and on Linux, so the two columns drifted apart down every + file. +* A lone carriage return started an extra line in every browser, and U+2028 + and U+2029 did in Safari, each pushing every later line below its number. +* The line highlight sat a pixel low, covered only the digits of each number, + and ended at the edge of the view on a file scrolled sideways. +* Code in a readme took the browser's own monospace font, Courier in Chrome + and Safari, rather than the theme's --font-mono. + + +v2.9.0 (2026-10-17) +------------------- + +A compatibility and hardening release. Lua 5.5 is supported, readmes render +closer to how GitHub shows them, the auth examples were overhauled, 32-bit +builds compile again, and two audits of the extensions and of the C code +closed what they found, from a cache lock that an exec filter let go of to +a log search that was never the literal match it claimed to be. + +Added +..... + +* Lua 5.5, detected when building and claimed by every extension, which + needs luaossl 20260910 or later there. +* Stable markup hooks for site themes: a data-page attribute, named sections + and a class per link kind. +* Readmes follow GitHub more closely: relative links lead into the tree at + the readme's own ref, lines of a paragraph run together, a table may cut a + paragraph short, a wrapped list item stays in its list, urls and addresses + in angle brackets link, backslash escapes and character references are + honoured, underscores inside words are left alone, and headings get the + anchors GitHub gives them. Images and badges are left out. +* The auth examples bind a session to the account's password hash, so a + changed password ends it, use a __Host- cookie where one can be set, turn + down passwords past 256 bytes unchecked, spend a missing account's login on + a real hash, load their libraries only when a request needs one, and say + which hash kinds each system's crypt checks. +* Avatars are looked up by SHA-256, offered at twice the size to dense + screens, marked decorative, and left out when luaossl is missing. +* The syntax highlighter finds a script's lexer from its shebang line. +* make get-git checks the Git tarball against the SHA-256 kernel.org lists. +* The dumb transport answers HEAD from the ref store and the index dates a + repository from its reftable, so reftable repositories clone and age. + +Changed +....... + +* enable-trailers is now enable-commit-trailers. +* The bundled Git is 2.56.0. +* The pages carry no version number, and the Lua-less build is checked by + the suite as well. +* Any path below the about page answers 404, the about filter is handed the + tree url its links need, and the about redirect keeps the query string. +* The dumb transport serves only what a clone asks for, a loose object, a + pack with its index and info/http-alternates, sends each file with its + size and keeps none of them in the cache. +* A page behind an auth filter is marked private, and every page that + follows a branch takes cache-dynamic-ttl. +* summary-branches, summary-tags and max-ref-count read a negative value as + no limit, and the feed refuses pathspec magic as the log does. +* patch, rawdiff and signature downloads hold to max-blob-size, and a + readme past it says so on the about page. +* Diffs no longer ask xdiff for a minimal result, which cost quadratic time + on a reordered file, and tar.xz snapshots are compressed on one thread. +* The cache slot lock is an flock, which outlasts an exec filter's swap of + stdout where the record lock did not. +* Git is built without translations or Tcl, the release script builds with + the compiler it probed, the two builds no longer share vendor/git at once, + sparse checks the sources as gnu17, and a musl build is documented. +* The example tracker links in link-commits.lua and link-trailers.lua ship + commented out, so an unedited copy links object names alone. +* The manual, README and sample cgitrc say what the code does: every page + and query parameter, every file make install puts in place, the defaults + and value syntax, and which filters get the repository variables. + +Fixed +..... + +* 32-bit builds, where Git 2.55's size_t object sizes no longer compiled. +* The log search matched as a regular expression after all, so a term with + a bracket in it answered a 500 and a crafted one took the memory of the + box. +* A pushed date or zone outside what git's date code accepts, and a notes + ref pointing at anything but a tree, ended the summary, refs, log, commit + and feed pages of the repository. +* A snapshot name led to a branch spelled like the tag's stem, members + of a snapshot named by its suffix alone started at a slash, and a missing + PATH refused every compressed snapshot. +* The plain view answered twice for duplicate tree entries and read a freed + mimetype on the way, a control byte in a file name made the web server + refuse the download, a scanned defbranch could name a path outside the + repository, and the error page resolved the very id it had refused. +* A fill whose last flush failed to write, on a full disk for one, left the + visitor a blank response, a cache ttl in the tens of millions of minutes + overflowed, and an empty list reached qsort as a null, which glibc's + sanitizer build aborted on. +* Links built from the repository url and the feed link's branch were not + encoded, a readme vanished behind an annotated tag, a followed log lost + its root commit and paged by the wrong name, a Lua build crashed when git + wrote before cgit's own setup, text was cut inside a multibyte character, + and the tag page offered snapshots of trees and blobs. +* An absolute symlink target was linked as a path inside the tree, a chain + of single directories ended in a dangling separator, a repository without + a path was dated from a file named "(null)", a NUL ended a config comment + early, and a tree row was left open when a link target could not be read. +* An empty repo.url is ignored, a readme ending in a colon is gated like a + path on disk, an error mid capture keeps its message, date-format= + local-local renders, an indented comment in the mimetype file is skipped, + types that only spell xml get no charset, the sendfile loop stops at a + short slot, slot keys and pages are read and written in full, and the + stats page stops after its error page. +* auth-file.lua refuses every repository when it cannot read its repos file, + cookie, readme and avatar parsing run in linear time, the cache hook keeps + its rm errors from pushers, the age hook leaves its directory writable to + the group, a Lua script may write while it loads, and every Lua filter + failure is named in the log. +* Git read the global config for its trace settings before cgit isolated + the environment, so every request probed $HOME/.gitconfig, which the + home-access test caught only once it ran on a real x86_64 kernel. +* make DEVELOPER=1 passes: string literals sit behind const pointers and + callbacks are passed by address. + + v2.8.0 (2026-09-16) ------------------- @@ -861,6 +861,14 @@ source filter:: be filtered is available on standard input and the filtered contents is expected on standard output. + The line numbers beside the output are counted from the line feeds of + the input, so the output has to break lines exactly where those fall. + A browser also starts a line at a carriage return with no line feed + after it, and may at a vertical tab, a form feed, or the Unicode next + line, line separator and paragraph separator, which is why cgit and + syntax-highlight.lua show each of those as an escape sequence in + span.escape. + trailer filter:: This filter is given two parameters, the key of the trailer being formatted, such as "Fixes", and a string indicating the originating @@ -35,7 +35,7 @@ GIT_TARBALL = git-$(GIT_VERSION).tar.xz # Compiled-in cgit defaults, all overridable through cgit.conf. Every one # carries the CGIT_ prefix except CACHE_ROOT, which is inherited from upstream # under that name. -CGIT_VERSION = v2.8.0 +CGIT_VERSION = v2.9.1 CGIT_SCRIPT_NAME = cgit.cgi CGIT_SCRIPT_PATH = /var/www/htdocs/cgit CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) @@ -98,6 +98,9 @@ script added through the css and js options has stable hooks to work with. * Relative ages are time elements with an age-* class and the timestamp in data-ut, while a date shown in full is a plain time element. Line numbers are anchors named n followed by the line, while enable-tree-linenumbers is on. + A character in a file that a browser would start a new line at, though git + does not, such as a carriage return with no line feed after it, is shown as + an escape sequence in span.escape. * Colours, fonts and metrics are custom properties on div#cgit, so a theme can redefine those alone. Every rule in cgit.css starts with div#cgit, apart from the background and margins it sets on html.cgit-standalone, the class of the diff --git a/assets/cgit.css b/assets/cgit.css index dbd807c..540480c 100644 --- a/assets/cgit.css +++ b/assets/cgit.css @@ -127,6 +127,13 @@ div#cgit table { border-collapse: collapse; } +div#cgit code, +div#cgit kbd, +div#cgit pre, +div#cgit samp { + font-family: var(--font-mono); +} + div#cgit select, div#cgit input { font-family: inherit; @@ -448,7 +455,6 @@ div#cgit div#about pre { div#cgit pre.plaintext { white-space: pre-wrap; overflow-wrap: anywhere; - font-family: var(--font-mono); line-height: 1.5; margin: 0; } @@ -642,7 +648,20 @@ div#cgit table.blob td.linenumbers { div#cgit table.blob pre { padding: 0; margin: 0; - font-family: var(--font-mono); +} + +/* + * The code is set exactly like the line numbers beside it, since in another + * font or size each line can come out taller than its number. + */ +div#cgit table.blob code { + font: inherit; +} + +div#cgit span.escape { + color: var(--muted); + outline: 1px dashed var(--border-mid); + outline-offset: -1px; } div#cgit table.blob td.linenumbers a, @@ -676,7 +695,6 @@ div#cgit table.blame { div#cgit div.line-hl { position: absolute; left: 0; - right: 0; background: var(--line-hl); pointer-events: none; } @@ -744,7 +762,6 @@ div#cgit table.blame td.lines > div > pre { padding: 0 0 0 0.5em; position: absolute; top: 0; - font-family: var(--font-mono); } div#cgit table.blame .oid { diff --git a/assets/cgit.js b/assets/cgit.js index 2c0a828..807f15f 100644 --- a/assets/cgit.js +++ b/assets/cgit.js @@ -112,7 +112,7 @@ var bar = null; function place_bar() { var match, first, last, table; - var table_box, first_box, last_box, top, bottom; + var table_box, first_box, last_box, leading, origin, top, bottom; if (bar) { bar.remove(); @@ -131,12 +131,24 @@ function place_bar() { table_box = table.getBoundingClientRect(); first_box = first.getBoundingClientRect(); last_box = last.getBoundingClientRect(); - top = Math.min(first_box.top, last_box.top) - table_box.top; - bottom = Math.max(first_box.bottom, last_box.bottom) - table_box.top; + + // An anchor's box holds only its digits, centred in a line that the line + // height makes taller, so the bar reaches out by the difference to cover + // whole lines. A line height of normal leaves nothing to add. + leading = parseFloat(getComputedStyle(first).lineHeight); + leading = (leading - first_box.height) / 2 || 0; + + // The bar is placed from inside the table's border, not from its edge. + origin = table_box.top + table.clientTop; + top = Math.min(first_box.top, last_box.top) - leading - origin; + bottom = Math.max(first_box.bottom, last_box.bottom) + leading - origin; bar = document.createElement("div"); bar.className = "line-hl"; bar.style.top = top + "px"; bar.style.height = (bottom - top) + "px"; + // A table too wide for the page scrolls sideways, and the bar has to run + // to the end of its longest line rather than to the edge of the view. + bar.style.width = table.scrollWidth + "px"; table.appendChild(bar); // A browser only scrolls to a fragment that names a real id, which a range diff --git a/custom/extensions/syntax-highlight.lua b/custom/extensions/syntax-highlight.lua index fdc4fa0..c178f25 100644 --- a/custom/extensions/syntax-highlight.lua +++ b/custom/extensions/syntax-highlight.lua @@ -95,10 +95,32 @@ local scintillua = nil local filename = "" local chunks = {} -local escape_map = { ["&"] = "&", ["<"] = "<", [">"] = ">" } +-- Besides the markup characters, everything a browser may start a new line +-- at is shown as an escape sequence, since the line numbers beside the code +-- count only line feeds. cgit escapes a blob it serves unhighlighted the same +-- way. +local escape_map = { + ["&"] = "&", + ["<"] = "<", + [">"] = ">", + ["\r"] = "<span class='escape'>\\r</span>", + ["\v"] = "<span class='escape'>\\v</span>", + ["\f"] = "<span class='escape'>\\f</span>", + ["\194\133"] = "<span class='escape'>\\u0085</span>", + ["\226\128\168"] = "<span class='escape'>\\u2028</span>", + ["\226\128\169"] = "<span class='escape'>\\u2029</span>", +} local function escape(s) - return (string.gsub(s, "[&<>]", escape_map)) + return (string.gsub(s, "[&<>\r\v\f]", escape_map)) +end + +-- The next line and the two Unicode separators take several bytes, which a +-- lexer may hand back in different tokens, so they are escaped once the +-- tokens are joined again. +local function escape_separators(s) + s = string.gsub(s, "\194\133", escape_map) + return (string.gsub(s, "\226\128[\168\169]", escape_map)) end local function scintillua_path() @@ -208,7 +230,7 @@ local function highlight(text) if pos <= #text then out[#out + 1] = escape(string.sub(text, pos)) end - return table.concat(out) + return escape_separators(table.concat(out)) end function filter_open(name) @@ -226,8 +248,13 @@ end -- source. function filter_close() local text = table.concat(chunks) + local fits = #text <= max_bytes chunks = {} - if #text <= max_bytes then + -- A browser reads CR LF as one line feed only while the two stay + -- together, and a lexer could hand them back in different tokens. + -- Every carriage return left after this is shown by escape(). + text = string.gsub(text, "\r\n", "\n") + if fits then if scintillua == nil then scintillua = load_scintillua() or false end @@ -241,8 +268,14 @@ function filter_close() end local pos = 1 while pos <= #text do - html(escape(string.sub(text, pos, pos + slice_bytes - 1))) - pos = pos + slice_bytes + local stop = pos + slice_bytes - 1 + -- A slice runs on to the end of the character it would cut, so + -- no separator is split where escape_separators cannot see it. + while string.find(text, "^[\128-\191]", stop + 1) do + stop = stop + 1 + end + html(escape_separators(escape(string.sub(text, pos, stop)))) + pos = stop + 1 end return 0 end diff --git a/source/cgit.c b/source/cgit.c index 5f8ecfa..a877e92 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -54,6 +54,8 @@ struct refmatch { int found; }; +const char *cgit_version = CGIT_VERSION; + /* * Isolate git from the calling user's configuration, which could otherwise * break once HOME is unset below. It runs as a constructor because git reads diff --git a/source/cgit.h b/source/cgit.h index 5b92632..c04193f 100644 --- a/source/cgit.h +++ b/source/cgit.h @@ -324,6 +324,8 @@ struct cgit_context { int empty_repo; }; +extern const char *cgit_version; + extern struct cgit_repolist cgit_repolist; extern struct cgit_context ctx; diff --git a/source/html.c b/source/html.c index d1e28f8..d13ac5b 100644 --- a/source/html.c +++ b/source/html.c @@ -258,6 +258,85 @@ ssize_t html_ntxt(const char *txt, size_t len) return left; } +/* + * git ends a line only at a line feed. A browser also starts one at a carriage + * return with no line feed after it, since the HTML parser turns that into a + * line feed, and may at the other characters Unicode makes mandatory breaks. + * Escaping those keeps one line on the page for every line git counts, so the + * numbers beside the text stay in step with it. + */ +const char *html_line_break_escape(const char *p, const char *end, size_t *width) +{ + const char *esc; + + switch ((unsigned char)*p) { + case '\r': + // The parser reads CR LF as the single line feed git ends the + // line with. + if (p + 1 < end && p[1] == '\n') + return NULL; + *width = 1; + return "\\r"; + case '\v': + *width = 1; + return "\\v"; + case '\f': + *width = 1; + return "\\f"; + case 0xc2: + if (end - p < 2 || memcmp(p, "\xc2\x85", 2)) + return NULL; + *width = 2; + return "\\u0085"; + case 0xe2: + if (end - p >= 3 && !memcmp(p, "\xe2\x80\xa8", 3)) + esc = "\\u2028"; + else if (end - p >= 3 && !memcmp(p, "\xe2\x80\xa9", 3)) + esc = "\\u2029"; + else + return NULL; + *width = 3; + return esc; + default: + return NULL; + } +} + +void html_blob_txt(const char *txt, size_t len) +{ + const char *end = txt + len; + const char *p; + + for (p = txt; p < end; p++) { + const char *entity = NULL, *esc = NULL; + size_t width = 1; + + if (*p == '<') + entity = "<"; + else if (*p == '>') + entity = ">"; + else if (*p == '&') + entity = "&"; + else + esc = html_line_break_escape(p, end, &width); + if (!entity && !esc) + continue; + html_raw(txt, p - txt); + if (entity) { + html(entity); + } else { + // The span lets a stylesheet tell the escape from the + // same characters typed into the file. + html("<span class='escape'>"); + html(esc); + html("</span>"); + } + p += width - 1; + txt = p + 1; + } + html_raw(txt, end - txt); +} + void html_attrf(const char *format, ...) { va_list args; diff --git a/source/html.h b/source/html.h index c6c0e19..9cad3a6 100644 --- a/source/html.h +++ b/source/html.h @@ -61,6 +61,19 @@ extern void html_txt(const char *txt); */ extern ssize_t html_ntxt(const char *txt, size_t len); +/* + * The escape sequence a blob's text shows for the character at p when a + * browser would start a new line at it though git does not, or NULL for any + * other character. The character's length in bytes is stored in width. + */ +extern const char *html_line_break_escape(const char *p, const char *end, size_t *width); + +/* + * Escape the text of a blob for the page beside its line numbers, writing + * each character html_line_break_escape names as its escape sequence. + */ +extern void html_blob_txt(const char *txt, size_t len); + extern void html_attr(const char *txt); extern void html_url_path(const char *txt); diff --git a/source/ui-blame.c b/source/ui-blame.c index 8fd6c83..f60020c 100644 --- a/source/ui-blame.c +++ b/source/ui-blame.c @@ -211,6 +211,15 @@ static size_t line_width(struct blame_scoreboard *sb, int line) size_t width = 0; while (pos < end) { + size_t len; + const char *esc = html_line_break_escape(pos, end, &len); + + // An escaped character takes the room of its escape sequence. + if (esc) { + width += strlen(esc); + pos += len; + continue; + } width++; if (*pos++ == '\t') width = (width + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1); @@ -297,9 +306,10 @@ static void print_blame_page(const struct object_id *oid, const char *path, cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path); html(")</div>\n"); - // A NUL past the window buffer_is_binary sniffs would end html_txt - // early while the hash and line number columns still cover the whole - // file, so a blob holding one anywhere is treated as binary too. + // A NUL past the window buffer_is_binary sniffs would end a Lua + // filter's output early while the hash and line number columns still + // cover the whole file, so a blob holding one anywhere is treated as + // binary too. if (buffer_is_binary(buf, size) || memchr(buf, 0, size)) { struct blame_entry *ent = sb.ent, *next; @@ -334,7 +344,7 @@ static void print_blame_page(const struct object_id *oid, const char *path, cgit_close_filter(ctx.repo->source_filter); free(filter_arg); } else { - html_txt(buf); + html_blob_txt(buf, size); } html("</code></pre>"); diff --git a/source/ui-patch.c b/source/ui-patch.c index 525e660..78c850c 100644 --- a/source/ui-patch.c +++ b/source/ui-patch.c @@ -62,6 +62,7 @@ void cgit_print_patch(const char *new_rev, const char *old_rev, const char *pref struct commit *commit; struct object_id new_oid, old_oid; char rev_range[REV_RANGE_LEN]; + const char *version; // setup_revisions reads these the way git reads a command line, so the // first entry stands in for the program name and is skipped, and the // array has to stay null terminated because the path after the double @@ -130,11 +131,16 @@ void cgit_print_patch(const char *new_rev, const char *old_rev, const char *pref ctx.page.filename = cgit_fmt("%s.patch", rev_range); cgit_print_http_headers(); + // git format-patch signs with its bare version number, so the v that + // cgit's tags carry is left off to read the same way. + if (!skip_prefix(cgit_version, "v", &version)) + version = cgit_version; + while ((commit = get_revision(&rev))) { log_tree_commit(&rev, commit); // Two dashes and a space is the mail signature separator, so - // git am and mail readers drop the line below rather than - // carrying it into the commit message. - printf("-- \ncgit\n\n"); + // git am and mail readers drop the version note below rather + // than carrying it into the commit message. + printf("-- \ncgit %s\n\n", version); } } diff --git a/source/ui-tree.c b/source/ui-tree.c index 13a9787..1d8bb3d 100644 --- a/source/ui-tree.c +++ b/source/ui-tree.c @@ -113,7 +113,7 @@ static void print_text_buffer(const char *filename, char *buf, size_t size) } html("<td class='lines'><pre><code>"); - html_txt(buf); + html_blob_txt(buf, size); html("</code></pre></td></tr></table>\n"); } @@ -188,7 +188,7 @@ static bool print_object(const struct object_id *oid, const char *path, return false; } // buffer_is_binary only sniffs the front of the blob, and a NUL past - // that window would end the escaped text render early while the line + // that window would end a Lua filter's output early while the line // number column still counts the whole file, so check the rest too. is_binary = buffer_is_binary(buf, size) || memchr(buf, 0, size); diff --git a/tests/extensions/test-syntax-highlight.lua b/tests/extensions/test-syntax-highlight.lua index a87cd80..f831b01 100644 --- a/tests/extensions/test-syntax-highlight.lua +++ b/tests/extensions/test-syntax-highlight.lua @@ -33,6 +33,17 @@ if mode == "nolexers" then out = render("big.fake", string.rep("x<y>", 30000)) h.equals("slicing loses nothing at the boundaries", out, string.rep("x<y>", 30000)) + out = render("hello.fake", "a\rb\vc\fd\r\ne") + h.equals("the fallback escapes what a browser breaks at", out, + "a<span class='escape'>\\r</span>b<span class='escape'>\\v</span>c" .. + "<span class='escape'>\\f</span>d\ne") + + -- The line separator starts on the last byte of the first slice, and + -- its other two bytes would land in the next one. + out = render("big.fake", string.rep("x", 64 * 1024 - 1) .. "\226\128\168y") + h.equals("a separator across a slice boundary is still escaped", out, + string.rep("x", 64 * 1024 - 1) .. "<span class='escape'>\\u2028</span>y") + h.finish() end @@ -70,6 +81,24 @@ h.equals("an extension with no lexer serves escaped text", out, "import <x> out = render("noextension", "words <here>") h.equals("a file with no extension serves escaped text", out, "words <here>") +-- The line numbers beside the code count line feeds alone, so each character +-- a browser would start a line at is an escape, and CR LF reaches the page as +-- the line feed a browser would have made of it. +out = render("hello.fake", "if\r42\vzz\f'a'\r\nif") +h.equals("what a browser breaks at is escaped between tokens", out, + "<span class='hl-keyword'>if</span><span class='escape'>\\r</span>" .. + "<span class='hl-number'>42</span><span class='escape'>\\v</span>" .. + "<span class='hl-keyword'>zz</span><span class='escape'>\\f</span>" .. + "<span class='hl-string'>'a'</span>\n<span class='hl-keyword'>if</span>") + +-- The fake lexer hands back every byte of a separator as a token of its own. +out = render("hello.fake", "a\194\133b\226\128\168c\226\128\169d") +h.equals("a separator split between tokens is escaped whole", out, + "<span class='hl-keyword'>a</span><span class='escape'>\\u0085</span>" .. + "<span class='hl-keyword'>b</span><span class='escape'>\\u2028</span>" .. + "<span class='hl-keyword'>c</span><span class='escape'>\\u2029</span>" .. + "<span class='hl-keyword'>d</span>") + out = render("big.fake", string.rep("a", 512 * 1024 + 1)) h.excludes("an oversized blob skips the lexing pass", out, "<span") h.equals("and still arrives whole", #out, 512 * 1024 + 1) diff --git a/tests/t0005-markup.sh b/tests/t0005-markup.sh index e3cb08d..5d802a7 100755 --- a/tests/t0005-markup.sh +++ b/tests/t0005-markup.sh @@ -90,21 +90,31 @@ test_expect_success 'the blob, blame and about pages open with their own contain grep "<div id=.about.>" tmp ' +# A browser gives these elements a monospace font of its own, which would +# otherwise win over the one a theme sets through --font-mono. +test_expect_success 'every monospace element takes the theme font' ' + sed -n "/^div#cgit code,$/,/^}/p" "$TEST_OUTPUT_DIRECTORY/../assets/cgit.css" >rule && + grep "^div#cgit pre,$" rule && + grep "^ font-family: var(--font-mono);$" rule +' + test_expect_success 'the stylesheet and the script name only the current hooks' ' ! grep "_dark\|#summary\|ul.pager\|td:empty" "$TEST_OUTPUT_DIRECTORY/../assets/cgit.css" && grep "window.cgit.updateAges" "$TEST_OUTPUT_DIRECTORY/../assets/cgit.js" && grep "window.cgit.highlightLines" "$TEST_OUTPUT_DIRECTORY/../assets/cgit.js" ' -# The rest of the hooks need a tag, a symlink, a submodule, a trailer, clone -# urls, an empty repository and a second page of repositories, so they get a -# commit and a config of their own after the checks above have read the first -# ones. +# The rest of the hooks need a tag, a symlink, a submodule, a trailer, a lone +# carriage return, clone urls, an empty repository and a second page of +# repositories, so they get a commit and a config of their own after the checks +# above have read the first ones. test_expect_success 'set up the remaining kinds of entry' ' ( cd repos/hooks && git tag -a -m "first release" v1 && test_ln_s_add file-1 link && + printf "a\\rb\\n" >cr.txt && + git add cr.txt && git update-index --add --cacheinfo "160000,$(git rev-parse HEAD),sub" && git commit -m "more kinds of entry" -m "Fixes: $(git rev-parse --short HEAD)" ) && @@ -139,6 +149,11 @@ test_expect_success 'the refs, summary and tree name every section and row' ' grep "<tr class=.mod.>" tmp ' +test_expect_success 'a character the browser would break a line at is an escape' ' + more "hooks/tree/cr.txt" >tmp && + grep "a<span class=.escape.>" tmp +' + test_expect_success 'the commit page has its trailer table and diffstat' ' more "hooks/commit/" >tmp && grep "<table class=.commit-trailers.>" tmp && diff --git a/tests/t0104-tree.sh b/tests/t0104-tree.sh index b48c394..d464f8c 100755 --- a/tests/t0104-tree.sh +++ b/tests/t0104-tree.sh @@ -22,6 +22,66 @@ test_expect_success 'no line 2' ' ! grep "<a id=.n2. href=.#n2.>2</a>" tmp ' +# The numbers and the code are two columns of text that a browser keeps in +# step only while both are set in one font. Only a browser shows the drift, +# so this checks the rule that prevents it. +test_expect_success 'the code is set in the font of its line numbers' ' + sed -n "/^div#cgit table.blob code {/,/^}/p" \ + "$TEST_OUTPUT_DIRECTORY/../assets/cgit.css" >rule && + grep "^ font: inherit;$" rule +' + +# A browser starts a new line at more characters than git ends one at, and +# each would push the rest of the code a line below its numbers. +test_expect_success 'set up a file holding the characters a browser breaks at' ' + test_create_repo repos/breaks && + ( + cd repos/breaks && + printf "a\\rb\\vc\\fd\\302\\205e\\342\\200\\250f\\342\\200\\251g\\nh\\r\\ni\\r" >breaks.txt && + git add breaks.txt && + git commit -m breaks + ) && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "enable-blame=1" && + echo "repo.url=breaks" && + echo "repo.path=$PWD/repos/breaks/.git" + } >breaksrc +' + +test_expect_success 'each of them is shown as an escape in the tree' ' + CGIT_CONFIG="$PWD/breaksrc" QUERY_STRING="url=breaks/tree/breaks.txt" cgit >tmp && + grep "<code>a<span class=.escape.>\\\\r</span>b<span class=.escape.>\\\\v</span>c" tmp && + grep "c<span class=.escape.>\\\\f</span>d<span class=.escape.>\\\\u0085</span>e" tmp && + grep "e<span class=.escape.>\\\\u2028</span>f<span class=.escape.>\\\\u2029</span>g$" tmp +' + +test_expect_success 'only a carriage return before a line feed is left as it is' ' + printf "h\\r\\n" >expect && + grep "^h" tmp >actual && + test_cmp expect actual && + grep "^i<span class=.escape.>\\\\r</span></code>" tmp +' + +test_expect_success 'the numbers count only the lines git counts' ' + grep "<a id=.n3. href=.#n3.>3</a>" tmp && + ! grep "<a id=.n4. href=.#n4.>4</a>" tmp +' + +test_expect_success 'the blame page escapes them the same way' ' + CGIT_CONFIG="$PWD/breaksrc" QUERY_STRING="url=breaks/blame/breaks.txt" cgit >tmp && + grep "<code>a<span class=.escape.>\\\\r</span>b<span class=.escape.>\\\\v</span>c" tmp && + grep "e<span class=.escape.>\\\\u2028</span>f<span class=.escape.>\\\\u2029</span>g$" tmp && + grep "^i<span class=.escape.>\\\\r</span></code>" tmp +' + +# The striped background is padded with spaces to the widest line, which is +# 31 columns once its six escapes are written out, though it is 18 bytes. +test_expect_success 'the blame stripes are as wide as the escaped line' ' + grep "^ \\{31\\}</pre></div>" tmp +' + test_expect_success 'generate foo+bar/tree' 'cgit_url "foo%2bbar/tree" >tmp' test_expect_success 'verify a+b link' ' diff --git a/tests/t0109-patch.sh b/tests/t0109-patch.sh index 3cb9d08..0c4bf8c 100755 --- a/tests/t0109-patch.sh +++ b/tests/t0109-patch.sh @@ -8,9 +8,13 @@ test_description='Check content on patch page' . ./setup.sh +# The version the built binary signs its patches with, without the v of the +# tag, as git writes its own. +CGIT_VERSION=$(sed -n "s/CGIT_VERSION = v\{0,1\}//p" "$TEST_OUTPUT_DIRECTORY/../build/VERSION") + # The signature sits on the second-to-last line, above the trailing blank. check_cgit_signature() { - tail -2 tmp | head -1 | grep "^cgit$" + tail -2 tmp | head -1 | grep -x -F "cgit $CGIT_VERSION" } test_expect_success 'generate foo/patch' ' @@ -35,7 +39,7 @@ test_expect_success 'find `cgit` signature' ' test_expect_success 'compare with output of git-format-patch(1)' ' git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" \ - --signature="cgit" --stdout HEAD^ >tmp2 && + --signature="cgit $CGIT_VERSION" --stdout HEAD^ >tmp2 && strip_headers <tmp >tmp_ && test_cmp tmp_ tmp2 ' @@ -64,7 +68,7 @@ test_expect_success 'find `cgit` signature on the range' ' test_expect_success 'compare the range with git-format-patch(1)' ' git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" \ - -N --signature="cgit" --stdout HEAD~3..HEAD >tmp2 && + -N --signature="cgit $CGIT_VERSION" --stdout HEAD~3..HEAD >tmp2 && strip_headers <tmp >tmp_ && test_cmp tmp_ tmp2 ' diff --git a/tests/t0502-syntax-highlight.sh b/tests/t0502-syntax-highlight.sh index 31ab7e7..ced9edd 100755 --- a/tests/t0502-syntax-highlight.sh +++ b/tests/t0502-syntax-highlight.sh @@ -70,4 +70,15 @@ test_expect_success CGIT_LUA 'bytes between tokens reach the page escaped' ' grep "<span class=.hl-number.>42</span> & " tmp ' +test_expect_success CGIT_LUA 'a lone carriage return reaches the page as an escape' ' + ( + cd repos/fake && + printf "if\\rzz\\n" >cr.fake && + git add cr.fake && + git commit -m "add a lone carriage return" + ) && + cgit_url "fake/tree/cr.fake" >tmp && + grep "<span class=.hl-keyword.>if</span><span class=.escape.>\\\\r</span>" tmp +' + test_done |
