changeset 538:7140bc781655

Add multiple keyword search to hgweb -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Add multiple keyword search to hgweb People kept pestering me about this one. Now it's done. If you type a tag/id/rev in the search box, it takes you to that entry in the changelog. If you type some other random keywords, it does a case-insensitive search through the history and returns the most recent N items. It's not super-fast, but it's serviceable. manifest hash: e8fa980dee92cf78c04051d3028da9b07a45f3de -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCxO6JywK+sNU5EO8RArAwAKCq+9qO/OL0mQxa1J7C77Z6AcZoWgCfbiDC AZ5KllldwBtdRRREn7HH6go= =sIy0 -----END PGP SIGNATURE-----
author mpm@selenic.com
date Thu, 30 Jun 2005 23:19:37 -0800
parents 411e05b04ffa
children 44b29b98254a
files mercurial/hgweb.py templates/map templates/search.tmpl templates/searchentry.tmpl
diffstat 4 files changed, 120 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/hgweb.py	Thu Jun 30 21:28:18 2005 -0800
+++ b/mercurial/hgweb.py	Thu Jun 30 23:19:37 2005 -0800
@@ -286,6 +286,68 @@
                      manifest = hex(mf),
                      rev = pos, changesets = count, entries = changelist)
 
+    def search(self, query):
+
+        def changelist():
+            cl = self.repo.changelog
+            count = 0
+            qw = query.lower().split()
+
+            def revgen():
+                for i in range(cl.count() - 1, 0, -100):
+                    l = []
+                    for j in range(max(0, i - 100), i):
+                        n = cl.node(j)
+                        changes = cl.read(n)
+                        l.insert(0, (n, j, changes))
+                    for e in l:
+                        yield e
+
+            for n, i, changes in revgen():
+                miss = 0
+                for q in qw:
+                    if not (q in changes[1].lower() or
+                            q in changes[4].lower() or
+                            q in " ".join(changes[3][:20]).lower()):
+                        miss = 1
+                        break
+                if miss: continue
+
+                count += 1
+                hn = hex(n)
+                p1, p2 = cl.parents(n)
+                t = float(changes[2].split(' ')[0])
+
+                yield self.t(
+                    'searchentry',
+                    parity = count & 1,
+                    author = changes[1],
+                    parent1 = self.parent("changelogparent",
+                                          hex(p1), cl.rev(p1)),
+                    parent2 = self.parent("changelogparent",
+                                          hex(p2), cl.rev(p2)),
+                    p1 = hex(p1), p2 = hex(p2),
+                    p1rev = cl.rev(p1), p2rev = cl.rev(p2),
+                    manifest = hex(changes[0]),
+                    desc = changes[4],
+                    date = t,
+                    files = self.listfilediffs(changes[3], n),
+                    rev = i,
+                    node = hn)
+
+                if count >= self.maxchanges: break
+
+        cl = self.repo.changelog
+        mf = cl.read(cl.tip())[0]
+
+        yield self.t('search',
+                     header = self.header(),
+                     footer = self.footer(),
+                     query = query,
+                     repo = self.reponame,
+                     manifest = hex(mf),
+                     entries = changelist)
+
     def changeset(self, nodeid):
         n = bin(nodeid)
         cl = self.repo.changelog
@@ -586,13 +648,16 @@
         self.t = templater(m, self.filters)
 
         if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
-            hi = self.repo.changelog.count() - 1
+            c = self.repo.changelog.count() - 1
+            hi = c
             if args.has_key('rev'):
                 hi = args['rev'][0]
                 try:
                     hi = self.repo.changelog.rev(self.repo.lookup(hi))
-                except KeyError: pass
-
+                except KeyError:
+                    write(self.search(hi))
+                    return
+                
             write(self.changelog(hi))
 
         elif args['cmd'][0] == 'changeset':
--- a/templates/map	Thu Jun 30 21:28:18 2005 -0800
+++ b/templates/map	Thu Jun 30 23:19:37 2005 -0800
@@ -1,11 +1,13 @@
 header = header.tmpl
 footer = footer.tmpl
+search = search.tmpl
 changelog = changelog.tmpl
 naventry = "<a href="?cmd=changelog;rev=#rev#">#label#</a> "
 filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#">#file#</a> "
 filenodelink = "<a href="?cmd=file;filenode=#filenode#;file=#file#">#file#</a> "
 fileellipses = "..."
 changelogentry = changelogentry.tmpl
+searchentry = searchentry.tmpl
 changeset = changeset.tmpl
 manifest = manifest.tmpl
 manifestdirentry = "<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a>"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/search.tmpl	Thu Jun 30 23:19:37 2005 -0800
@@ -0,0 +1,28 @@
+#header#
+<title>#repo|escape#: searching for #query|escape#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="?cmd=changelog;rev=#rev#">changelog</a>
+<a href="?cmd=tags">tags</a>
+<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
+</div>
+
+<h2>searching for #query|escape#</h2>
+
+<form>
+search:
+<input type="hidden" name="cmd" value="changelog">
+<input name="rev" type="text" width="30" value="#query|escape#">
+</form>
+
+#entries#
+
+<form>
+search:
+<input type="hidden" name="cmd" value="changelog">
+<input name="rev" type="text" width="30">
+</form>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/searchentry.tmpl	Thu Jun 30 23:19:37 2005 -0800
@@ -0,0 +1,22 @@
+<div class="parity#parity#">
+<table width="100%" cellpadding="0" cellspacing="0">
+<tr>
+ <td align="right" width="15%"><b>#date|age# ago:&nbsp;</b></td>
+ <td><b>#desc|firstline|escape#</b></td></tr>
+<tr>
+ <td align="right">changeset #rev#:&nbsp;</td>
+ <td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>
+#parent1#
+#parent2#
+<tr>
+ <td align="right">author:&nbsp;</td>
+ <td>#author|obfuscate#</td></tr>
+<tr>
+ <td align="right">date:&nbsp;</td>
+ <td>#date|date#</td></tr>
+<tr>
+ <td align="right" valign="top"><a href="?cmd=manifest;manifest=#manifest#;path=/">files</a>:&nbsp;</td>
+ <td>#files#</td></tr>
+</table>
+</div>
+