summaryrefslogtreecommitdiffabout
authorJohan Herland <johan@herland.net>2010-06-09 23:09:36 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2010-06-19 08:40:24 (UTC)
commit7fdff2460440c09d13fc76af3b75e85434e6f563 (patch) (unidiff)
tree2285bf24286d5ec6046a13b18599e0e00e63111d
parent685872b770be2af643d00365d5358e46687f7385 (diff)
downloadcgit-7fdff2460440c09d13fc76af3b75e85434e6f563.zip
cgit-7fdff2460440c09d13fc76af3b75e85434e6f563.tar.gz
cgit-7fdff2460440c09d13fc76af3b75e85434e6f563.tar.bz2
ui-shared: Preserve path limit in "tab bar" links
When using the "tab bar" in the pageheader to navigate between pages, any path limit in effect on the current page is forgotten in the link to the target page, even if the target page can interpret and use the path limit constructively. Instead, preserve the current page's path limit in the "tab bar" links to other pages, where the path limit is useful to the target page. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--ui-shared.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/ui-shared.c b/ui-shared.c
index 372b9e7..e991799 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -409,475 +409,476 @@ void cgit_self_link(char *name, const char *title, const char *class,
409 else if (!strcmp(ctx->qry.page, "summary")) 409 else if (!strcmp(ctx->qry.page, "summary"))
410 return cgit_summary_link(name, title, class, ctx->qry.head); 410 return cgit_summary_link(name, title, class, ctx->qry.head);
411 else if (!strcmp(ctx->qry.page, "tag")) 411 else if (!strcmp(ctx->qry.page, "tag"))
412 return cgit_tag_link(name, title, class, ctx->qry.head, 412 return cgit_tag_link(name, title, class, ctx->qry.head,
413 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL); 413 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL);
414 else if (!strcmp(ctx->qry.page, "tree")) 414 else if (!strcmp(ctx->qry.page, "tree"))
415 return cgit_tree_link(name, title, class, ctx->qry.head, 415 return cgit_tree_link(name, title, class, ctx->qry.head,
416 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 416 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
417 ctx->qry.path); 417 ctx->qry.path);
418 else if (!strcmp(ctx->qry.page, "plain")) 418 else if (!strcmp(ctx->qry.page, "plain"))
419 return cgit_plain_link(name, title, class, ctx->qry.head, 419 return cgit_plain_link(name, title, class, ctx->qry.head,
420 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 420 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
421 ctx->qry.path); 421 ctx->qry.path);
422 else if (!strcmp(ctx->qry.page, "log")) 422 else if (!strcmp(ctx->qry.page, "log"))
423 return cgit_log_link(name, title, class, ctx->qry.head, 423 return cgit_log_link(name, title, class, ctx->qry.head,
424 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 424 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
425 ctx->qry.path, ctx->qry.ofs, 425 ctx->qry.path, ctx->qry.ofs,
426 ctx->qry.grep, ctx->qry.search, 426 ctx->qry.grep, ctx->qry.search,
427 ctx->qry.showmsg); 427 ctx->qry.showmsg);
428 else if (!strcmp(ctx->qry.page, "commit")) 428 else if (!strcmp(ctx->qry.page, "commit"))
429 return cgit_commit_link(name, title, class, ctx->qry.head, 429 return cgit_commit_link(name, title, class, ctx->qry.head,
430 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 430 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
431 ctx->qry.path, 0); 431 ctx->qry.path, 0);
432 else if (!strcmp(ctx->qry.page, "patch")) 432 else if (!strcmp(ctx->qry.page, "patch"))
433 return cgit_patch_link(name, title, class, ctx->qry.head, 433 return cgit_patch_link(name, title, class, ctx->qry.head,
434 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 434 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
435 ctx->qry.path); 435 ctx->qry.path);
436 else if (!strcmp(ctx->qry.page, "refs")) 436 else if (!strcmp(ctx->qry.page, "refs"))
437 return cgit_refs_link(name, title, class, ctx->qry.head, 437 return cgit_refs_link(name, title, class, ctx->qry.head,
438 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 438 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
439 ctx->qry.path); 439 ctx->qry.path);
440 else if (!strcmp(ctx->qry.page, "snapshot")) 440 else if (!strcmp(ctx->qry.page, "snapshot"))
441 return cgit_snapshot_link(name, title, class, ctx->qry.head, 441 return cgit_snapshot_link(name, title, class, ctx->qry.head,
442 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 442 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
443 ctx->qry.path); 443 ctx->qry.path);
444 else if (!strcmp(ctx->qry.page, "diff")) 444 else if (!strcmp(ctx->qry.page, "diff"))
445 return cgit_diff_link(name, title, class, ctx->qry.head, 445 return cgit_diff_link(name, title, class, ctx->qry.head,
446 ctx->qry.sha1, ctx->qry.sha2, 446 ctx->qry.sha1, ctx->qry.sha2,
447 ctx->qry.path, 0); 447 ctx->qry.path, 0);
448 else if (!strcmp(ctx->qry.page, "stats")) 448 else if (!strcmp(ctx->qry.page, "stats"))
449 return cgit_stats_link(name, title, class, ctx->qry.head, 449 return cgit_stats_link(name, title, class, ctx->qry.head,
450 ctx->qry.path); 450 ctx->qry.path);
451 451
452 /* Don't known how to make link for this page */ 452 /* Don't known how to make link for this page */
453 repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path); 453 repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path);
454 html("><!-- cgit_self_link() doesn't know how to make link for page '"); 454 html("><!-- cgit_self_link() doesn't know how to make link for page '");
455 html_txt(ctx->qry.page); 455 html_txt(ctx->qry.page);
456 html("' -->"); 456 html("' -->");
457 html_txt(name); 457 html_txt(name);
458 html("</a>"); 458 html("</a>");
459} 459}
460 460
461void cgit_object_link(struct object *obj) 461void cgit_object_link(struct object *obj)
462{ 462{
463 char *page, *shortrev, *fullrev, *name; 463 char *page, *shortrev, *fullrev, *name;
464 464
465 fullrev = sha1_to_hex(obj->sha1); 465 fullrev = sha1_to_hex(obj->sha1);
466 shortrev = xstrdup(fullrev); 466 shortrev = xstrdup(fullrev);
467 shortrev[10] = '\0'; 467 shortrev[10] = '\0';
468 if (obj->type == OBJ_COMMIT) { 468 if (obj->type == OBJ_COMMIT) {
469 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, 469 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
470 ctx.qry.head, fullrev, NULL, 0); 470 ctx.qry.head, fullrev, NULL, 0);
471 return; 471 return;
472 } else if (obj->type == OBJ_TREE) 472 } else if (obj->type == OBJ_TREE)
473 page = "tree"; 473 page = "tree";
474 else if (obj->type == OBJ_TAG) 474 else if (obj->type == OBJ_TAG)
475 page = "tag"; 475 page = "tag";
476 else 476 else
477 page = "blob"; 477 page = "blob";
478 name = fmt("%s %s...", typename(obj->type), shortrev); 478 name = fmt("%s %s...", typename(obj->type), shortrev);
479 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); 479 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
480} 480}
481 481
482void cgit_print_date(time_t secs, const char *format, int local_time) 482void cgit_print_date(time_t secs, const char *format, int local_time)
483{ 483{
484 char buf[64]; 484 char buf[64];
485 struct tm *time; 485 struct tm *time;
486 486
487 if (!secs) 487 if (!secs)
488 return; 488 return;
489 if(local_time) 489 if(local_time)
490 time = localtime(&secs); 490 time = localtime(&secs);
491 else 491 else
492 time = gmtime(&secs); 492 time = gmtime(&secs);
493 strftime(buf, sizeof(buf)-1, format, time); 493 strftime(buf, sizeof(buf)-1, format, time);
494 html_txt(buf); 494 html_txt(buf);
495} 495}
496 496
497void cgit_print_age(time_t t, time_t max_relative, const char *format) 497void cgit_print_age(time_t t, time_t max_relative, const char *format)
498{ 498{
499 time_t now, secs; 499 time_t now, secs;
500 500
501 if (!t) 501 if (!t)
502 return; 502 return;
503 time(&now); 503 time(&now);
504 secs = now - t; 504 secs = now - t;
505 505
506 if (secs > max_relative && max_relative >= 0) { 506 if (secs > max_relative && max_relative >= 0) {
507 cgit_print_date(t, format, ctx.cfg.local_time); 507 cgit_print_date(t, format, ctx.cfg.local_time);
508 return; 508 return;
509 } 509 }
510 510
511 if (secs < TM_HOUR * 2) { 511 if (secs < TM_HOUR * 2) {
512 htmlf("<span class='age-mins'>%.0f min.</span>", 512 htmlf("<span class='age-mins'>%.0f min.</span>",
513 secs * 1.0 / TM_MIN); 513 secs * 1.0 / TM_MIN);
514 return; 514 return;
515 } 515 }
516 if (secs < TM_DAY * 2) { 516 if (secs < TM_DAY * 2) {
517 htmlf("<span class='age-hours'>%.0f hours</span>", 517 htmlf("<span class='age-hours'>%.0f hours</span>",
518 secs * 1.0 / TM_HOUR); 518 secs * 1.0 / TM_HOUR);
519 return; 519 return;
520 } 520 }
521 if (secs < TM_WEEK * 2) { 521 if (secs < TM_WEEK * 2) {
522 htmlf("<span class='age-days'>%.0f days</span>", 522 htmlf("<span class='age-days'>%.0f days</span>",
523 secs * 1.0 / TM_DAY); 523 secs * 1.0 / TM_DAY);
524 return; 524 return;
525 } 525 }
526 if (secs < TM_MONTH * 2) { 526 if (secs < TM_MONTH * 2) {
527 htmlf("<span class='age-weeks'>%.0f weeks</span>", 527 htmlf("<span class='age-weeks'>%.0f weeks</span>",
528 secs * 1.0 / TM_WEEK); 528 secs * 1.0 / TM_WEEK);
529 return; 529 return;
530 } 530 }
531 if (secs < TM_YEAR * 2) { 531 if (secs < TM_YEAR * 2) {
532 htmlf("<span class='age-months'>%.0f months</span>", 532 htmlf("<span class='age-months'>%.0f months</span>",
533 secs * 1.0 / TM_MONTH); 533 secs * 1.0 / TM_MONTH);
534 return; 534 return;
535 } 535 }
536 htmlf("<span class='age-years'>%.0f years</span>", 536 htmlf("<span class='age-years'>%.0f years</span>",
537 secs * 1.0 / TM_YEAR); 537 secs * 1.0 / TM_YEAR);
538} 538}
539 539
540void cgit_print_http_headers(struct cgit_context *ctx) 540void cgit_print_http_headers(struct cgit_context *ctx)
541{ 541{
542 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1")) 542 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1"))
543 return; 543 return;
544 544
545 if (ctx->page.status) 545 if (ctx->page.status)
546 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg); 546 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg);
547 if (ctx->page.mimetype && ctx->page.charset) 547 if (ctx->page.mimetype && ctx->page.charset)
548 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, 548 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
549 ctx->page.charset); 549 ctx->page.charset);
550 else if (ctx->page.mimetype) 550 else if (ctx->page.mimetype)
551 htmlf("Content-Type: %s\n", ctx->page.mimetype); 551 htmlf("Content-Type: %s\n", ctx->page.mimetype);
552 if (ctx->page.size) 552 if (ctx->page.size)
553 htmlf("Content-Length: %ld\n", ctx->page.size); 553 htmlf("Content-Length: %ld\n", ctx->page.size);
554 if (ctx->page.filename) 554 if (ctx->page.filename)
555 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 555 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
556 ctx->page.filename); 556 ctx->page.filename);
557 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 557 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
558 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 558 htmlf("Expires: %s\n", http_date(ctx->page.expires));
559 if (ctx->page.etag) 559 if (ctx->page.etag)
560 htmlf("ETag: \"%s\"\n", ctx->page.etag); 560 htmlf("ETag: \"%s\"\n", ctx->page.etag);
561 html("\n"); 561 html("\n");
562 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD")) 562 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD"))
563 exit(0); 563 exit(0);
564} 564}
565 565
566void cgit_print_docstart(struct cgit_context *ctx) 566void cgit_print_docstart(struct cgit_context *ctx)
567{ 567{
568 if (ctx->cfg.embedded) { 568 if (ctx->cfg.embedded) {
569 if (ctx->cfg.header) 569 if (ctx->cfg.header)
570 html_include(ctx->cfg.header); 570 html_include(ctx->cfg.header);
571 return; 571 return;
572 } 572 }
573 573
574 char *host = cgit_hosturl(); 574 char *host = cgit_hosturl();
575 html(cgit_doctype); 575 html(cgit_doctype);
576 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 576 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
577 html("<head>\n"); 577 html("<head>\n");
578 html("<title>"); 578 html("<title>");
579 html_txt(ctx->page.title); 579 html_txt(ctx->page.title);
580 html("</title>\n"); 580 html("</title>\n");
581 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 581 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
582 if (ctx->cfg.robots && *ctx->cfg.robots) 582 if (ctx->cfg.robots && *ctx->cfg.robots)
583 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 583 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
584 html("<link rel='stylesheet' type='text/css' href='"); 584 html("<link rel='stylesheet' type='text/css' href='");
585 html_attr(ctx->cfg.css); 585 html_attr(ctx->cfg.css);
586 html("'/>\n"); 586 html("'/>\n");
587 if (ctx->cfg.favicon) { 587 if (ctx->cfg.favicon) {
588 html("<link rel='shortcut icon' href='"); 588 html("<link rel='shortcut icon' href='");
589 html_attr(ctx->cfg.favicon); 589 html_attr(ctx->cfg.favicon);
590 html("'/>\n"); 590 html("'/>\n");
591 } 591 }
592 if (host && ctx->repo) { 592 if (host && ctx->repo) {
593 html("<link rel='alternate' title='Atom feed' href='"); 593 html("<link rel='alternate' title='Atom feed' href='");
594 html(cgit_httpscheme()); 594 html(cgit_httpscheme());
595 html_attr(cgit_hosturl()); 595 html_attr(cgit_hosturl());
596 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, 596 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath,
597 fmt("h=%s", ctx->qry.head))); 597 fmt("h=%s", ctx->qry.head)));
598 html("' type='application/atom+xml'/>\n"); 598 html("' type='application/atom+xml'/>\n");
599 } 599 }
600 if (ctx->cfg.head_include) 600 if (ctx->cfg.head_include)
601 html_include(ctx->cfg.head_include); 601 html_include(ctx->cfg.head_include);
602 html("</head>\n"); 602 html("</head>\n");
603 html("<body>\n"); 603 html("<body>\n");
604 if (ctx->cfg.header) 604 if (ctx->cfg.header)
605 html_include(ctx->cfg.header); 605 html_include(ctx->cfg.header);
606} 606}
607 607
608void cgit_print_docend() 608void cgit_print_docend()
609{ 609{
610 html("</div> <!-- class=content -->\n"); 610 html("</div> <!-- class=content -->\n");
611 if (ctx.cfg.embedded) { 611 if (ctx.cfg.embedded) {
612 html("</div> <!-- id=cgit -->\n"); 612 html("</div> <!-- id=cgit -->\n");
613 if (ctx.cfg.footer) 613 if (ctx.cfg.footer)
614 html_include(ctx.cfg.footer); 614 html_include(ctx.cfg.footer);
615 return; 615 return;
616 } 616 }
617 if (ctx.cfg.footer) 617 if (ctx.cfg.footer)
618 html_include(ctx.cfg.footer); 618 html_include(ctx.cfg.footer);
619 else { 619 else {
620 htmlf("<div class='footer'>generated by cgit %s at ", 620 htmlf("<div class='footer'>generated by cgit %s at ",
621 cgit_version); 621 cgit_version);
622 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); 622 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
623 html("</div>\n"); 623 html("</div>\n");
624 } 624 }
625 html("</div> <!-- id=cgit -->\n"); 625 html("</div> <!-- id=cgit -->\n");
626 html("</body>\n</html>\n"); 626 html("</body>\n</html>\n");
627} 627}
628 628
629int print_branch_option(const char *refname, const unsigned char *sha1, 629int print_branch_option(const char *refname, const unsigned char *sha1,
630 int flags, void *cb_data) 630 int flags, void *cb_data)
631{ 631{
632 char *name = (char *)refname; 632 char *name = (char *)refname;
633 html_option(name, name, ctx.qry.head); 633 html_option(name, name, ctx.qry.head);
634 return 0; 634 return 0;
635} 635}
636 636
637int print_archive_ref(const char *refname, const unsigned char *sha1, 637int print_archive_ref(const char *refname, const unsigned char *sha1,
638 int flags, void *cb_data) 638 int flags, void *cb_data)
639{ 639{
640 struct tag *tag; 640 struct tag *tag;
641 struct taginfo *info; 641 struct taginfo *info;
642 struct object *obj; 642 struct object *obj;
643 char buf[256], *url; 643 char buf[256], *url;
644 unsigned char fileid[20]; 644 unsigned char fileid[20];
645 int *header = (int *)cb_data; 645 int *header = (int *)cb_data;
646 646
647 if (prefixcmp(refname, "refs/archives")) 647 if (prefixcmp(refname, "refs/archives"))
648 return 0; 648 return 0;
649 strncpy(buf, refname+14, sizeof(buf)); 649 strncpy(buf, refname+14, sizeof(buf));
650 obj = parse_object(sha1); 650 obj = parse_object(sha1);
651 if (!obj) 651 if (!obj)
652 return 1; 652 return 1;
653 if (obj->type == OBJ_TAG) { 653 if (obj->type == OBJ_TAG) {
654 tag = lookup_tag(sha1); 654 tag = lookup_tag(sha1);
655 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 655 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
656 return 0; 656 return 0;
657 hashcpy(fileid, tag->tagged->sha1); 657 hashcpy(fileid, tag->tagged->sha1);
658 } else if (obj->type != OBJ_BLOB) { 658 } else if (obj->type != OBJ_BLOB) {
659 return 0; 659 return 0;
660 } else { 660 } else {
661 hashcpy(fileid, sha1); 661 hashcpy(fileid, sha1);
662 } 662 }
663 if (!*header) { 663 if (!*header) {
664 html("<h1>download</h1>\n"); 664 html("<h1>download</h1>\n");
665 *header = 1; 665 *header = 1;
666 } 666 }
667 url = cgit_pageurl(ctx.qry.repo, "blob", 667 url = cgit_pageurl(ctx.qry.repo, "blob",
668 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 668 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
669 buf)); 669 buf));
670 html_link_open(url, NULL, "menu"); 670 html_link_open(url, NULL, "menu");
671 html_txt(strlpart(buf, 20)); 671 html_txt(strlpart(buf, 20));
672 html_link_close(); 672 html_link_close();
673 return 0; 673 return 0;
674} 674}
675 675
676void cgit_add_hidden_formfields(int incl_head, int incl_search, 676void cgit_add_hidden_formfields(int incl_head, int incl_search,
677 const char *page) 677 const char *page)
678{ 678{
679 char *url; 679 char *url;
680 680
681 if (!ctx.cfg.virtual_root) { 681 if (!ctx.cfg.virtual_root) {
682 url = fmt("%s/%s", ctx.qry.repo, page); 682 url = fmt("%s/%s", ctx.qry.repo, page);
683 if (ctx.qry.vpath) 683 if (ctx.qry.vpath)
684 url = fmt("%s/%s", url, ctx.qry.vpath); 684 url = fmt("%s/%s", url, ctx.qry.vpath);
685 html_hidden("url", url); 685 html_hidden("url", url);
686 } 686 }
687 687
688 if (incl_head && ctx.qry.head && ctx.repo->defbranch && 688 if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
689 strcmp(ctx.qry.head, ctx.repo->defbranch)) 689 strcmp(ctx.qry.head, ctx.repo->defbranch))
690 html_hidden("h", ctx.qry.head); 690 html_hidden("h", ctx.qry.head);
691 691
692 if (ctx.qry.sha1) 692 if (ctx.qry.sha1)
693 html_hidden("id", ctx.qry.sha1); 693 html_hidden("id", ctx.qry.sha1);
694 if (ctx.qry.sha2) 694 if (ctx.qry.sha2)
695 html_hidden("id2", ctx.qry.sha2); 695 html_hidden("id2", ctx.qry.sha2);
696 if (ctx.qry.showmsg) 696 if (ctx.qry.showmsg)
697 html_hidden("showmsg", "1"); 697 html_hidden("showmsg", "1");
698 698
699 if (incl_search) { 699 if (incl_search) {
700 if (ctx.qry.grep) 700 if (ctx.qry.grep)
701 html_hidden("qt", ctx.qry.grep); 701 html_hidden("qt", ctx.qry.grep);
702 if (ctx.qry.search) 702 if (ctx.qry.search)
703 html_hidden("q", ctx.qry.search); 703 html_hidden("q", ctx.qry.search);
704 } 704 }
705} 705}
706 706
707static const char *hc(struct cgit_context *ctx, const char *page) 707static const char *hc(struct cgit_context *ctx, const char *page)
708{ 708{
709 return strcmp(ctx->qry.page, page) ? NULL : "active"; 709 return strcmp(ctx->qry.page, page) ? NULL : "active";
710} 710}
711 711
712static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path) 712static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path)
713{ 713{
714 char *old_path = ctx->qry.path; 714 char *old_path = ctx->qry.path;
715 char *p = path, *q, *end = path + strlen(path); 715 char *p = path, *q, *end = path + strlen(path);
716 716
717 ctx->qry.path = NULL; 717 ctx->qry.path = NULL;
718 cgit_self_link("root", NULL, NULL, ctx); 718 cgit_self_link("root", NULL, NULL, ctx);
719 ctx->qry.path = p = path; 719 ctx->qry.path = p = path;
720 while (p < end) { 720 while (p < end) {
721 if (!(q = strchr(p, '/'))) 721 if (!(q = strchr(p, '/')))
722 q = end; 722 q = end;
723 *q = '\0'; 723 *q = '\0';
724 html_txt("/"); 724 html_txt("/");
725 cgit_self_link(p, NULL, NULL, ctx); 725 cgit_self_link(p, NULL, NULL, ctx);
726 if (q < end) 726 if (q < end)
727 *q = '/'; 727 *q = '/';
728 p = q + 1; 728 p = q + 1;
729 } 729 }
730 ctx->qry.path = old_path; 730 ctx->qry.path = old_path;
731} 731}
732 732
733static void print_header(struct cgit_context *ctx) 733static void print_header(struct cgit_context *ctx)
734{ 734{
735 html("<table id='header'>\n"); 735 html("<table id='header'>\n");
736 html("<tr>\n"); 736 html("<tr>\n");
737 737
738 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) { 738 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) {
739 html("<td class='logo' rowspan='2'><a href='"); 739 html("<td class='logo' rowspan='2'><a href='");
740 if (ctx->cfg.logo_link) 740 if (ctx->cfg.logo_link)
741 html_attr(ctx->cfg.logo_link); 741 html_attr(ctx->cfg.logo_link);
742 else 742 else
743 html_attr(cgit_rooturl()); 743 html_attr(cgit_rooturl());
744 html("'><img src='"); 744 html("'><img src='");
745 html_attr(ctx->cfg.logo); 745 html_attr(ctx->cfg.logo);
746 html("' alt='cgit logo'/></a></td>\n"); 746 html("' alt='cgit logo'/></a></td>\n");
747 } 747 }
748 748
749 html("<td class='main'>"); 749 html("<td class='main'>");
750 if (ctx->repo) { 750 if (ctx->repo) {
751 cgit_index_link("index", NULL, NULL, NULL, 0); 751 cgit_index_link("index", NULL, NULL, NULL, 0);
752 html(" : "); 752 html(" : ");
753 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 753 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
754 html("</td><td class='form'>"); 754 html("</td><td class='form'>");
755 html("<form method='get' action=''>\n"); 755 html("<form method='get' action=''>\n");
756 cgit_add_hidden_formfields(0, 1, ctx->qry.page); 756 cgit_add_hidden_formfields(0, 1, ctx->qry.page);
757 html("<select name='h' onchange='this.form.submit();'>\n"); 757 html("<select name='h' onchange='this.form.submit();'>\n");
758 for_each_branch_ref(print_branch_option, ctx->qry.head); 758 for_each_branch_ref(print_branch_option, ctx->qry.head);
759 html("</select> "); 759 html("</select> ");
760 html("<input type='submit' name='' value='switch'/>"); 760 html("<input type='submit' name='' value='switch'/>");
761 html("</form>"); 761 html("</form>");
762 } else 762 } else
763 html_txt(ctx->cfg.root_title); 763 html_txt(ctx->cfg.root_title);
764 html("</td></tr>\n"); 764 html("</td></tr>\n");
765 765
766 html("<tr><td class='sub'>"); 766 html("<tr><td class='sub'>");
767 if (ctx->repo) { 767 if (ctx->repo) {
768 html_txt(ctx->repo->desc); 768 html_txt(ctx->repo->desc);
769 html("</td><td class='sub right'>"); 769 html("</td><td class='sub right'>");
770 html_txt(ctx->repo->owner); 770 html_txt(ctx->repo->owner);
771 } else { 771 } else {
772 if (ctx->cfg.root_desc) 772 if (ctx->cfg.root_desc)
773 html_txt(ctx->cfg.root_desc); 773 html_txt(ctx->cfg.root_desc);
774 else if (ctx->cfg.index_info) 774 else if (ctx->cfg.index_info)
775 html_include(ctx->cfg.index_info); 775 html_include(ctx->cfg.index_info);
776 } 776 }
777 html("</td></tr></table>\n"); 777 html("</td></tr></table>\n");
778} 778}
779 779
780void cgit_print_pageheader(struct cgit_context *ctx) 780void cgit_print_pageheader(struct cgit_context *ctx)
781{ 781{
782 html("<div id='cgit'>"); 782 html("<div id='cgit'>");
783 if (!ctx->cfg.noheader) 783 if (!ctx->cfg.noheader)
784 print_header(ctx); 784 print_header(ctx);
785 785
786 html("<table class='tabs'><tr><td>\n"); 786 html("<table class='tabs'><tr><td>\n");
787 if (ctx->repo) { 787 if (ctx->repo) {
788 cgit_summary_link("summary", NULL, hc(ctx, "summary"), 788 cgit_summary_link("summary", NULL, hc(ctx, "summary"),
789 ctx->qry.head); 789 ctx->qry.head);
790 cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head, 790 cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head,
791 ctx->qry.sha1, NULL); 791 ctx->qry.sha1, NULL);
792 cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head, 792 cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head,
793 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg); 793 NULL, ctx->qry.vpath, 0, NULL, NULL,
794 ctx->qry.showmsg);
794 cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head, 795 cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head,
795 ctx->qry.sha1, NULL); 796 ctx->qry.sha1, ctx->qry.vpath);
796 cgit_commit_link("commit", NULL, hc(ctx, "commit"), 797 cgit_commit_link("commit", NULL, hc(ctx, "commit"),
797 ctx->qry.head, ctx->qry.sha1, NULL, 0); 798 ctx->qry.head, ctx->qry.sha1, ctx->qry.vpath, 0);
798 cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head, 799 cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head,
799 ctx->qry.sha1, ctx->qry.sha2, NULL, 0); 800 ctx->qry.sha1, ctx->qry.sha2, ctx->qry.vpath, 0);
800 if (ctx->repo->max_stats) 801 if (ctx->repo->max_stats)
801 cgit_stats_link("stats", NULL, hc(ctx, "stats"), 802 cgit_stats_link("stats", NULL, hc(ctx, "stats"),
802 ctx->qry.head, NULL); 803 ctx->qry.head, ctx->qry.vpath);
803 if (ctx->repo->readme) 804 if (ctx->repo->readme)
804 reporevlink("about", "about", NULL, 805 reporevlink("about", "about", NULL,
805 hc(ctx, "about"), ctx->qry.head, NULL, 806 hc(ctx, "about"), ctx->qry.head, NULL,
806 NULL); 807 NULL);
807 html("</td><td class='form'>"); 808 html("</td><td class='form'>");
808 html("<form class='right' method='get' action='"); 809 html("<form class='right' method='get' action='");
809 if (ctx->cfg.virtual_root) 810 if (ctx->cfg.virtual_root)
810 html_url_path(cgit_fileurl(ctx->qry.repo, "log", 811 html_url_path(cgit_fileurl(ctx->qry.repo, "log",
811 ctx->qry.vpath, NULL)); 812 ctx->qry.vpath, NULL));
812 html("'>\n"); 813 html("'>\n");
813 cgit_add_hidden_formfields(1, 0, "log"); 814 cgit_add_hidden_formfields(1, 0, "log");
814 html("<select name='qt'>\n"); 815 html("<select name='qt'>\n");
815 html_option("grep", "log msg", ctx->qry.grep); 816 html_option("grep", "log msg", ctx->qry.grep);
816 html_option("author", "author", ctx->qry.grep); 817 html_option("author", "author", ctx->qry.grep);
817 html_option("committer", "committer", ctx->qry.grep); 818 html_option("committer", "committer", ctx->qry.grep);
818 html("</select>\n"); 819 html("</select>\n");
819 html("<input class='txt' type='text' size='10' name='q' value='"); 820 html("<input class='txt' type='text' size='10' name='q' value='");
820 html_attr(ctx->qry.search); 821 html_attr(ctx->qry.search);
821 html("'/>\n"); 822 html("'/>\n");
822 html("<input type='submit' value='search'/>\n"); 823 html("<input type='submit' value='search'/>\n");
823 html("</form>\n"); 824 html("</form>\n");
824 } else { 825 } else {
825 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); 826 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0);
826 if (ctx->cfg.root_readme) 827 if (ctx->cfg.root_readme)
827 site_link("about", "about", NULL, hc(ctx, "about"), 828 site_link("about", "about", NULL, hc(ctx, "about"),
828 NULL, 0); 829 NULL, 0);
829 html("</td><td class='form'>"); 830 html("</td><td class='form'>");
830 html("<form method='get' action='"); 831 html("<form method='get' action='");
831 html_attr(cgit_rooturl()); 832 html_attr(cgit_rooturl());
832 html("'>\n"); 833 html("'>\n");
833 html("<input type='text' name='q' size='10' value='"); 834 html("<input type='text' name='q' size='10' value='");
834 html_attr(ctx->qry.search); 835 html_attr(ctx->qry.search);
835 html("'/>\n"); 836 html("'/>\n");
836 html("<input type='submit' value='search'/>\n"); 837 html("<input type='submit' value='search'/>\n");
837 html("</form>"); 838 html("</form>");
838 } 839 }
839 html("</td></tr></table>\n"); 840 html("</td></tr></table>\n");
840 if (ctx->qry.vpath) { 841 if (ctx->qry.vpath) {
841 html("<div class='path'>"); 842 html("<div class='path'>");
842 html("path: "); 843 html("path: ");
843 cgit_print_path_crumbs(ctx, ctx->qry.vpath); 844 cgit_print_path_crumbs(ctx, ctx->qry.vpath);
844 html("</div>"); 845 html("</div>");
845 } 846 }
846 html("<div class='content'>"); 847 html("<div class='content'>");
847} 848}
848 849
849void cgit_print_filemode(unsigned short mode) 850void cgit_print_filemode(unsigned short mode)
850{ 851{
851 if (S_ISDIR(mode)) 852 if (S_ISDIR(mode))
852 html("d"); 853 html("d");
853 else if (S_ISLNK(mode)) 854 else if (S_ISLNK(mode))
854 html("l"); 855 html("l");
855 else if (S_ISGITLINK(mode)) 856 else if (S_ISGITLINK(mode))
856 html("m"); 857 html("m");
857 else 858 else
858 html("-"); 859 html("-");
859 html_fileperm(mode >> 6); 860 html_fileperm(mode >> 6);
860 html_fileperm(mode >> 3); 861 html_fileperm(mode >> 3);
861 html_fileperm(mode); 862 html_fileperm(mode);
862} 863}
863 864
864void cgit_print_snapshot_links(const char *repo, const char *head, 865void cgit_print_snapshot_links(const char *repo, const char *head,
865 const char *hex, int snapshots) 866 const char *hex, int snapshots)
866{ 867{
867 const struct cgit_snapshot_format* f; 868 const struct cgit_snapshot_format* f;
868 char *prefix; 869 char *prefix;
869 char *filename; 870 char *filename;
870 unsigned char sha1[20]; 871 unsigned char sha1[20];
871 872
872 if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && 873 if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 &&
873 (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) 874 (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1]))
874 hex++; 875 hex++;
875 prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex)); 876 prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex));
876 for (f = cgit_snapshot_formats; f->suffix; f++) { 877 for (f = cgit_snapshot_formats; f->suffix; f++) {
877 if (!(snapshots & f->bit)) 878 if (!(snapshots & f->bit))
878 continue; 879 continue;
879 filename = fmt("%s%s", prefix, f->suffix); 880 filename = fmt("%s%s", prefix, f->suffix);
880 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); 881 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
881 html("<br/>"); 882 html("<br/>");
882 } 883 }
883} 884}