aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuchen Pei <id@ypei.org>2023-07-24 13:58:09 +1000
committerYuchen Pei <id@ypei.org>2023-07-24 13:58:09 +1000
commit7cea566a9616f1300cfc2728acf664ac5bd89bd8 (patch)
treeae65e5d7d160bca38a6783f791a3ac8dbc620aa0
parent78672bd3ccd71e36cd99d57b244213a37a8bf32e (diff)
Add search.
- For mediawiki sites, use API search. - For non-mediawiki sites, use eww. - Now it depends on a new library `generic-search.el'.
-rw-r--r--README.org6
-rw-r--r--wiki-engine.el97
-rw-r--r--wiki-utils.el21
-rw-r--r--wiki.el2
4 files changed, 105 insertions, 21 deletions
diff --git a/README.org b/README.org
index 32e2b50..0635b1d 100644
--- a/README.org
+++ b/README.org
@@ -47,18 +47,20 @@ Currently supported features:
* Install and use
:PROPERTIES:
- :UPDATED: [2023-07-23 Sun 22:25]
+ :UPDATED: [2023-07-24 Mon 13:57]
:END:
Clone, require, M-x:
#+begin_src shell
+git clone https://g.ypei.me/generic-search.el.git
git clone https://g.ypei.me/wiki.el.git
#+end_src
-Assuming you have cloned into =~/.emacs.d/lisp/wiki.el=, then
+Assuming you have cloned into dirs under =~/.emacs.d/lisp=, then
#+begin_src emacs-lisp
+(add-to-list 'load-path "~/.emacs.d/lisp/generic-search.el")
(add-to-list 'load-path "~/.emacs.d/lisp/wiki.el")
(require 'wiki)
#+end_src
diff --git a/wiki-engine.el b/wiki-engine.el
index 242c6d4..b69f7ed 100644
--- a/wiki-engine.el
+++ b/wiki-engine.el
@@ -28,6 +28,7 @@
;;; Code:
(require 'wiki-utils)
(require 'wiki-markup)
+(require 'generic-search)
;; TODO: make this a defcustom
(defvar wiki-default-engine 'mediawiki
@@ -122,6 +123,10 @@ And switch to the corresponding buffer."
('oddmuse (error "API not supported for engine: %s" engine))
(_ (error "Unknown engine: %s" engine))))))
+(defun wiki-engine-compute-fetcher (site-info)
+ "Return :fetcher of SITE-INFO, or default."
+ (or (plist-get site-info :fetcher) 'wiki-engine-simple-fetch))
+
(defun wiki-engine-wiki-url (site title)
"Construct the url to fetch wiki of TITLE from SITE."
(let* ((site-info (alist-get site wiki-sites))
@@ -165,12 +170,6 @@ API-BASE-URL is the base url for the api request."
"%s/api.php?action=query&format=json&titles=%s&prop=revisions&rvprop=content&rvslots=main"
api-base-url title)))
-(defun wiki-engine-mediawiki-api-search (api-base-url query)
- (wiki-url-fetch-json
- (format
- "%s/api.php?action=query&format=json&list=search&srsearch=%s"
- api-base-url query)))
-
(defun wiki-engine-mediawiki-api-fetch (site-id title)
"Fetch TITLE from site with SITE-ID using mediawiki api."
(when (string-empty-p title) (setq title "Main Page"))
@@ -227,24 +226,92 @@ DIR defaults to `default-directory'."
(wiki-mode)
(buffer-name)))))
-(defmacro defun-wiki-fetchers ()
+(defmacro define-wiki-site-commands ()
"Defines all wiki fetcher functions."
(cons 'progn
(mapcar
(lambda (pair)
(pcase-let ((`(,id . ,info) pair))
(let ((engine-fetcher
- (or (plist-get info :fetcher)
- 'wiki-engine-simple-fetch)))
- `(defun ,(wiki-site-fetcher id) (title)
- (interactive ,(format "sFetch title for %s: "
- (wiki-engine-compute-display-name
- id info)))
- (,engine-fetcher ',id title)))))
+ (wiki-engine-compute-fetcher info)))
+ `(progn
+ (defun ,(wiki-site-fetcher id) (title)
+ (interactive ,(format "sFetch title for %s: "
+ (wiki-engine-compute-display-name
+ id info)))
+ (,engine-fetcher ',id title))
+ (defun ,(wiki-site-searcher id) (title)
+ (interactive ,(format "sSearch %s for: "
+ (wiki-engine-compute-display-name
+ id info)))
+ (wiki-engine-simple-search ',id title))))))
(seq-filter #'cdr wiki-sites)
)))
-(defun-wiki-fetchers)
+(define-wiki-site-commands)
+
+;; FIXME: make this work with local wiki, by using say grep-based
+;; search.
+(defun wiki-engine-simple-search (site-id query)
+ "Simple search of QUERY using eww with its default search.
+
+SITE-ID is the id of the site."
+ (let ((site-info (alist-get site-id wiki-sites)))
+ (pcase (wiki-engine-compute-engine site-info)
+ ('mediawiki (wiki-engine-mediawiki-search site-id query))
+ ('local (error "Search not implemented for local engine yet" ))
+ (_
+ (eww (format "%s site:%s" query
+ (plist-get (alist-get site-id wiki-sites) :host)))))))
+
+(defun wiki-engine-mediawiki-api-search (api-base-url query)
+ "Make an API call searching for QUERY.
+
+API-BASE-URL is the base url for the api request."
+ (wiki-url-fetch-json
+ (format
+ "%s/api.php?action=query&format=json&list=search&srsearch=%s"
+ api-base-url query)))
+
+(defun wiki-engine-mediawiki-search-action (site-id)
+ (lambda (info)
+ (interactive)
+ (funcall (wiki-site-fetcher site-id) (alist-get 'title info))))
+
+(defun wiki-engine-mediawiki-search (site-id query)
+ (let ((api-base-url (wiki-engine-compute-api-base-url
+ (alist-get site-id wiki-sites))))
+ (generic-search-open
+ (alist-get 'search
+ (alist-get 'query
+ (wiki-engine-mediawiki-api-search
+ api-base-url query)))
+ (format "%s-query:%s" site-id query)
+ `((formatter . wiki-engine-mediawiki-format-query-result)
+ (default-action . ,(wiki-engine-mediawiki-search-action
+ site-id))
+ (keymap . ,my-wikipedia-button-keymap)))))
+
+(defun wiki-engine-mediawiki-format-query-result (result)
+ (concat
+ (format "%s (%d words)"
+ (alist-get 'title result)
+ (alist-get 'wordcount result))
+ (propertize
+ (format "\n\n%s"
+ (wiki-mediawiki-highlight-snippet-matches
+ (alist-get 'snippet result)))
+ 'face 'default)))
+
+(defun wiki-mediawiki-highlight-snippet-matches (snippet)
+ (with-temp-buffer
+ (insert snippet)
+ (goto-char (point-min))
+ (while (re-search-forward
+ "<span class=\"searchmatch\">\\(.*?\\)</span>" nil t)
+ (replace-match
+ (propertize (match-string 1) 'face 'match)))
+ (buffer-string)))
(defun wiki-open-url (url)
"Open the raw wiki corresponding to the URL of a html wiki page.
diff --git a/wiki-utils.el b/wiki-utils.el
index fd5a0bc..043602b 100644
--- a/wiki-utils.el
+++ b/wiki-utils.el
@@ -110,15 +110,30 @@ Assuming the current buffer to be a `url-retrieve' response buffer."
"Alist of wiki sites.
Each item is in the form of (identifier . properties), where
-identifier is a symbol, and properties is a plist of the site.
-One of the sites is (local), meaning a local filesystem.")
-
+identifier is a symbol, and properties is a plist of site
+properties. One of the sites is (local), meaning a local
+filesystem.
+
+The only mandatory field is `:host'. All other fields, i.e.
+`:engine', `:base-url', `:api-base-url', `display-name' may be
+computed from `wiki-engine-compute-engine',
+`wiki-engine-compute-base-url',
+`wiki-engine-compute-api-base-url', or
+`wiki-engine-compute-display-name'.")
+
+;; FIXME: does it make sense to fallback to wiki-find-file here?
(defun wiki-site-fetcher (site-id)
"Return the fetcher function for wiki site with SITE-ID."
(if site-id
(intern (format "wiki-%s-fetch" site-id))
'wiki-find-file))
+(defun wiki-site-searcher (site-id)
+ "Return the fetcher function for wiki site with SITE-ID."
+ (if site-id
+ (intern (format "wiki-%s-search" site-id))
+ (error "Unknown site id: %s" site-id)))
+
(defvar wiki-client-buffer-name "*wiki api*"
"Name of the buffer recording wiki API calls.")
diff --git a/wiki.el b/wiki.el
index 64a6b9c..cc81d51 100644
--- a/wiki.el
+++ b/wiki.el
@@ -7,7 +7,7 @@
;; Created: 2023
;; Version: 0
;; Keywords: wiki, markup
-;; Package-Requires: ((emacs "28"))
+;; Package-Requires: ((emacs "28") (generic-search "0"))
;; Package-Type: multi
;; Homepage: https://g.ypei.me/wiki.el.git