summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2009-09-13 20:01:52 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-09-13 20:01:52 (UTC)
commit5f12e45fe3338095916a444ff106dd9fc9991d84 (patch) (side-by-side diff)
tree26b04e10b2ea277c09620bcf119eaa8f79e2fb88
parent45c49d6cf4b819385dfee620a81e3cb095ed5cd1 (diff)
parent6638f40868ccf7806a9668560d3608324704c2b7 (diff)
downloadcgit-5f12e45fe3338095916a444ff106dd9fc9991d84.zip
cgit-5f12e45fe3338095916a444ff106dd9fc9991d84.tar.gz
cgit-5f12e45fe3338095916a444ff106dd9fc9991d84.tar.bz2
Merge branch 'fp/linenumbers'
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c3
-rw-r--r--cgit.css6
-rw-r--r--cgit.h1
-rw-r--r--cgitrc.5.txt4
-rw-r--r--ui-tree.c35
5 files changed, 32 insertions, 17 deletions
diff --git a/cgit.c b/cgit.c
index b0e1c44..ec40e1f 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,336 +1,339 @@
/* cgit.c: cgi for the git scm
*
* Copyright (C) 2006 Lars Hjemli
*
* Licensed under GNU General Public License v2
* (see COPYING for full license text)
*/
#include "cgit.h"
#include "cache.h"
#include "cmd.h"
#include "configfile.h"
#include "html.h"
#include "ui-shared.h"
#include "ui-stats.h"
#include "scan-tree.h"
const char *cgit_version = CGIT_VERSION;
void add_mimetype(const char *name, const char *value)
{
struct string_list_item *item;
item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes);
item->util = xstrdup(value);
}
struct cgit_filter *new_filter(const char *cmd, int extra_args)
{
struct cgit_filter *f;
if (!cmd || !cmd[0])
return NULL;
f = xmalloc(sizeof(struct cgit_filter));
f->cmd = xstrdup(cmd);
f->argv = xmalloc((2 + extra_args) * sizeof(char *));
f->argv[0] = f->cmd;
f->argv[1] = NULL;
return f;
}
void config_cb(const char *name, const char *value)
{
if (!strcmp(name, "root-title"))
ctx.cfg.root_title = xstrdup(value);
else if (!strcmp(name, "root-desc"))
ctx.cfg.root_desc = xstrdup(value);
else if (!strcmp(name, "root-readme"))
ctx.cfg.root_readme = xstrdup(value);
else if (!strcmp(name, "css"))
ctx.cfg.css = xstrdup(value);
else if (!strcmp(name, "favicon"))
ctx.cfg.favicon = xstrdup(value);
else if (!strcmp(name, "footer"))
ctx.cfg.footer = xstrdup(value);
else if (!strcmp(name, "head-include"))
ctx.cfg.head_include = xstrdup(value);
else if (!strcmp(name, "header"))
ctx.cfg.header = xstrdup(value);
else if (!strcmp(name, "logo"))
ctx.cfg.logo = xstrdup(value);
else if (!strcmp(name, "index-header"))
ctx.cfg.index_header = xstrdup(value);
else if (!strcmp(name, "index-info"))
ctx.cfg.index_info = xstrdup(value);
else if (!strcmp(name, "logo-link"))
ctx.cfg.logo_link = xstrdup(value);
else if (!strcmp(name, "module-link"))
ctx.cfg.module_link = xstrdup(value);
else if (!strcmp(name, "virtual-root")) {
ctx.cfg.virtual_root = trim_end(value, '/');
if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
ctx.cfg.virtual_root = "";
} else if (!strcmp(name, "nocache"))
ctx.cfg.nocache = atoi(value);
else if (!strcmp(name, "noplainemail"))
ctx.cfg.noplainemail = atoi(value);
else if (!strcmp(name, "noheader"))
ctx.cfg.noheader = atoi(value);
else if (!strcmp(name, "snapshots"))
ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
else if (!strcmp(name, "enable-index-links"))
ctx.cfg.enable_index_links = atoi(value);
else if (!strcmp(name, "enable-log-filecount"))
ctx.cfg.enable_log_filecount = atoi(value);
else if (!strcmp(name, "enable-log-linecount"))
ctx.cfg.enable_log_linecount = atoi(value);
+ else if (!strcmp(name, "enable-tree-linenumbers"))
+ ctx.cfg.enable_tree_linenumbers = atoi(value);
else if (!strcmp(name, "max-stats"))
ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
else if (!strcmp(name, "cache-size"))
ctx.cfg.cache_size = atoi(value);
else if (!strcmp(name, "cache-root"))
ctx.cfg.cache_root = xstrdup(value);
else if (!strcmp(name, "cache-root-ttl"))
ctx.cfg.cache_root_ttl = atoi(value);
else if (!strcmp(name, "cache-repo-ttl"))
ctx.cfg.cache_repo_ttl = atoi(value);
else if (!strcmp(name, "cache-static-ttl"))
ctx.cfg.cache_static_ttl = atoi(value);
else if (!strcmp(name, "cache-dynamic-ttl"))
ctx.cfg.cache_dynamic_ttl = atoi(value);
else if (!strcmp(name, "about-filter"))
ctx.cfg.about_filter = new_filter(value, 0);
else if (!strcmp(name, "commit-filter"))
ctx.cfg.commit_filter = new_filter(value, 0);
else if (!strcmp(name, "embedded"))
ctx.cfg.embedded = atoi(value);
else if (!strcmp(name, "max-message-length"))
ctx.cfg.max_msg_len = atoi(value);
else if (!strcmp(name, "max-repodesc-length"))
ctx.cfg.max_repodesc_len = atoi(value);
else if (!strcmp(name, "max-repo-count"))
ctx.cfg.max_repo_count = atoi(value);
else if (!strcmp(name, "max-commit-count"))
ctx.cfg.max_commit_count = atoi(value);
else if (!strcmp(name, "source-filter"))
ctx.cfg.source_filter = new_filter(value, 1);
else if (!strcmp(name, "summary-log"))
ctx.cfg.summary_log = atoi(value);
else if (!strcmp(name, "summary-branches"))
ctx.cfg.summary_branches = atoi(value);
else if (!strcmp(name, "summary-tags"))
ctx.cfg.summary_tags = atoi(value);
else if (!strcmp(name, "agefile"))
ctx.cfg.agefile = xstrdup(value);
else if (!strcmp(name, "renamelimit"))
ctx.cfg.renamelimit = atoi(value);
else if (!strcmp(name, "robots"))
ctx.cfg.robots = xstrdup(value);
else if (!strcmp(name, "clone-prefix"))
ctx.cfg.clone_prefix = xstrdup(value);
else if (!strcmp(name, "local-time"))
ctx.cfg.local_time = atoi(value);
else if (!prefixcmp(name, "mimetype."))
add_mimetype(name + 9, value);
else if (!strcmp(name, "repo.group"))
ctx.cfg.repo_group = xstrdup(value);
else if (!strcmp(name, "repo.url"))
ctx.repo = cgit_add_repo(value);
else if (!strcmp(name, "repo.name"))
ctx.repo->name = xstrdup(value);
else if (ctx.repo && !strcmp(name, "repo.path"))
ctx.repo->path = trim_end(value, '/');
else if (ctx.repo && !strcmp(name, "repo.clone-url"))
ctx.repo->clone_url = xstrdup(value);
else if (ctx.repo && !strcmp(name, "repo.desc"))
ctx.repo->desc = xstrdup(value);
else if (ctx.repo && !strcmp(name, "repo.owner"))
ctx.repo->owner = xstrdup(value);
else if (ctx.repo && !strcmp(name, "repo.defbranch"))
ctx.repo->defbranch = xstrdup(value);
else if (ctx.repo && !strcmp(name, "repo.snapshots"))
ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
else if (ctx.repo && !strcmp(name, "repo.max-stats"))
ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
else if (ctx.repo && !strcmp(name, "repo.module-link"))
ctx.repo->module_link= xstrdup(value);
else if (ctx.repo && !strcmp(name, "repo.about-filter"))
ctx.repo->about_filter = new_filter(value, 0);
else if (ctx.repo && !strcmp(name, "repo.commit-filter"))
ctx.repo->commit_filter = new_filter(value, 0);
else if (ctx.repo && !strcmp(name, "repo.source-filter"))
ctx.repo->source_filter = new_filter(value, 1);
else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
if (*value == '/')
ctx.repo->readme = xstrdup(value);
else
ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
} else if (!strcmp(name, "include"))
parse_configfile(value, config_cb);
}
static void querystring_cb(const char *name, const char *value)
{
if (!value)
value = "";
if (!strcmp(name,"r")) {
ctx.qry.repo = xstrdup(value);
ctx.repo = cgit_get_repoinfo(value);
} else if (!strcmp(name, "p")) {
ctx.qry.page = xstrdup(value);
} else if (!strcmp(name, "url")) {
ctx.qry.url = xstrdup(value);
cgit_parse_url(value);
} else if (!strcmp(name, "qt")) {
ctx.qry.grep = xstrdup(value);
} else if (!strcmp(name, "q")) {
ctx.qry.search = xstrdup(value);
} else if (!strcmp(name, "h")) {
ctx.qry.head = xstrdup(value);
ctx.qry.has_symref = 1;
} else if (!strcmp(name, "id")) {
ctx.qry.sha1 = xstrdup(value);
ctx.qry.has_sha1 = 1;
} else if (!strcmp(name, "id2")) {
ctx.qry.sha2 = xstrdup(value);
ctx.qry.has_sha1 = 1;
} else if (!strcmp(name, "ofs")) {
ctx.qry.ofs = atoi(value);
} else if (!strcmp(name, "path")) {
ctx.qry.path = trim_end(value, '/');
} else if (!strcmp(name, "name")) {
ctx.qry.name = xstrdup(value);
} else if (!strcmp(name, "mimetype")) {
ctx.qry.mimetype = xstrdup(value);
} else if (!strcmp(name, "s")){
ctx.qry.sort = xstrdup(value);
} else if (!strcmp(name, "showmsg")) {
ctx.qry.showmsg = atoi(value);
} else if (!strcmp(name, "period")) {
ctx.qry.period = xstrdup(value);
}
}
char *xstrdupn(const char *str)
{
return (str ? xstrdup(str) : NULL);
}
static void prepare_context(struct cgit_context *ctx)
{
memset(ctx, 0, sizeof(ctx));
ctx->cfg.agefile = "info/web/last-modified";
ctx->cfg.nocache = 0;
ctx->cfg.cache_size = 0;
ctx->cfg.cache_dynamic_ttl = 5;
ctx->cfg.cache_max_create_time = 5;
ctx->cfg.cache_repo_ttl = 5;
ctx->cfg.cache_root = CGIT_CACHE_ROOT;
ctx->cfg.cache_root_ttl = 5;
ctx->cfg.cache_static_ttl = -1;
ctx->cfg.css = "/cgit.css";
ctx->cfg.logo = "/cgit.png";
ctx->cfg.local_time = 0;
+ ctx->cfg.enable_tree_linenumbers = 1;
ctx->cfg.max_repo_count = 50;
ctx->cfg.max_commit_count = 50;
ctx->cfg.max_lock_attempts = 5;
ctx->cfg.max_msg_len = 80;
ctx->cfg.max_repodesc_len = 80;
ctx->cfg.max_stats = 0;
ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
ctx->cfg.renamelimit = -1;
ctx->cfg.robots = "index, nofollow";
ctx->cfg.root_title = "Git repository browser";
ctx->cfg.root_desc = "a fast webinterface for the git dscm";
ctx->cfg.script_name = CGIT_SCRIPT_NAME;
ctx->cfg.summary_branches = 10;
ctx->cfg.summary_log = 10;
ctx->cfg.summary_tags = 10;
ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
ctx->env.https = xstrdupn(getenv("HTTPS"));
ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
ctx->page.mimetype = "text/html";
ctx->page.charset = PAGE_ENCODING;
ctx->page.filename = NULL;
ctx->page.size = 0;
ctx->page.modified = time(NULL);
ctx->page.expires = ctx->page.modified;
ctx->page.etag = NULL;
memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
if (ctx->env.script_name)
ctx->cfg.script_name = ctx->env.script_name;
if (ctx->env.query_string)
ctx->qry.raw = ctx->env.query_string;
if (!ctx->env.cgit_config)
ctx->env.cgit_config = CGIT_CONFIG;
}
struct refmatch {
char *req_ref;
char *first_ref;
int match;
};
int find_current_ref(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
struct refmatch *info;
info = (struct refmatch *)cb_data;
if (!strcmp(refname, info->req_ref))
info->match = 1;
if (!info->first_ref)
info->first_ref = xstrdup(refname);
return info->match;
}
char *find_default_branch(struct cgit_repo *repo)
{
struct refmatch info;
char *ref;
info.req_ref = repo->defbranch;
info.first_ref = NULL;
info.match = 0;
for_each_branch_ref(find_current_ref, &info);
if (info.match)
ref = info.req_ref;
else
ref = info.first_ref;
if (ref)
ref = xstrdup(ref);
return ref;
}
static int prepare_repo_cmd(struct cgit_context *ctx)
{
char *tmp;
unsigned char sha1[20];
int nongit = 0;
setenv("GIT_DIR", ctx->repo->path, 1);
setup_git_directory_gently(&nongit);
if (nongit) {
ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
"config error");
tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
ctx->repo = NULL;
cgit_print_http_headers(ctx);
cgit_print_docstart(ctx);
cgit_print_pageheader(ctx);
cgit_print_error(tmp);
cgit_print_docend();
diff --git a/cgit.css b/cgit.css
index e3b32e7..ebf3322 100644
--- a/cgit.css
+++ b/cgit.css
@@ -144,202 +144,202 @@ table.list th {
table.list td {
border: none;
padding: 0.1em 0.5em 0.1em 0.5em;
}
table.list td.logsubject {
font-family: monospace;
font-weight: bold;
}
table.list td.logmsg {
font-family: monospace;
white-space: pre;
padding: 1em 0.5em 2em 0.5em;
}
table.list td a {
color: black;
}
table.list td a:hover {
color: #00f;
}
img {
border: none;
}
input#switch-btn {
margin: 2px 0px 0px 0px;
}
td#sidebar input.txt {
width: 100%;
margin: 2px 0px 0px 0px;
}
table#grid {
margin: 0px;
}
td#content {
vertical-align: top;
padding: 1em 2em 1em 1em;
border: none;
}
div#summary {
vertical-align: top;
margin-bottom: 1em;
}
table#downloads {
float: right;
border-collapse: collapse;
border: solid 1px #777;
margin-left: 0.5em;
margin-bottom: 0.5em;
}
table#downloads th {
background-color: #ccc;
}
div#blob {
border: solid 1px black;
}
div.error {
color: red;
font-weight: bold;
margin: 1em 2em;
}
a.ls-blob, a.ls-dir, a.ls-mod {
font-family: monospace;
}
td.ls-size {
text-align: right;
font-family: monospace;
width: 10em;
}
td.ls-mode {
font-family: monospace;
width: 10em;
}
table.blob {
margin-top: 0.5em;
border-top: solid 1px black;
}
table.blob td.lines {
- margin: 0; padding: 0;
+ margin: 0; padding: 0 0 0 0.5em;
vertical-align: top;
color: black;
}
table.blob td.linenumbers {
- margin: 0; padding: 0;
+ margin: 0; padding: 0 0.5em 0 0.5em;
vertical-align: top;
+ text-align: right;
border-right: 1px solid gray;
- background-color: #eee;
}
table.blob pre {
padding: 0; margin: 0;
}
table.blob a.no {
color: gray;
text-align: right;
text-decoration: none;
}
table.blob a.no a:hover {
color: black;
}
table.bin-blob {
margin-top: 0.5em;
border: solid 1px black;
}
table.bin-blob th {
font-family: monospace;
white-space: pre;
border: solid 1px #777;
padding: 0.5em 1em;
}
table.bin-blob td {
font-family: monospace;
white-space: pre;
border-left: solid 1px #777;
padding: 0em 1em;
}
table.nowrap td {
white-space: nowrap;
}
table.commit-info {
border-collapse: collapse;
margin-top: 1.5em;
}
table.commit-info th {
text-align: left;
font-weight: normal;
padding: 0.1em 1em 0.1em 0.1em;
vertical-align: top;
}
table.commit-info td {
font-weight: normal;
padding: 0.1em 1em 0.1em 0.1em;
}
div.commit-subject {
font-weight: bold;
font-size: 125%;
margin: 1.5em 0em 0.5em 0em;
padding: 0em;
}
div.commit-msg {
white-space: pre;
font-family: monospace;
}
div.diffstat-header {
font-weight: bold;
padding-top: 1.5em;
}
table.diffstat {
border-collapse: collapse;
border: solid 1px #aaa;
background-color: #eee;
}
table.diffstat th {
font-weight: normal;
text-align: left;
text-decoration: underline;
padding: 0.1em 1em 0.1em 0.1em;
font-size: 100%;
}
table.diffstat td {
padding: 0.2em 0.2em 0.1em 0.1em;
font-size: 100%;
border: none;
}
table.diffstat td.mode {
white-space: nowrap;
}
diff --git a/cgit.h b/cgit.h
index adb8da4..a20679a 100644
--- a/cgit.h
+++ b/cgit.h
@@ -80,192 +80,193 @@ struct cgit_repo {
};
struct cgit_repolist {
int length;
int count;
struct cgit_repo *repos;
};
struct commitinfo {
struct commit *commit;
char *author;
char *author_email;
unsigned long author_date;
char *committer;
char *committer_email;
unsigned long committer_date;
char *subject;
char *msg;
char *msg_encoding;
};
struct taginfo {
char *tagger;
char *tagger_email;
unsigned long tagger_date;
char *msg;
};
struct refinfo {
const char *refname;
struct object *object;
union {
struct taginfo *tag;
struct commitinfo *commit;
};
};
struct reflist {
struct refinfo **refs;
int alloc;
int count;
};
struct cgit_query {
int has_symref;
int has_sha1;
char *raw;
char *repo;
char *page;
char *search;
char *grep;
char *head;
char *sha1;
char *sha2;
char *path;
char *name;
char *mimetype;
char *url;
char *period;
int ofs;
int nohead;
char *sort;
int showmsg;
};
struct cgit_config {
char *agefile;
char *cache_root;
char *clone_prefix;
char *css;
char *favicon;
char *footer;
char *head_include;
char *header;
char *index_header;
char *index_info;
char *logo;
char *logo_link;
char *module_link;
char *repo_group;
char *robots;
char *root_title;
char *root_desc;
char *root_readme;
char *script_name;
char *virtual_root;
int cache_size;
int cache_dynamic_ttl;
int cache_max_create_time;
int cache_repo_ttl;
int cache_root_ttl;
int cache_static_ttl;
int embedded;
int enable_index_links;
int enable_log_filecount;
int enable_log_linecount;
+ int enable_tree_linenumbers;
int local_time;
int max_repo_count;
int max_commit_count;
int max_lock_attempts;
int max_msg_len;
int max_repodesc_len;
int max_stats;
int nocache;
int noplainemail;
int noheader;
int renamelimit;
int snapshots;
int summary_branches;
int summary_log;
int summary_tags;
struct string_list mimetypes;
struct cgit_filter *about_filter;
struct cgit_filter *commit_filter;
struct cgit_filter *source_filter;
};
struct cgit_page {
time_t modified;
time_t expires;
size_t size;
char *mimetype;
char *charset;
char *filename;
char *etag;
char *title;
int status;
char *statusmsg;
};
struct cgit_environment {
char *cgit_config;
char *http_host;
char *https;
char *no_http;
char *path_info;
char *query_string;
char *request_method;
char *script_name;
char *server_name;
char *server_port;
};
struct cgit_context {
struct cgit_environment env;
struct cgit_query qry;
struct cgit_config cfg;
struct cgit_repo *repo;
struct cgit_page page;
};
struct cgit_snapshot_format {
const char *suffix;
const char *mimetype;
write_archive_fn_t write_func;
int bit;
};
extern const char *cgit_version;
extern struct cgit_repolist cgit_repolist;
extern struct cgit_context ctx;
extern const struct cgit_snapshot_format cgit_snapshot_formats[];
extern struct cgit_repo *cgit_add_repo(const char *url);
extern struct cgit_repo *cgit_get_repoinfo(const char *url);
extern void cgit_repo_config_cb(const char *name, const char *value);
extern int chk_zero(int result, char *msg);
extern int chk_positive(int result, char *msg);
extern int chk_non_negative(int result, char *msg);
extern char *trim_end(const char *str, char c);
extern char *strlpart(char *txt, int maxlen);
extern char *strrpart(char *txt, int maxlen);
extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
int flags, void *cb_data);
extern void *cgit_free_commitinfo(struct commitinfo *info);
extern int cgit_diff_files(const unsigned char *old_sha1,
const unsigned char *new_sha1,
unsigned long *old_size, unsigned long *new_size,
int *binary, linediff_fn fn);
extern void cgit_diff_tree(const unsigned char *old_sha1,
const unsigned char *new_sha1,
filepair_fn fn, const char *prefix);
extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 0d18290..3b16db9 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -6,192 +6,196 @@ NAME
----
cgitrc - runtime configuration for cgit
SYNOPSIS
--------
Cgitrc contains all runtime settings for cgit, including the list of git
repositories, formatted as a line-separated list of NAME=VALUE pairs. Blank
lines, and lines starting with '#', are ignored.
LOCATION
--------
The default location of cgitrc, defined at compile time, is /etc/cgitrc. At
runtime, cgit will consult the environment variable CGIT_CONFIG and, if
defined, use its value instead.
GLOBAL SETTINGS
---------------
about-filter::
Specifies a command which will be invoked to format the content of
about pages (both top-level and for each repository). The command will
get the content of the about-file on its STDIN, and the STDOUT from the
command will be included verbatim on the about page. Default value:
none.
agefile::
Specifies a path, relative to each repository path, which can be used
to specify the date and time of the youngest commit in the repository.
The first line in the file is used as input to the "parse_date"
function in libgit. Recommended timestamp-format is "yyyy-mm-dd
hh:mm:ss". Default value: "info/web/last-modified".
cache-root::
Path used to store the cgit cache entries. Default value:
"/var/cache/cgit".
cache-dynamic-ttl::
Number which specifies the time-to-live, in minutes, for the cached
version of repository pages accessed without a fixed SHA1. Default
value: "5".
cache-repo-ttl::
Number which specifies the time-to-live, in minutes, for the cached
version of the repository summary page. Default value: "5".
cache-root-ttl::
Number which specifies the time-to-live, in minutes, for the cached
version of the repository index page. Default value: "5".
cache-size::
The maximum number of entries in the cgit cache. Default value: "0"
(i.e. caching is disabled).
cache-static-ttl::
Number which specifies the time-to-live, in minutes, for the cached
version of repository pages accessed with a fixed SHA1. Default value:
"5".
clone-prefix::
Space-separated list of common prefixes which, when combined with a
repository url, generates valid clone urls for the repository. This
setting is only used if `repo.clone-url` is unspecified. Default value:
none.
commit-filter::
Specifies a command which will be invoked to format commit messages.
The command will get the message on its STDIN, and the STDOUT from the
command will be included verbatim as the commit message, i.e. this can
be used to implement bugtracker integration. Default value: none.
css::
Url which specifies the css document to include in all cgit pages.
Default value: "/cgit.css".
embedded::
Flag which, when set to "1", will make cgit generate a html fragment
suitable for embedding in other html pages. Default value: none. See
also: "noheader".
enable-index-links::
Flag which, when set to "1", will make cgit generate extra links for
each repo in the repository index (specifically, to the "summary",
"commit" and "tree" pages). Default value: "0".
enable-log-filecount::
Flag which, when set to "1", will make cgit print the number of
modified files for each commit on the repository log page. Default
value: "0".
enable-log-linecount::
Flag which, when set to "1", will make cgit print the number of added
and removed lines for each commit on the repository log page. Default
value: "0".
+enable-tree-linenumbers::
+ Flag which, when set to "1", will make cgit generate linenumber links
+ for plaintext blobs printed in the tree view. Default value: "1".
+
favicon::
Url used as link to a shortcut icon for cgit. If specified, it is
suggested to use the value "/favicon.ico" since certain browsers will
ignore other values. Default value: none.
footer::
The content of the file specified with this option will be included
verbatim at the bottom of all pages (i.e. it replaces the standard
"generated by..." message. Default value: none.
head-include::
The content of the file specified with this option will be included
verbatim in the html HEAD section on all pages. Default value: none.
header::
The content of the file specified with this option will be included
verbatim at the top of all pages. Default value: none.
include::
Name of a configfile to include before the rest of the current config-
file is parsed. Default value: none.
index-header::
The content of the file specified with this option will be included
verbatim above the repository index. This setting is deprecated, and
will not be supported by cgit-1.0 (use root-readme instead). Default
value: none.
index-info::
The content of the file specified with this option will be included
verbatim below the heading on the repository index page. This setting
is deprecated, and will not be supported by cgit-1.0 (use root-desc
instead). Default value: none.
local-time::
Flag which, if set to "1", makes cgit print commit and tag times in the
servers timezone. Default value: "0".
logo::
Url which specifies the source of an image which will be used as a logo
on all cgit pages. Default value: "/cgit.png".
logo-link::
Url loaded when clicking on the cgit logo image. If unspecified the
calculated url of the repository index page will be used. Default
value: none.
max-commit-count::
Specifies the number of entries to list per page in "log" view. Default
value: "50".
max-message-length::
Specifies the maximum number of commit message characters to display in
"log" view. Default value: "80".
max-repo-count::
Specifies the number of entries to list per page on the repository
index page. Default value: "50".
max-repodesc-length::
Specifies the maximum number of repo description characters to display
on the repository index page. Default value: "80".
max-stats::
Set the default maximum statistics period. Valid values are "week",
"month", "quarter" and "year". If unspecified, statistics are
disabled. Default value: none. See also: "repo.max-stats".
mimetype.<ext>::
Set the mimetype for the specified filename extension. This is used
by the `plain` command when returning blob content.
module-link::
Text which will be used as the formatstring for a hyperlink when a
submodule is printed in a directory listing. The arguments for the
formatstring are the path and SHA1 of the submodule commit. Default
value: "./?repo=%s&page=commit&id=%s"
nocache::
If set to the value "1" caching will be disabled. This settings is
deprecated, and will not be honored starting with cgit-1.0. Default
value: "0".
noplainemail::
If set to "1" showing full author email adresses will be disabled.
Default value: "0".
noheader::
Flag which, when set to "1", will make cgit omit the standard header
on all pages. Default value: none. See also: "embedded".
renamelimit::
Maximum number of files to consider when detecting renames. The value
"-1" uses the compiletime value in git (for further info, look at
`man git-diff`). Default value: "-1".
diff --git a/ui-tree.c b/ui-tree.c
index c608754..f53ab64 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,143 +1,150 @@
/* ui-tree.c: functions for tree output
*
* Copyright (C) 2006 Lars Hjemli
*
* Licensed under GNU General Public License v2
* (see COPYING for full license text)
*/
#include <ctype.h>
#include "cgit.h"
#include "html.h"
#include "ui-shared.h"
char *curr_rev;
char *match_path;
int header = 0;
static void print_text_buffer(const char *name, char *buf, unsigned long size)
{
unsigned long lineno, idx;
const char *numberfmt =
"<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n";
html("<table summary='blob content' class='blob'>\n");
+
+ if (ctx.cfg.enable_tree_linenumbers) {
+ html("<tr><td class='linenumbers'><pre>");
+ idx = 0;
+ lineno = 0;
+
+ if (size) {
+ htmlf(numberfmt, ++lineno);
+ while(idx < size - 1) { // skip absolute last newline
+ if (buf[idx] == '\n')
+ htmlf(numberfmt, ++lineno);
+ idx++;
+ }
+ }
+ html("</pre></td>\n");
+ }
+ else {
+ html("<tr>\n");
+ }
+
if (ctx.repo->source_filter) {
- html("<tr><td class='lines'><pre><code>");
+ html("<td class='lines'><pre><code>");
ctx.repo->source_filter->argv[1] = xstrdup(name);
cgit_open_filter(ctx.repo->source_filter);
write(STDOUT_FILENO, buf, size);
cgit_close_filter(ctx.repo->source_filter);
html("</code></pre></td></tr></table>\n");
return;
}
- html("<tr><td class='linenumbers'><pre>");
- idx = 0;
- lineno = 0;
-
- if (size) {
- htmlf(numberfmt, ++lineno);
- while(idx < size - 1) { // skip absolute last newline
- if (buf[idx] == '\n')
- htmlf(numberfmt, ++lineno);
- idx++;
- }
- }
- html("</pre></td>\n");
html("<td class='lines'><pre><code>");
html_txt(buf);
html("</code></pre></td></tr></table>\n");
}
#define ROWLEN 32
static void print_binary_buffer(char *buf, unsigned long size)
{
unsigned long ofs, idx;
static char ascii[ROWLEN + 1];
html("<table summary='blob content' class='bin-blob'>\n");
html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs);
for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
htmlf("%*s%02x",
idx == 16 ? 4 : 1, "",
buf[idx] & 0xff);
html(" </td><td class='hex'>");
for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
ascii[idx] = '\0';
html_txt(ascii);
html("</td></tr>\n");
}
html("</table>\n");
}
static void print_object(const unsigned char *sha1, char *path, const char *basename)
{
enum object_type type;
char *buf;
unsigned long size;
type = sha1_object_info(sha1, &size);
if (type == OBJ_BAD) {
cgit_print_error(fmt("Bad object name: %s",
sha1_to_hex(sha1)));
return;
}
buf = read_sha1_file(sha1, &type, &size);
if (!buf) {
cgit_print_error(fmt("Error reading object %s",
sha1_to_hex(sha1)));
return;
}
html(" (");
cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
curr_rev, path);
htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1));
if (buffer_is_binary(buf, size))
print_binary_buffer(buf, size);
else
print_text_buffer(basename, buf, size);
}
static int ls_item(const unsigned char *sha1, const char *base, int baselen,
const char *pathname, unsigned int mode, int stage,
void *cbdata)
{
char *name;
char *fullpath;
char *class;
enum object_type type;
unsigned long size = 0;
name = xstrdup(pathname);
fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
ctx.qry.path ? "/" : "", name);
if (!S_ISGITLINK(mode)) {
type = sha1_object_info(sha1, &size);
if (type == OBJ_BAD) {
htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
name,
sha1_to_hex(sha1));
return 0;
}
}
html("<tr><td class='ls-mode'>");
cgit_print_filemode(mode);
html("</td><td>");
if (S_ISGITLINK(mode)) {
htmlf("<a class='ls-mod' href='");
html_attr(fmt(ctx.repo->module_link,
name,
sha1_to_hex(sha1)));
html("'>");
html_txt(name);