Initial search implementation
Initial search implementation

file:a/gitphp.css -> file:b/gitphp.css
--- a/gitphp.css
+++ b/gitphp.css
@@ -45,7 +45,7 @@
 div.pre { font-family:monospace; font-size:12px; white-space:pre; }
 div.diff_info { font-family:monospace; color:#000099; background-color:#edece6; font-style:italic; }
 div.index_include { border:solid #d9d8d1; border-width:0px 0px 1px; padding:12px 8px; }
-div.search { margin:4px 8px; position:absolute; top:56px; right:12px }
+div.search { font-size: 12px; font-weight: normal; margin:4px 8px; position: absolute; top:56px; right:12px }
 a.linenr { color:#999999; text-decoration:none }
 a.rss_logo {
 	float:right; padding:3px 0px; width:35px; line-height:10px;
@@ -96,4 +96,11 @@
 span.latenight {
 	color: #cc0000;
 }
+span.searchmatch {
+	color: #e00000;
+}
+div.error {
+	padding: 10px;
+	color: #ff0000;
+}
 

--- /dev/null
+++ b/include/display.git_search.php
@@ -1,1 +1,127 @@
+<?php
+/*
+ *  display.git_search.php
+ *  gitphp: A PHP git repository browser
+ *  Component: Display - search
+ *
+ *  Copyright (C) 2009 Christopher Han <xiphux@gmail.com>
+ */
 
+include_once('gitutil.git_read_commit.php');
+include_once('gitutil.git_rev_list.php');
+
+function git_search($projectroot, $project, $hash, $search, $searchtype, $page = 0)
+{
+	global $tpl;
+
+	if (!isset($search) || (strlen($search) < 2)) {
+		$tpl->clear_all_assign();
+		$tpl->assign("error",TRUE);
+		$tpl->assign("message","You must enter search text of at least 2 characters");
+		$tpl->display("message.tpl");
+		return;
+	}
+	if (!isset($hash)) {
+		//$hash = git_read_head($projectroot . $project);
+		$hash = "HEAD";
+	}
+
+	$co = git_read_commit($projectroot . $project, $hash);
+
+	$revlist = explode("\n",trim(git_rev_list($projectroot . $project, $hash, 101, ($page * 100), FALSE, FALSE, $searchtype, $search)));
+
+	if (count($revlist) < 1 || (strlen($revlist[0]) < 1)) {
+		$tpl->clear_all_assign();
+		$tpl->assign("message","No matches for '" . $search . "'.");
+		$tpl->display("message.tpl");
+		return;
+	}
+
+	$tpl->clear_all_assign();
+	$tpl->assign("project",$project);
+	$tpl->assign("hash",$hash);
+	$tpl->assign("treehash",$co['tree']);
+	$tpl->display("search_nav.tpl");
+
+	$tpl->assign("search",$search);
+	$tpl->assign("searchtype",$searchtype);
+	if ($page > 0) {
+		$tpl->assign("firstlink",TRUE);
+		$tpl->assign("prevlink",TRUE);
+		if ($page > 1)
+			$tpl->assign("prevpage",$page-1);
+	}
+	if (count($revlist) > 100) {
+		$tpl->assign("nextlink",TRUE);
+		$tpl->assign("nextpage",$page+1);
+	}
+	$tpl->display("search_pagenav.tpl");
+
+	$tpl->assign("title",$co['title']);
+	$tpl->display("search_header.tpl");
+
+	$alternate = FALSE;
+	for ($i = 0; $i <= 100; $i++) {
+		$tpl->clear_all_assign();
+		$commit = $revlist[$i];
+		if (strlen(trim($commit)) > 0) {
+			$co2 = git_read_commit($projectroot . $project, $commit);
+			if ($alternate)
+				$tpl->assign("class","dark");
+			else
+				$tpl->assign("class","light");
+			$alternate = !$alternate;
+			$tpl->assign("project",$project);
+			$tpl->assign("commit",$commit);
+			$tpl->assign("agestringage",$co2['age_string_age']);
+			$tpl->assign("agestringdate",$co2['age_string_date']);
+			$tpl->assign("authorname",$co2['author_name']);
+			$tpl->assign("title_short",$co2['title_short']);
+			if (strlen($co2['title_short']) < strlen($co2['title']))
+				$tpl->assign("title",$co2['title']);
+			$tpl->assign("committree",$co2['tree']);
+			$matches = array();
+			foreach ($co2['comment'] as $comline) {
+				if (eregi("(.*)(" . quotemeta($search) . ")(.*)",$comline,$regs)) {
+					$maxlen = 50;
+					$linelen = strlen($regs[0]);
+					if ($linelen > $maxlen) {
+						$matchlen = strlen($regs[2]);
+						$remain = floor(($maxlen - $matchlen) / 2);
+						$leftlen = strlen($regs[1]);
+						$rightlen = strlen($regs[3]);
+						if ($leftlen > $remain) {
+							$leftremain = $remain;
+							if ($rightlen < $remain)
+								$leftremain += ($remain - $rightlen);
+							$regs[1] = "..." . substr($regs[1], ($leftlen - ($leftremain - 3)));
+						}
+						if ($rightlen > $remain) {
+							$rightremain = $remain;
+							if ($leftlen < $remain)
+								$rightremain += ($remain - $leftlen);
+							$regs[3] = substr($regs[3],0,$rightremain-3) . "...";
+						}
+					}
+					$matches[] = $regs[1] . "<span class=\"searchmatch\">" . $regs[2] . "</span>" . $regs[3];
+				}
+			}
+			$tpl->assign("matches",$matches);
+			$tpl->display("search_item.tpl");
+		}
+	}
+
+	$tpl->clear_all_assign();
+	$tpl->assign("project",$project);
+	$tpl->assign("hash",$hash);
+	$tpl->assign("search",$search);
+	$tpl->assign("searchtype",$searchtype);
+	if (count($revlist) > 100) {
+		$tpl->assign("nextlink",TRUE);
+		$tpl->assign("nextpage",$page+1);
+	}
+	$tpl->display("search_footer.tpl");
+}
+
+?>
+

--- a/include/gitutil.git_read_commit.php
+++ b/include/gitutil.git_read_commit.php
@@ -12,7 +12,7 @@
 
 function git_read_commit($proj,$head)
 {
-	$revlist = git_rev_list($proj,$head,1,TRUE,TRUE);
+	$revlist = git_rev_list($proj,$head,1,NULL,TRUE,TRUE);
 	$lines = explode("\n",$revlist);
 	if (!($lines[0]) || !ereg("^[0-9a-fA-F]{40}",$lines[0]))
 		return null;

--- a/include/gitutil.git_read_revlist.php
+++ b/include/gitutil.git_read_revlist.php
@@ -9,9 +9,9 @@
 
  include_once('gitutil.git_rev_list.php');
 
-function git_read_revlist($proj,$head,$count)
+function git_read_revlist($proj,$head,$count,$skip = NULL)
 {
-	$revs = trim(git_rev_list($proj,$head,$count));
+	$revs = trim(git_rev_list($proj,$head,$count, $skip));
 	$revlist = explode("\n",$revs);
 	return $revlist;
 }

--- a/include/gitutil.git_rev_list.php
+++ b/include/gitutil.git_rev_list.php
@@ -10,7 +10,7 @@
  include_once('defs.commands.php');
  include_once('gitutil.git_exec.php');
 
-function git_rev_list($proj,$head,$count = NULL,$header = FALSE,$parents = FALSE)
+function git_rev_list($proj,$head,$count = NULL,$skip = NULL,$header = FALSE,$parents = FALSE,$greptype = NULL, $search = NULL)
 {
 	$cmd = GIT_REV_LIST . " ";
 	if ($header)
@@ -18,7 +18,18 @@
 	if ($parents)
 		$cmd .= "--parents ";
 	if ($count)
-		$cmd .= "--max-count=" . $count;
+		$cmd .= "--max-count=" . $count . " ";
+	if ($skip)
+		$cmd .= "--skip=" . $skip . " ";
+	if ($greptype && $search) {
+		if ($greptype == "commit")
+			$cmd .= "--grep=" . $search . " ";
+		else if ($greptype == "author")
+			$cmd .= "--author=" . $search . " ";
+		else if ($greptype == "committer")
+			$cmd .= "--committer=" . $search . " ";
+		$cmd .= "--regexp-ignore-case ";
+	}
 	return git_exec($proj, $cmd . " " . $head);
 }
 

file:a/index.php -> file:b/index.php
--- a/index.php
+++ b/index.php
@@ -118,6 +118,10 @@
 					include_once('include/display.git_history.php');
 					git_history($gitphp_conf['projectroot'],$_GET['p'], (isset($_GET['h']) ? $_GET['h'] : NULL),$_GET['f']);
 					break;
+				case "search":
+					include_once('include/display.git_search.php');
+					git_search($gitphp_conf['projectroot'],$_GET['p'],(isset($_GET['h']) ? $_GET['h'] : NULL),(isset($_GET['s']) ? $_GET['s'] : NULL),(isset($_GET['st']) ? $_GET['st'] : "commit"),(isset($_GET['pg']) ? $_GET['pg'] : 0));
+					break;
 				default:
 					echo "Unknown action";
 					break;
@@ -147,6 +151,16 @@
 		}
 	 }
 	 $tpl->assign("title",$title);
+	 if (isset($_GET['st']))
+	 	$tpl->assign("searchtype",$_GET['st']);
+	else
+		$tpl->assign("searchtype","commit");
+	if (isset($_GET['s']))
+		$tpl->assign("search",$_GET['s']);
+	if (isset($_GET['hb']))
+		$tpl->assign("hash",$_GET['hb']);
+	else if (isset($_GET['h']))
+		$tpl->assign("hash",$_GET['h']);
 	 $tpl->display("header.tpl");
  }
 

--- a/templates/header.tpl
+++ b/templates/header.tpl
@@ -30,6 +30,18 @@
   {if $action}
     / {$action}
   {/if}
+<form method="get" action="index.php" enctype="application/x-www-form-urlencoded">
+<div class="search">
+<input type="hidden" name="p" value="{$project}" />
+<input type="hidden" name="a" value="search" />
+<input type="hidden" name="h" value="{if $hash}{$hash}{else}HEAD{/if}" />
+<select name="st">
+<option {if $searchtype == 'commit'}selected="selected"{/if} value="commit">commit</option>
+<option {if $searchtype == 'author'}selected="selected"{/if} value="author">author</option>
+<option {if $searchtype == 'committer'}selected="selected"{/if} value="committer">committer</option>
+</select> search: <input type="text" name="s" {if $search}value="{$search}"{/if} />
+</div>
+</form>
 {/if}
 </div>
 

--- a/templates/log_nav.tpl
+++ b/templates/log_nav.tpl
@@ -6,6 +6,6 @@
  *  Copyright (C) 2006 Christopher Han <xiphux@gmail.com>
  *}
  <div class="page_nav">
- <a href="{$SCRIPT_NAME}?p={$project}&a=summary">summary</a> | <a href="{$SCIRPT_NAME}?p={$project}&a=shortlog&h={$hash}">shortlog</a> | log | <a href="{$SCRIPT_NAME}?p={$project}&a=commit&h={$hash}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=commitdiff&h={$hash}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=tree&h={$hash}&hb={$hash}">tree</a>
+ <a href="{$SCRIPT_NAME}?p={$project}&a=summary">summary</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=shortlog&h={$hash}">shortlog</a> | log | <a href="{$SCRIPT_NAME}?p={$project}&a=commit&h={$hash}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=commitdiff&h={$hash}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=tree&h={$hash}&hb={$hash}">tree</a>
  <br />
 

--- a/templates/log_pagenav.tpl
+++ b/templates/log_pagenav.tpl
@@ -1,5 +1,5 @@
 {*
- *  log_page.tpl
+ *  log_pagenav.tpl
  *  gitphp: A PHP git repository browser
  *  Component: Log view page nav template
  *

--- /dev/null
+++ b/templates/message.tpl
@@ -1,1 +1,9 @@
+{*
+ *  error.tpl
+ *  gitphp: A PHP git repository browser
+ *  Component: Error message template
+ *
+ *  Copyright (C) 2009 Christopher Han <xiphux@gmail.com>
+ *}
+<div {if $error}class="error"{/if}>{$message}</div>
 

--- /dev/null
+++ b/templates/search_footer.tpl
@@ -1,1 +1,12 @@
+{*
+ *  search_footer.tpl
+ *  gitphp: A PHP git repository browser
+ *  Component: Search view footer template
+ *
+ *  Copyright (C) 2009 Christopher Han <xiphux@gmail.com>
+ *}
+ {if $nextlink}
+ <tr><td><a href="{$SCRIPT_NAME}?p={$project}&a=search&h={$hash}&s={$search}&st={$searchtype}&pg={$nextpage}" title="Alt-n">next</a></td></tr>
+ {/if}
+ </table>
 

--- /dev/null
+++ b/templates/search_header.tpl
@@ -1,1 +1,12 @@
+{*
+ *  search_header.tpl
+ *  gitphp: A PHP git repository browser
+ *  Component: Search header template
+ *
+ *  Copyright (C) 2009 Christopher Han <xiphux@gmail.com>
+ *}
+<div>
+<a href="{$SCRIPT_NAME}?p={$project}&a=commit&h={$hash}" class="title">{$title}</a>
+</div>
+<table cellspacing="0">
 

--- /dev/null
+++ b/templates/search_item.tpl
@@ -1,1 +1,19 @@
+{*
+ *  search_item.tpl
+ *  gitphp: A PHP git repository browser
+ *  Component: Search view item template
+ *
+ *  Copyright (C) 2009 Christopher Han <xiphux@gmail.com>
+ *}
+<tr class="{$class}">
+<td title="{$agestringage}"><i>{$agestringdate}</i></td>
+<td><i>{$authorname}</i></td>
+<td><a href="{$SCRIPT_NAME}?p={$project}&a=commit&h={$commit}" class="list" {if $title}title="{$title}"{/if}><b>{$title_short}</b>
+{foreach from=$matches item=line name=match}
+{if $smarty.foreach.match.first}<br />{/if}{$line}<br />
+{/foreach}
+</td>
+<td class="link"><a href="{$SCRIPT_NAME}?p={$project}&a=commit&h={$commit}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=commitdiff&h={$commit}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=tree&h={$committree}&hb={$commit}">tree</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=snapshot&h={$commit}">snapshot</a>
+</td>
+</tr>
 

--- /dev/null
+++ b/templates/search_nav.tpl
@@ -1,1 +1,11 @@
+{*
+ *  search_nav.tpl
+ *  gitphp: A PHP git repository browser
+ *  Component: Search view nav template
+ *
+ *  Copyright (C) 2009 Christopher Han <xiphux@gmail.com>
+ *}
+<div class="page_nav">
+<a href="{$SCRIPT_NAME}?p={$project}&a=summary">summary</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=shortlog&h={$hash}">shortlog</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=log&h={$hash}">log</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=commit&h={$hash}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=commitdiff&h={$hash}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project}&a=tree&h={$treehash}&hb={$hash}">tree</a>
+<br />
 

--- /dev/null
+++ b/templates/search_pagenav.tpl
@@ -1,1 +1,11 @@
+{*
+ *  search_pagenav.tpl
+ *  gitphp: A PHP git repository browser
+ *  Component: Log view page nav template
+ *
+ *  Copyright (C) 2006 Christopher Han <xiphux@gmail.com>
+ *}
+ {if $firstlink}<a href="{$SCRIPT_NAME}?p={$project}&a=search&h={$hash}&s={$search}&st={$searchtype}">{/if}first{if $firstlink}</a>{/if} &sdot; {if $prevlink}<a href="{$SCRIPT_NAME}?p={$project}&a=search&h={$hash}&s={$search}&st={$searchtype}{if $prevpage}&pg={$prevpage}{/if}" accesskey="p" title="Alt-p">{/if}prev{if $prevlink}</a>{/if} &sdot; {if $nextlink}<a href="{$SCRIPT_NAME}?p={$project}&a=search&h={$hash}&s={$search}&st={$searchtype}&pg={$nextpage}" accesskey="n" title="Alt-n">{/if}next{if $nextlink}</a>{/if}
+ <br />
+ </div>
 

comments