<?php
// find_expr runs nutrimatic's find-expr, calling $match_fn for each match.
// if $match_fn returns a non-false value, the search will stop
function find_expr($index, $expr, $match_fn, $error_fn) {
$cmd = implode(' ', array_map('escapeshellarg', [
"./nutrimatic/bin/find-expr",
$index,
$expr,
]));
$cmd = "ulimit -t 30; exec $cmd";
$descriptorspec = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$proc = proc_open($cmd, $descriptorspec, $pipes);
list($stdin, $stdout, $stderr) = $pipes;
fclose($stdin);
// assumption: anything written to stderr will fit in the pipe buffer
// nutrimatic only appears to write-then-exit, so It's Probably Fine
while ($line = fscanf($stdout, "%s %[^\n]s\n")) {
list($score, $text) = $line;
if ($match_fn($score, $text)) {
break;
}
}
fclose($stdout);
proc_terminate($proc);
while ($err = fgets($stderr)) {
$error_fn($err);
}
fclose($stderr);
$retval = proc_close($proc);
return $retval;
}
function index_name($file) {
return preg_replace('/\.index$/', '', $file);
}
$index_files = glob("*.index");
$default_index = "enwiki-latest.index";
$selected_index = $default_index;
foreach ($index_files as $file) {
if (index_name($file) == $_GET['idx']) {
$selected_index = $file;
}
}
$q = $_GET['q'] ?: "";
$more = 0;
$autofocus = 'autofocus ';
if ($_GET['more']) {
$more = (int)($_GET['more']);
$autofocus = '';
}
$max_more = 10;
?>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0">
<title><?php
if ($q) {
echo htmlspecialchars($q);
echo ' » ';
}
if ($selected_index != $default_index) {
echo htmlspecialchars(index_name($selected_index));
echo ' ';
}
echo "nut";
?></title>
<style>
li:target {
border-top: 1px solid red;
}
</style>
</head>
<body>
<form>
<fieldset>
<legend><a href=".">nut</a></legend>
<select name="idx">
<?php
foreach ($index_files as $file) {
$name = index_name($file);
$attrs = '';
if ($file == $selected_index) {
$attrs .= ' selected';
}
?>
<option<?= $attrs ?> value="<?=htmlspecialchars($name)?>"><?=htmlspecialchars($name)?></option>
<?php
}
?>
</select>
<input type="text" name="q" value="<?=htmlspecialchars($q)?>" <?=$autofocus?>/>
<input type="submit" />
</fieldset>
</form>
<?php
if ($more > $max_more) {
echo "no";
} else if ($q) {
?>
<ol>
<?php
$depth = 0;
$count = 0;
$anchor = '';
find_expr($selected_index, $q, function($score, $text) use (&$depth, &$count, &$anchor, $more, $max_more) {
if ($score == '#') {
$depth++;
if ($depth == $more) {
$anchor .= ' id="more"';
}
return $depth > $more && ($count > 0 || $depth > $max_more);
}
$count++;
?>
<li class="match" value="<?=(int)(float)($score)?>"<?=$anchor?>><?=htmlspecialchars($text)?></li>
<?php
$anchor = '';
}, function($err) {
?>
<li class="error" value="0"><?=htmlspecialchars($err)?></li>
<?php
});
?>
</ol>
<?php
$first_more = TRUE;
while ($depth <= $max_more) {
?>
<a<?=$anchor?> class="more" href="?<?=http_build_query([
'idx' => index_name($selected_index),
'q' => $q,
'more' => $depth,
])?><?= $first_more ? "#more" : "" ?>"><?= $first_more ? "MORE" : $depth ?></a>
<?php
$anchor = "";
$depth++;
$first_more = FALSE;
}
} else {
?>
<p>Hi I'm a <a href="//nutrimatic.org/">Nutrimatic</a></p>
<p><a href="https://git.doof.net/nut/">Source</a></p>
<?php
}
?>
</body>
</html>