# HG changeset patch # User Michael Albinus # Date 1217965647 0 # Node ID 6cec2902d7b8313e1e84492264e636a04bd33b76 # Parent b0e0f868bbd785a05889d2e19c22920e22832697 * net/xesam.el (top): Require `wid-edit' always. (xesam-mode-line, xesam-highlight): New deffaces. (xesam-objects): New local variable. (xesam-search-engines): Fix error in field list. (xesam-mode): Use `xesam-mode-line' instead of `font-lock-type-face'. Apply `xesam-mode' to a temp buffer, for proper initiatilzaion (why?). (xesam-highlight-string, xesam-get-hits) (xesam-kill-buffer-function): New defuns. (xesam-refresh-entry): Move code to `xesam-get-hits'. Check result of "hit.fields", it isn't a string only. Wrap an error of the strigi search engine ("xesam:size" is returned as string). Highlight search items. (xesam-refresh-search-buffer): Make logic of counters more simple. Prefetch next hits. (xesam-signal-handler): Use `xesam-mode-line' instead of `font-lock-type-face'. (xesam-new-search): Add `xesam-kill-buffer-function' to `kill-buffer-hook'. diff -r b0e0f868bbd7 -r 6cec2902d7b8 lisp/net/xesam.el --- a/lisp/net/xesam.el Tue Aug 05 18:37:12 2008 +0000 +++ b/lisp/net/xesam.el Tue Aug 05 19:47:27 2008 +0000 @@ -117,9 +117,7 @@ ;; Widgets are used to highlight the search results. (require 'widget) - -(eval-when-compile - (require 'wid-edit)) +(require 'wid-edit) ;; `run-at-time' is used in the signal handler. (require 'timer) @@ -141,10 +139,20 @@ (const :tag "Xesam fulltext query" fulltext-query))) (defcustom xesam-hits-per-page 20 - "Number of search hits to be displayed in the result buffer" + "Number of search hits to be displayed in the result buffer." :group 'xesam :type 'integer) +(defface xesam-mode-line '((t :inherit mode-line-emphasis)) + "Face to highlight mode line." + :group 'xesam) + +(defface xesam-highlight '((t :inherit match)) + "Face to highlight query entries. +It will be overlayed by `widget-documentation-face', so it shall +be different at least in one face property not set in that face." + :group 'xesam) + (defvar xesam-debug nil "Insert debug information in the help echo.") @@ -294,6 +302,7 @@ (defvar xesam-type nil) (defvar xesam-query nil) (defvar xesam-xml-string nil) +(defvar xesam-objects nil) (defvar xesam-current nil) (defvar xesam-count nil) (defvar xesam-to nil) @@ -376,7 +385,7 @@ ((string-equal vendor-id "Beagle") '("xesam:mimeType" "xesam:url")) ((string-equal vendor-id "Strigi") - '("xesam:author" "xesam:cc" "xesam:cc" "xesam:charset" + '("xesam:author" "xesam:cc" "xesam:charset" "xesam:contentType" "xesam:fileExtension" "xesam:id" "xesam:lineCount" "xesam:links" "xesam:mimeType" "xesam:name" "xesam:size" "xesam:sourceModified" "xesam:subject" @@ -420,6 +429,7 @@ (set (make-local-variable 'xesam-type) "") (set (make-local-variable 'xesam-query) "") (set (make-local-variable 'xesam-xml-string) "") + (set (make-local-variable 'xesam-objects) nil) ;; `xesam-current' is the last hit put into the search buffer, (set (make-local-variable 'xesam-current) 0) ;; `xesam-count' is the number of hits reported by the search engine. @@ -439,13 +449,13 @@ (list '(20 (:eval (list "Type: " - (propertize xesam-type 'face 'font-lock-type-face)))) + (propertize xesam-type 'face 'xesam-mode-line)))) '(10 (:eval (list " Query: " (propertize xesam-query - 'face 'font-lock-type-face + 'face 'xesam-mode-line 'help-echo (when xesam-debug xesam-xml-string))))))) (when (not (interactive-p)) @@ -457,28 +467,30 @@ ;; It doesn't make sense to call it interactively. (put 'xesam-mode 'disabled t) +;; The very first buffer created with `xesam-mode' does not have the +;; keymap etc. So we create a dummy buffer. Stupid. +(with-temp-buffer (xesam-mode)) + (defun xesam-buffer-name (service search) "Return the buffer name where to present search results. SERVICE is the D-Bus unique service name of the Xesam search engine. SEARCH is the search identification in that engine. Both must be strings." (format "*%s/%s*" service search)) -(defun xesam-refresh-entry (engine search) +(defun xesam-highlight-string (string) + "Highlight text enclosed by and ." + (while (string-match "\\(.*\\)\\(\\)\\(.*\\)\\(\\)\\(.*\\)" string) + (setq string + (format + "%s%s%s" + (match-string 1 string) + (propertize (match-string 3 string) 'face 'xesam-highlight) + (match-string 5 string)))) + string) + +(defun xesam-refresh-entry (engine entry) "Refreshes one entry in the search buffer." - (let* ((result - (car - (xesam-dbus-call-method - :session (car engine) xesam-path-search - xesam-interface-search "GetHits" search 1))) - (snippet) - ;; We must disable this for the time being; the search - ;; engines don't return usable values so far. -; (caaar -; (dbus-ignore-errors -; (xesam-dbus-call-method -; :session (car engine) xesam-path-search -; xesam-interface-search "GetHitData" -; search (list xesam-current) '("snippet"))))) + (let* ((result (nth (1- xesam-current) xesam-objects)) widget) ;; Create widget. @@ -488,7 +500,10 @@ ;; Take all results. (dolist (field (xesam-get-cached-property engine "hit.fields")) - (when (not (zerop (length (caar result)))) + (when (cond + ((stringp (caar result)) (not (zerop (length (caar result))))) + ((numberp (caar result)) (not (zerop (caar result)))) + ((caar result) t)) (when xesam-debug (widget-put widget :help-echo @@ -503,6 +518,12 @@ (widget-put widget :xesam:url (concat "file://" (widget-get widget :xesam:url)))) + ;; Strigi returns xesam:size as string. We must fix this. + (when (and (widget-member widget :xesam:size) + (stringp (widget-get widget :xesam:size))) + (widget-put + widget :xesam:size (string-to-number (widget-get widget :xesam:url)))) + ;; First line: :tag. (cond ((widget-member widget :xesam:title) @@ -514,6 +535,11 @@ ((widget-member widget :xesam:name) (widget-put widget :tag (widget-get widget :xesam:name)))) + ;; Highlight the search items. + (when (widget-member widget :tag) + (widget-put + widget :tag (xesam-highlight-string (widget-get widget :tag)))) + ;; Last Modified. (when (widget-member widget :xesam:sourceModified) (widget-put @@ -556,11 +582,12 @@ (widget-put widget :doc (widget-get widget :xesam:snippet)))) (when (widget-member widget :doc) - (widget-put widget :help-echo (widget-get widget :doc)) (with-temp-buffer - (insert (widget-get widget :doc)) + (insert + (xesam-highlight-string (widget-get widget :doc))) (fill-region-as-paragraph (point-min) (point-max)) - (widget-put widget :doc (buffer-string)))) + (widget-put widget :doc (buffer-string))) + (widget-put widget :help-echo (widget-get widget :doc))) ;; Format the widget. (widget-put @@ -576,24 +603,38 @@ (force-mode-line-update) (redisplay))) +(defun xesam-get-hits (engine search hits) + "Retrieve hits from ENGINE." + (with-current-buffer (xesam-buffer-name (car engine) search) + (setq xesam-objects + (append xesam-objects + (xesam-dbus-call-method + :session (car engine) xesam-path-search + xesam-interface-search "GetHits" search hits))))) + (defun xesam-refresh-search-buffer (engine search) "Refreshes the buffer, presenting results of SEARCH." (with-current-buffer (xesam-buffer-name (car engine) search) ;; Work only if nobody else is here. - (unless xesam-refreshing + (unless (or xesam-refreshing (>= xesam-current xesam-to)) (setq xesam-refreshing t) (unwind-protect - (let (widget updated) - ;; Add all result widgets. The upper boundary is always - ;; computed, because new hits might have arrived while - ;; running. + (let (widget) + + ;; Retrieve needed hits for visualization. + (while (> (min xesam-to xesam-count) (length xesam-objects)) + (xesam-get-hits + engine search + (min xesam-hits-per-page + (- (min xesam-to xesam-count) (length xesam-objects))))) + + ;; Add all result widgets. (while (< xesam-current (min xesam-to xesam-count)) - (setq updated t - xesam-current (1+ xesam-current)) + (setq xesam-current (1+ xesam-current)) (xesam-refresh-entry engine search)) ;; Add "NEXT" widget. - (when (and updated (> xesam-count xesam-to)) + (when (> xesam-count xesam-to) (goto-char (point-max)) (widget-create 'link @@ -603,7 +644,16 @@ (widget-delete widget) (xesam-refresh-search-buffer xesam-engine xesam-search)) "NEXT") - (widget-beginning-of-line))) + (widget-beginning-of-line)) + + ;; Prefetch next hits. + (when (> (min (+ xesam-hits-per-page xesam-to) xesam-count) + (length xesam-objects)) + (xesam-get-hits + engine search + (min xesam-hits-per-page + (- (min (+ xesam-hits-per-page xesam-to) xesam-count) + (length xesam-objects)))))) ;; Return with save settings. (setq xesam-refreshing nil))))) @@ -632,9 +682,16 @@ ((string-equal member "SearchDone") (setq mode-line-process - (propertize " Done" 'face 'font-lock-type-face)) + (propertize " Done" 'face 'xesam-mode-line)) (force-mode-line-update))))))) +(defun xesam-kill-buffer-function () + "Send the CloseSearch indication." + (when (and (eq major-mode 'xesam-mode) (stringp xesam-search)) + (xesam-dbus-call-method + :session (car xesam-engine) xesam-path-search + xesam-interface-search "CloseSearch" xesam-search))) + (defun xesam-new-search (engine type query) "Create a new search session. ENGINE identifies the search engine. TYPE is the query type, it @@ -675,6 +732,7 @@ xesam-type (symbol-name type) xesam-query query xesam-xml-string xml-string + xesam-objects nil ;; The buffer identification shall indicate the search ;; engine. The `help-echo' property is used for debug ;; information, when applicable. @@ -694,7 +752,8 @@ "vendor.ontology.sources" "vendor.extensions" "vendor.ontologies" "vendor.maxhits") "\n")))) - (force-mode-line-update)) + (add-hook 'kill-buffer-hook 'xesam-kill-buffer-function) + (force-mode-line-update)) ;; Start the search. (xesam-dbus-call-method @@ -748,18 +807,16 @@ ;;; TODO: -;; * Solve error, that xesam-mode does not work the very first time. -;; * Retrieve several results at once. -;; * Retrieve hits for the next page in advance. +;; * Accept input while retrieving prefetched hits. `run-at-time'? ;; * With prefix, let's choose search engine. ;; * Minibuffer completion for user queries. ;; * `revert-buffer-function' implementation. -;; * Close search when search buffer is killed. ;; ;; * Mid term ;; - If available, use ontologies for field selection. ;; - Search engines for Emacs bugs database, wikipedia, google, ;; yahoo, ebay, ... +;; - Construct complex queries via widgets, like in mairix.el. ;; arch-tag: 7fb9fc6c-c2ff-4bc7-bb42-bacb80cce2b2 ;;; xesam.el ends here