git: f02f9006ee - main - support opensearch autocomplete for FreeBSD manual pages
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 08 Jan 2023 07:44:47 UTC
The branch main has been updated by wosch:
URL: https://cgit.FreeBSD.org/doc/commit/?id=f02f9006ee45c59ae46b895ebf2b9446f58a88f2
commit f02f9006ee45c59ae46b895ebf2b9446f58a88f2
Author: Wolfram Schneider <wosch@FreeBSD.org>
AuthorDate: 2023-01-08 07:38:48 +0000
Commit: Wolfram Schneider <wosch@FreeBSD.org>
CommitDate: 2023-01-08 07:38:48 +0000
support opensearch autocomplete for FreeBSD manual pages
---
website/content/en/cgi/man-autocomplete.cgi | 209 ++++++++++++++++++++++++++++
1 file changed, 209 insertions(+)
diff --git a/website/content/en/cgi/man-autocomplete.cgi b/website/content/en/cgi/man-autocomplete.cgi
new file mode 100755
index 0000000000..d05f1b0b23
--- /dev/null
+++ b/website/content/en/cgi/man-autocomplete.cgi
@@ -0,0 +1,209 @@
+#!/usr/local/bin/perl -T
+# Copyright (c) 2009-2023 Wolfram Schneider, https://wolfram.schneider.org
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# man-autocomplete.cgi - autocomplete/suggestion service for FreeBSD manpages
+#
+# expected run time on a modern CPU:
+# FreeBSD Release: 12ms for perl cgi script and 5ms for GNU grep => 17ms
+# FreeBSD Release + Ports: 15ms for perl cgi script and 10ms for GNU grep => 25ms
+#
+
+use lib qw(. ../../lib);
+use MyCgiSimple;
+
+use strict;
+use warnings; # 3% slower
+
+$ENV{PATH} = "/usr/local/bin:/bin:/usr/bin";
+$ENV{'LANG'} = 'C';
+
+my $debug = 2;
+binmode( \*STDIN, ":bytes" );
+binmode( \*STDOUT, ":bytes" );
+binmode( \*STDERR, ":bytes" );
+
+sub suggestion {
+ my %args = @_;
+
+ my $database = $args{'database'};
+ my $icase = $args{'icase'};
+ my $manpath = $args{'manpath'};
+ my $query = $args{'query'};
+ my $limit = $args{'limit'};
+
+ if ( !-e $database ) {
+ warn "$!: $database\n";
+ return;
+ }
+
+ # GNU grep, ripgrep, agrep, BSD grep etc.
+ my @command = ('grep');
+
+ # read more data for prefix match <=> sub-string match
+ my $limit_factor = 8;
+
+ push @command, ( '-m', $limit * $limit_factor );
+ push @command, '-i' if $icase == 1;
+ push @command, ( '--', $query, $database );
+
+ warn join( " ", @command ), "\n" if $debug >= 2;
+ if ( !open( IN, '-|' ) ) {
+ exec @command;
+ die "@command: $! :: $?\n";
+ }
+ binmode( \*IN, ":bytes" );
+
+ my @data = ();
+ while (<IN>) {
+ chomp;
+ s,["\s/],,g;
+
+ # XXX: workaround for Firefox which ignores entries with "::" or "." inside a string
+ # Note: we have to undo this in man.cgi
+ s/::/: :/g;
+ s/\./ \./g;
+ push @data, $_;
+
+ last if scalar(@data) >= $limit * $limit_factor;
+ }
+
+ close IN;
+
+ # a sorted list, but prefix matches first
+ # e.g. 'sort(1)' is before 'alphasort(3) if you searched for 'sor'
+ my $lc_query = $icase ? lc($query) : $query;
+ my @prefix = grep { index( lc($_), $lc_query ) == 0 } @data;
+ my @non_prefix = grep { index( lc($_), $lc_query ) != 0 } @data;
+
+ # prefix first & real limit
+ @data = ( @prefix, @non_prefix );
+ @data = splice( @data, 0, $limit );
+
+ warn "data: ", join( " ", @data ), "\n" if $debug >= 2;
+ return @data;
+}
+
+sub escapeQuote {
+ my $string = shift;
+
+ $string =~ s/"/\\"/g;
+
+ return $string;
+}
+
+# create devbridge autocomplete response JSON object
+sub devbridge_autocomplete {
+ my $query = shift;
+ my $suggestion = shift;
+
+ my @suggestion = @$suggestion;
+
+ print qq/{ query:"/, escapeQuote($query), qq/", suggestions:[/;
+ print '"', join( '","', map { escapeQuote($_) } @suggestion ), '"'
+ if scalar(@suggestion) > 0;
+ print "] }\n";
+
+ warn "query '$query', suggestions: ", join ", ", @suggestion, "\n"
+ if $debug >= 1;
+}
+
+# create opensearch autocomplete response JSON object
+sub opensearch_autocomplete {
+ my $query = shift;
+ my $suggestion = shift;
+
+ my @suggestion = @$suggestion;
+
+ print '["', escapeQuote($query), '", [';
+
+ print qq{"}, join( '","', map { escapeQuote($_) } @suggestion ), qq{"}
+ if scalar(@suggestion) > 0;
+ print "]]\n";
+
+ warn "query '$query', suggestions: ", join ", ", @suggestion, "\n"
+ if $debug >= 1;
+}
+
+######################################################################
+# param alias: query, q: search query
+# manpath, m: release or release + ports
+# icase,i : case sensitive
+# debug, d: debug level
+
+my $max_suggestions = 24;
+my $database_freebsd_release =
+ '/usr/local/www/bsddoc/man/etc/autocomplete/freebsd-release.txt';
+my $database_freebsd_release_ports =
+ '/usr/local/www/bsddoc/man/etc/autocomplete/freebsd-release-ports.txt';
+
+my $q = new MyCgiSimple;
+
+my $test_street = "kurz";
+
+my $query = $q->param('query') // $q->param('q') // $test_street;
+my $manpath = $q->param('manpath') // $q->param('m') // "";
+my $d = $q->param('debug') // $q->param('d') // $debug;
+
+# we always use case insensive search for autocomplete
+my $icase = $q->param('icase') // $q->param('i') // 1;
+
+$query = ( $query =~ /^(.+)$/ ? $1 : "" );
+$manpath = ( $manpath =~ /^([a-z\-]+)$/ ? $1 : "" );
+$icase = ( $icase =~ /^([01])$/ ? $1 : 0 );
+$debug = ( $d =~ /^([0-3])$/ ? $1 : $debug );
+
+# not part of a filename
+$query =~ s,["\s'/]+,,;
+
+my $database =
+ $manpath eq 'freebsd-release-ports'
+ ? $database_freebsd_release_ports
+ : $database_freebsd_release;
+
+my $expire = $debug >= 2 ? '+1s' : '+1h';
+print $q->header(
+ -type => 'text/javascript',
+ -charset => 'utf-8',
+ -expires => $expire,
+);
+
+my @suggestion = ();
+if ( length($query) >= 2 ) {
+ @suggestion = &suggestion(
+ 'database' => $database,
+ 'limit' => $max_suggestions,
+ 'query' => $query,
+ 'icase' => $icase,
+ 'manpath' => $manpath,
+ );
+}
+
+# ns=devbridge, for jQuery devbridge plugin
+# &devbridge_autocomplete( $query, \@suggestion );
+
+# ns=opensearch (Firefox etc.)
+&opensearch_autocomplete( $query, \@suggestion );
+
+#EOF