diff options
| author | Michael Albinus | 2008-08-05 19:49:17 +0000 |
|---|---|---|
| committer | Michael Albinus | 2008-08-05 19:49:17 +0000 |
| commit | 4edefb46c017a81a88d698be36012573aac96efd (patch) | |
| tree | e49c0d17ad1083e43465b38b7dd48f7051374d60 | |
| parent | 7be2b0943a334fcc902c1dbf177c01f4010b2575 (diff) | |
| download | emacs-4edefb46c017a81a88d698be36012573aac96efd.tar.gz emacs-4edefb46c017a81a88d698be36012573aac96efd.zip | |
* 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'.
| -rw-r--r-- | lisp/ChangeLog | 22 | ||||
| -rw-r--r-- | lisp/net/xesam.el | 139 |
2 files changed, 120 insertions, 41 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 9b0e652701e..3af0ce170bd 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,25 @@ | |||
| 1 | 2008-08-05 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | * net/xesam.el (top): Require `wid-edit' always. | ||
| 4 | (xesam-mode-line, xesam-highlight): New deffaces. | ||
| 5 | (xesam-objects): New local variable. | ||
| 6 | (xesam-search-engines): Fix error in field list. | ||
| 7 | (xesam-mode): Use `xesam-mode-line' instead of | ||
| 8 | `font-lock-type-face'. Apply `xesam-mode' to a temp buffer, for | ||
| 9 | proper initiatilzaion (why?). | ||
| 10 | (xesam-highlight-string, xesam-get-hits) | ||
| 11 | (xesam-kill-buffer-function): New defuns. | ||
| 12 | (xesam-refresh-entry): Move code to `xesam-get-hits'. Check | ||
| 13 | result of "hit.fields", it isn't a string only. Wrap an error of | ||
| 14 | the strigi search engine ("xesam:size" is returned as string). | ||
| 15 | Highlight search items. | ||
| 16 | (xesam-refresh-search-buffer): Make logic of counters more simple. | ||
| 17 | Prefetch next hits. | ||
| 18 | (xesam-signal-handler): Use `xesam-mode-line' instead of | ||
| 19 | `font-lock-type-face'. | ||
| 20 | (xesam-new-search): Add `xesam-kill-buffer-function' to | ||
| 21 | `kill-buffer-hook'. | ||
| 22 | |||
| 1 | 2008-08-05 Teodor Zlatanov <tzz@lifelogs.com> | 23 | 2008-08-05 Teodor Zlatanov <tzz@lifelogs.com> |
| 2 | 24 | ||
| 3 | * add-log.el (change-log-next-error, change-log-mode): Add support | 25 | * add-log.el (change-log-next-error, change-log-mode): Add support |
diff --git a/lisp/net/xesam.el b/lisp/net/xesam.el index c864bc2cb83..36a6b49f6e7 100644 --- a/lisp/net/xesam.el +++ b/lisp/net/xesam.el | |||
| @@ -117,9 +117,7 @@ | |||
| 117 | 117 | ||
| 118 | ;; Widgets are used to highlight the search results. | 118 | ;; Widgets are used to highlight the search results. |
| 119 | (require 'widget) | 119 | (require 'widget) |
| 120 | 120 | (require 'wid-edit) | |
| 121 | (eval-when-compile | ||
| 122 | (require 'wid-edit)) | ||
| 123 | 121 | ||
| 124 | ;; `run-at-time' is used in the signal handler. | 122 | ;; `run-at-time' is used in the signal handler. |
| 125 | (require 'timer) | 123 | (require 'timer) |
| @@ -141,10 +139,20 @@ | |||
| 141 | (const :tag "Xesam fulltext query" fulltext-query))) | 139 | (const :tag "Xesam fulltext query" fulltext-query))) |
| 142 | 140 | ||
| 143 | (defcustom xesam-hits-per-page 20 | 141 | (defcustom xesam-hits-per-page 20 |
| 144 | "Number of search hits to be displayed in the result buffer" | 142 | "Number of search hits to be displayed in the result buffer." |
| 145 | :group 'xesam | 143 | :group 'xesam |
| 146 | :type 'integer) | 144 | :type 'integer) |
| 147 | 145 | ||
| 146 | (defface xesam-mode-line '((t :inherit mode-line-emphasis)) | ||
| 147 | "Face to highlight mode line." | ||
| 148 | :group 'xesam) | ||
| 149 | |||
| 150 | (defface xesam-highlight '((t :inherit match)) | ||
| 151 | "Face to highlight query entries. | ||
| 152 | It will be overlayed by `widget-documentation-face', so it shall | ||
| 153 | be different at least in one face property not set in that face." | ||
| 154 | :group 'xesam) | ||
| 155 | |||
| 148 | (defvar xesam-debug nil | 156 | (defvar xesam-debug nil |
| 149 | "Insert debug information in the help echo.") | 157 | "Insert debug information in the help echo.") |
| 150 | 158 | ||
| @@ -294,6 +302,7 @@ from VALUE, depending on what the search engine accepts." | |||
| 294 | (defvar xesam-type nil) | 302 | (defvar xesam-type nil) |
| 295 | (defvar xesam-query nil) | 303 | (defvar xesam-query nil) |
| 296 | (defvar xesam-xml-string nil) | 304 | (defvar xesam-xml-string nil) |
| 305 | (defvar xesam-objects nil) | ||
| 297 | (defvar xesam-current nil) | 306 | (defvar xesam-current nil) |
| 298 | (defvar xesam-count nil) | 307 | (defvar xesam-count nil) |
| 299 | (defvar xesam-to nil) | 308 | (defvar xesam-to nil) |
| @@ -376,7 +385,7 @@ If there is no registered search engine at all, the function returns `nil'." | |||
| 376 | ((string-equal vendor-id "Beagle") | 385 | ((string-equal vendor-id "Beagle") |
| 377 | '("xesam:mimeType" "xesam:url")) | 386 | '("xesam:mimeType" "xesam:url")) |
| 378 | ((string-equal vendor-id "Strigi") | 387 | ((string-equal vendor-id "Strigi") |
| 379 | '("xesam:author" "xesam:cc" "xesam:cc" "xesam:charset" | 388 | '("xesam:author" "xesam:cc" "xesam:charset" |
| 380 | "xesam:contentType" "xesam:fileExtension" "xesam:id" | 389 | "xesam:contentType" "xesam:fileExtension" "xesam:id" |
| 381 | "xesam:lineCount" "xesam:links" "xesam:mimeType" "xesam:name" | 390 | "xesam:lineCount" "xesam:links" "xesam:mimeType" "xesam:name" |
| 382 | "xesam:size" "xesam:sourceModified" "xesam:subject" | 391 | "xesam:size" "xesam:sourceModified" "xesam:subject" |
| @@ -420,6 +429,7 @@ Turning on Xesam mode runs the normal hook `xesam-mode-hook'." | |||
| 420 | (set (make-local-variable 'xesam-type) "") | 429 | (set (make-local-variable 'xesam-type) "") |
| 421 | (set (make-local-variable 'xesam-query) "") | 430 | (set (make-local-variable 'xesam-query) "") |
| 422 | (set (make-local-variable 'xesam-xml-string) "") | 431 | (set (make-local-variable 'xesam-xml-string) "") |
| 432 | (set (make-local-variable 'xesam-objects) nil) | ||
| 423 | ;; `xesam-current' is the last hit put into the search buffer, | 433 | ;; `xesam-current' is the last hit put into the search buffer, |
| 424 | (set (make-local-variable 'xesam-current) 0) | 434 | (set (make-local-variable 'xesam-current) 0) |
| 425 | ;; `xesam-count' is the number of hits reported by the search engine. | 435 | ;; `xesam-count' is the number of hits reported by the search engine. |
| @@ -439,13 +449,13 @@ Turning on Xesam mode runs the normal hook `xesam-mode-hook'." | |||
| 439 | (list '(20 | 449 | (list '(20 |
| 440 | (:eval | 450 | (:eval |
| 441 | (list "Type: " | 451 | (list "Type: " |
| 442 | (propertize xesam-type 'face 'font-lock-type-face)))) | 452 | (propertize xesam-type 'face 'xesam-mode-line)))) |
| 443 | '(10 | 453 | '(10 |
| 444 | (:eval | 454 | (:eval |
| 445 | (list " Query: " | 455 | (list " Query: " |
| 446 | (propertize | 456 | (propertize |
| 447 | xesam-query | 457 | xesam-query |
| 448 | 'face 'font-lock-type-face | 458 | 'face 'xesam-mode-line |
| 449 | 'help-echo (when xesam-debug xesam-xml-string))))))) | 459 | 'help-echo (when xesam-debug xesam-xml-string))))))) |
| 450 | 460 | ||
| 451 | (when (not (interactive-p)) | 461 | (when (not (interactive-p)) |
| @@ -457,28 +467,30 @@ Turning on Xesam mode runs the normal hook `xesam-mode-hook'." | |||
| 457 | ;; It doesn't make sense to call it interactively. | 467 | ;; It doesn't make sense to call it interactively. |
| 458 | (put 'xesam-mode 'disabled t) | 468 | (put 'xesam-mode 'disabled t) |
| 459 | 469 | ||
| 470 | ;; The very first buffer created with `xesam-mode' does not have the | ||
| 471 | ;; keymap etc. So we create a dummy buffer. Stupid. | ||
| 472 | (with-temp-buffer (xesam-mode)) | ||
| 473 | |||
| 460 | (defun xesam-buffer-name (service search) | 474 | (defun xesam-buffer-name (service search) |
| 461 | "Return the buffer name where to present search results. | 475 | "Return the buffer name where to present search results. |
| 462 | SERVICE is the D-Bus unique service name of the Xesam search engine. | 476 | SERVICE is the D-Bus unique service name of the Xesam search engine. |
| 463 | SEARCH is the search identification in that engine. Both must be strings." | 477 | SEARCH is the search identification in that engine. Both must be strings." |
| 464 | (format "*%s/%s*" service search)) | 478 | (format "*%s/%s*" service search)) |
| 465 | 479 | ||
| 466 | (defun xesam-refresh-entry (engine search) | 480 | (defun xesam-highlight-string (string) |
| 481 | "Highlight text enclosed by <b> and </b>." | ||
| 482 | (while (string-match "\\(.*\\)\\(<b>\\)\\(.*\\)\\(</b>\\)\\(.*\\)" string) | ||
| 483 | (setq string | ||
| 484 | (format | ||
| 485 | "%s%s%s" | ||
| 486 | (match-string 1 string) | ||
| 487 | (propertize (match-string 3 string) 'face 'xesam-highlight) | ||
| 488 | (match-string 5 string)))) | ||
| 489 | string) | ||
| 490 | |||
| 491 | (defun xesam-refresh-entry (engine entry) | ||
| 467 | "Refreshes one entry in the search buffer." | 492 | "Refreshes one entry in the search buffer." |
| 468 | (let* ((result | 493 | (let* ((result (nth (1- xesam-current) xesam-objects)) |
| 469 | (car | ||
| 470 | (xesam-dbus-call-method | ||
| 471 | :session (car engine) xesam-path-search | ||
| 472 | xesam-interface-search "GetHits" search 1))) | ||
| 473 | (snippet) | ||
| 474 | ;; We must disable this for the time being; the search | ||
| 475 | ;; engines don't return usable values so far. | ||
| 476 | ; (caaar | ||
| 477 | ; (dbus-ignore-errors | ||
| 478 | ; (xesam-dbus-call-method | ||
| 479 | ; :session (car engine) xesam-path-search | ||
| 480 | ; xesam-interface-search "GetHitData" | ||
| 481 | ; search (list xesam-current) '("snippet"))))) | ||
| 482 | widget) | 494 | widget) |
| 483 | 495 | ||
| 484 | ;; Create widget. | 496 | ;; Create widget. |
| @@ -488,7 +500,10 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 488 | 500 | ||
| 489 | ;; Take all results. | 501 | ;; Take all results. |
| 490 | (dolist (field (xesam-get-cached-property engine "hit.fields")) | 502 | (dolist (field (xesam-get-cached-property engine "hit.fields")) |
| 491 | (when (not (zerop (length (caar result)))) | 503 | (when (cond |
| 504 | ((stringp (caar result)) (not (zerop (length (caar result))))) | ||
| 505 | ((numberp (caar result)) (not (zerop (caar result)))) | ||
| 506 | ((caar result) t)) | ||
| 492 | (when xesam-debug | 507 | (when xesam-debug |
| 493 | (widget-put | 508 | (widget-put |
| 494 | widget :help-echo | 509 | widget :help-echo |
| @@ -503,6 +518,12 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 503 | (widget-put | 518 | (widget-put |
| 504 | widget :xesam:url (concat "file://" (widget-get widget :xesam:url)))) | 519 | widget :xesam:url (concat "file://" (widget-get widget :xesam:url)))) |
| 505 | 520 | ||
| 521 | ;; Strigi returns xesam:size as string. We must fix this. | ||
| 522 | (when (and (widget-member widget :xesam:size) | ||
| 523 | (stringp (widget-get widget :xesam:size))) | ||
| 524 | (widget-put | ||
| 525 | widget :xesam:size (string-to-number (widget-get widget :xesam:url)))) | ||
| 526 | |||
| 506 | ;; First line: :tag. | 527 | ;; First line: :tag. |
| 507 | (cond | 528 | (cond |
| 508 | ((widget-member widget :xesam:title) | 529 | ((widget-member widget :xesam:title) |
| @@ -514,6 +535,11 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 514 | ((widget-member widget :xesam:name) | 535 | ((widget-member widget :xesam:name) |
| 515 | (widget-put widget :tag (widget-get widget :xesam:name)))) | 536 | (widget-put widget :tag (widget-get widget :xesam:name)))) |
| 516 | 537 | ||
| 538 | ;; Highlight the search items. | ||
| 539 | (when (widget-member widget :tag) | ||
| 540 | (widget-put | ||
| 541 | widget :tag (xesam-highlight-string (widget-get widget :tag)))) | ||
| 542 | |||
| 517 | ;; Last Modified. | 543 | ;; Last Modified. |
| 518 | (when (widget-member widget :xesam:sourceModified) | 544 | (when (widget-member widget :xesam:sourceModified) |
| 519 | (widget-put | 545 | (widget-put |
| @@ -556,11 +582,12 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 556 | (widget-put widget :doc (widget-get widget :xesam:snippet)))) | 582 | (widget-put widget :doc (widget-get widget :xesam:snippet)))) |
| 557 | 583 | ||
| 558 | (when (widget-member widget :doc) | 584 | (when (widget-member widget :doc) |
| 559 | (widget-put widget :help-echo (widget-get widget :doc)) | ||
| 560 | (with-temp-buffer | 585 | (with-temp-buffer |
| 561 | (insert (widget-get widget :doc)) | 586 | (insert |
| 587 | (xesam-highlight-string (widget-get widget :doc))) | ||
| 562 | (fill-region-as-paragraph (point-min) (point-max)) | 588 | (fill-region-as-paragraph (point-min) (point-max)) |
| 563 | (widget-put widget :doc (buffer-string)))) | 589 | (widget-put widget :doc (buffer-string))) |
| 590 | (widget-put widget :help-echo (widget-get widget :doc))) | ||
| 564 | 591 | ||
| 565 | ;; Format the widget. | 592 | ;; Format the widget. |
| 566 | (widget-put | 593 | (widget-put |
| @@ -576,24 +603,38 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 576 | (force-mode-line-update) | 603 | (force-mode-line-update) |
| 577 | (redisplay))) | 604 | (redisplay))) |
| 578 | 605 | ||
| 606 | (defun xesam-get-hits (engine search hits) | ||
| 607 | "Retrieve hits from ENGINE." | ||
| 608 | (with-current-buffer (xesam-buffer-name (car engine) search) | ||
| 609 | (setq xesam-objects | ||
| 610 | (append xesam-objects | ||
| 611 | (xesam-dbus-call-method | ||
| 612 | :session (car engine) xesam-path-search | ||
| 613 | xesam-interface-search "GetHits" search hits))))) | ||
| 614 | |||
| 579 | (defun xesam-refresh-search-buffer (engine search) | 615 | (defun xesam-refresh-search-buffer (engine search) |
| 580 | "Refreshes the buffer, presenting results of SEARCH." | 616 | "Refreshes the buffer, presenting results of SEARCH." |
| 581 | (with-current-buffer (xesam-buffer-name (car engine) search) | 617 | (with-current-buffer (xesam-buffer-name (car engine) search) |
| 582 | ;; Work only if nobody else is here. | 618 | ;; Work only if nobody else is here. |
| 583 | (unless xesam-refreshing | 619 | (unless (or xesam-refreshing (>= xesam-current xesam-to)) |
| 584 | (setq xesam-refreshing t) | 620 | (setq xesam-refreshing t) |
| 585 | (unwind-protect | 621 | (unwind-protect |
| 586 | (let (widget updated) | 622 | (let (widget) |
| 587 | ;; Add all result widgets. The upper boundary is always | 623 | |
| 588 | ;; computed, because new hits might have arrived while | 624 | ;; Retrieve needed hits for visualization. |
| 589 | ;; running. | 625 | (while (> (min xesam-to xesam-count) (length xesam-objects)) |
| 626 | (xesam-get-hits | ||
| 627 | engine search | ||
| 628 | (min xesam-hits-per-page | ||
| 629 | (- (min xesam-to xesam-count) (length xesam-objects))))) | ||
| 630 | |||
| 631 | ;; Add all result widgets. | ||
| 590 | (while (< xesam-current (min xesam-to xesam-count)) | 632 | (while (< xesam-current (min xesam-to xesam-count)) |
| 591 | (setq updated t | 633 | (setq xesam-current (1+ xesam-current)) |
| 592 | xesam-current (1+ xesam-current)) | ||
| 593 | (xesam-refresh-entry engine search)) | 634 | (xesam-refresh-entry engine search)) |
| 594 | 635 | ||
| 595 | ;; Add "NEXT" widget. | 636 | ;; Add "NEXT" widget. |
| 596 | (when (and updated (> xesam-count xesam-to)) | 637 | (when (> xesam-count xesam-to) |
| 597 | (goto-char (point-max)) | 638 | (goto-char (point-max)) |
| 598 | (widget-create | 639 | (widget-create |
| 599 | 'link | 640 | 'link |
| @@ -603,7 +644,16 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 603 | (widget-delete widget) | 644 | (widget-delete widget) |
| 604 | (xesam-refresh-search-buffer xesam-engine xesam-search)) | 645 | (xesam-refresh-search-buffer xesam-engine xesam-search)) |
| 605 | "NEXT") | 646 | "NEXT") |
| 606 | (widget-beginning-of-line))) | 647 | (widget-beginning-of-line)) |
| 648 | |||
| 649 | ;; Prefetch next hits. | ||
| 650 | (when (> (min (+ xesam-hits-per-page xesam-to) xesam-count) | ||
| 651 | (length xesam-objects)) | ||
| 652 | (xesam-get-hits | ||
| 653 | engine search | ||
| 654 | (min xesam-hits-per-page | ||
| 655 | (- (min (+ xesam-hits-per-page xesam-to) xesam-count) | ||
| 656 | (length xesam-objects)))))) | ||
| 607 | 657 | ||
| 608 | ;; Return with save settings. | 658 | ;; Return with save settings. |
| 609 | (setq xesam-refreshing nil))))) | 659 | (setq xesam-refreshing nil))))) |
| @@ -632,9 +682,16 @@ SEARCH is the search identification in that engine. Both must be strings." | |||
| 632 | 682 | ||
| 633 | ((string-equal member "SearchDone") | 683 | ((string-equal member "SearchDone") |
| 634 | (setq mode-line-process | 684 | (setq mode-line-process |
| 635 | (propertize " Done" 'face 'font-lock-type-face)) | 685 | (propertize " Done" 'face 'xesam-mode-line)) |
| 636 | (force-mode-line-update))))))) | 686 | (force-mode-line-update))))))) |
| 637 | 687 | ||
| 688 | (defun xesam-kill-buffer-function () | ||
| 689 | "Send the CloseSearch indication." | ||
| 690 | (when (and (eq major-mode 'xesam-mode) (stringp xesam-search)) | ||
| 691 | (xesam-dbus-call-method | ||
| 692 | :session (car xesam-engine) xesam-path-search | ||
| 693 | xesam-interface-search "CloseSearch" xesam-search))) | ||
| 694 | |||
| 638 | (defun xesam-new-search (engine type query) | 695 | (defun xesam-new-search (engine type query) |
| 639 | "Create a new search session. | 696 | "Create a new search session. |
| 640 | ENGINE identifies the search engine. TYPE is the query type, it | 697 | ENGINE identifies the search engine. TYPE is the query type, it |
| @@ -675,6 +732,7 @@ search, is returned." | |||
| 675 | xesam-type (symbol-name type) | 732 | xesam-type (symbol-name type) |
| 676 | xesam-query query | 733 | xesam-query query |
| 677 | xesam-xml-string xml-string | 734 | xesam-xml-string xml-string |
| 735 | xesam-objects nil | ||
| 678 | ;; The buffer identification shall indicate the search | 736 | ;; The buffer identification shall indicate the search |
| 679 | ;; engine. The `help-echo' property is used for debug | 737 | ;; engine. The `help-echo' property is used for debug |
| 680 | ;; information, when applicable. | 738 | ;; information, when applicable. |
| @@ -694,7 +752,8 @@ search, is returned." | |||
| 694 | "vendor.ontology.sources" "vendor.extensions" | 752 | "vendor.ontology.sources" "vendor.extensions" |
| 695 | "vendor.ontologies" "vendor.maxhits") | 753 | "vendor.ontologies" "vendor.maxhits") |
| 696 | "\n")))) | 754 | "\n")))) |
| 697 | (force-mode-line-update)) | 755 | (add-hook 'kill-buffer-hook 'xesam-kill-buffer-function) |
| 756 | (force-mode-line-update)) | ||
| 698 | 757 | ||
| 699 | ;; Start the search. | 758 | ;; Start the search. |
| 700 | (xesam-dbus-call-method | 759 | (xesam-dbus-call-method |
| @@ -748,18 +807,16 @@ Example: | |||
| 748 | 807 | ||
| 749 | ;;; TODO: | 808 | ;;; TODO: |
| 750 | 809 | ||
| 751 | ;; * Solve error, that xesam-mode does not work the very first time. | 810 | ;; * Accept input while retrieving prefetched hits. `run-at-time'? |
| 752 | ;; * Retrieve several results at once. | ||
| 753 | ;; * Retrieve hits for the next page in advance. | ||
| 754 | ;; * With prefix, let's choose search engine. | 811 | ;; * With prefix, let's choose search engine. |
| 755 | ;; * Minibuffer completion for user queries. | 812 | ;; * Minibuffer completion for user queries. |
| 756 | ;; * `revert-buffer-function' implementation. | 813 | ;; * `revert-buffer-function' implementation. |
| 757 | ;; * Close search when search buffer is killed. | ||
| 758 | ;; | 814 | ;; |
| 759 | ;; * Mid term | 815 | ;; * Mid term |
| 760 | ;; - If available, use ontologies for field selection. | 816 | ;; - If available, use ontologies for field selection. |
| 761 | ;; - Search engines for Emacs bugs database, wikipedia, google, | 817 | ;; - Search engines for Emacs bugs database, wikipedia, google, |
| 762 | ;; yahoo, ebay, ... | 818 | ;; yahoo, ebay, ... |
| 819 | ;; - Construct complex queries via widgets, like in mairix.el. | ||
| 763 | 820 | ||
| 764 | ;; arch-tag: 7fb9fc6c-c2ff-4bc7-bb42-bacb80cce2b2 | 821 | ;; arch-tag: 7fb9fc6c-c2ff-4bc7-bb42-bacb80cce2b2 |
| 765 | ;;; xesam.el ends here | 822 | ;;; xesam.el ends here |