2008-07-24 21:45:01 +00:00
|
|
|
|
;;; xesam.el --- Xesam interface to search engines.
|
|
|
|
|
|
|
|
|
|
;; Copyright (C) 2008 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
;; Author: Michael Albinus <michael.albinus@gmx.de>
|
|
|
|
|
;; Keywords: tools, hypermedia
|
|
|
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
|
2008-08-10 00:32:57 +00:00
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
2008-08-10 00:32:57 +00:00
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2008-08-10 00:32:57 +00:00
|
|
|
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
|
|
;; This package provides an interface to the Xesam, a D-Bus based "eXtEnsible
|
|
|
|
|
;; Search And Metadata specification". It has been tested with
|
|
|
|
|
;;
|
|
|
|
|
;; xesam-glib 0.3.4, xesam-tools 0.6.1
|
|
|
|
|
;; beagle 0.3.7, beagle-xesam 0.2
|
2008-07-31 19:30:14 +00:00
|
|
|
|
;; strigi 0.5.11
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; The precondition for this package is a D-Bus aware Emacs. This is
|
|
|
|
|
;; configured per default, when Emacs is built on a machine running
|
|
|
|
|
;; D-Bus. Furthermore, there must be at least one search engine
|
|
|
|
|
;; running, which support the Xesam interface. Beagle and strigi have
|
|
|
|
|
;; been tested; tracker, pinot and recoll are also said to support
|
|
|
|
|
;; Xesam. You can check the existence of such a search engine by
|
|
|
|
|
;;
|
|
|
|
|
;; (dbus-list-queued-owners :session "org.freedesktop.xesam.searcher")
|
|
|
|
|
|
|
|
|
|
;; In order to start a search, you must load xesam.el:
|
|
|
|
|
;;
|
|
|
|
|
;; (require 'xesam)
|
|
|
|
|
|
|
|
|
|
;; xesam.el supports two types of queries, which are explained *very* short:
|
|
|
|
|
;;
|
|
|
|
|
;; * Full text queries. Just search keys shall be given, like
|
|
|
|
|
;;
|
|
|
|
|
;; hello world
|
|
|
|
|
;;
|
|
|
|
|
;; A full text query in xesam.el is restricted to files.
|
|
|
|
|
;;
|
|
|
|
|
;; * Xesam End User Search Language queries. The Xesam query language
|
|
|
|
|
;; is described at <http://xesam.org/main/XesamUserSearchLanguage>,
|
|
|
|
|
;; which must be consulted for the whole features.
|
|
|
|
|
;;
|
|
|
|
|
;; A query string consists of search keys, collectors, selectors,
|
|
|
|
|
;; and phrases. Search keys are words like in a full text query:
|
|
|
|
|
;;
|
|
|
|
|
;; hello word
|
|
|
|
|
;;
|
|
|
|
|
;; A selector is a tuple <keyword><relation>. <keyword> can be any
|
|
|
|
|
;; predefined Xesam keyword, the most common keywords are "ext"
|
|
|
|
|
;; (file name extension), "format " (mime type), "tag" (user
|
|
|
|
|
;; keywords) and "type" (types of items, like "audio", "file",
|
|
|
|
|
;; "picture", "attachment"). <relation> is a comparison to a value,
|
|
|
|
|
;; which must be a string (relation ":" or "=") or number (relation
|
|
|
|
|
;; "<=", ">=", "<", ">"):
|
|
|
|
|
;;
|
|
|
|
|
;; type:attachment ext=el
|
|
|
|
|
;;
|
|
|
|
|
;; A collector is one of the items "AND", "and", "&&", "OR", "or",
|
|
|
|
|
;; "||", or "-". The default collector on multiple terms is "AND";
|
|
|
|
|
;; "-" means "AND NOT".
|
|
|
|
|
;;
|
|
|
|
|
;; albinus -type:file
|
|
|
|
|
;;
|
|
|
|
|
;; A phrase is a string enclosed in quotes, with appended modifiers
|
|
|
|
|
;; (single letters). Examples of modifiers are "c" (case
|
|
|
|
|
;; sensitive), "C" (case insensitive), "e" (exact match), "r"
|
|
|
|
|
;; (regular expression):
|
|
|
|
|
;;
|
|
|
|
|
;; "Hello world"c
|
|
|
|
|
|
|
|
|
|
;; You can customize, whether you want to apply a Xesam user query, or
|
|
|
|
|
;; a full text query. Note, that not every search engine supports
|
|
|
|
|
;; both query types.
|
|
|
|
|
;;
|
|
|
|
|
;; (setq xesam-query-type 'fulltext-query)
|
|
|
|
|
;;
|
|
|
|
|
;; Another option to be customised is the number of hits to be
|
|
|
|
|
;; presented at once.
|
|
|
|
|
;;
|
|
|
|
|
;; (setq xesam-hits-per-page 50)
|
|
|
|
|
|
|
|
|
|
;; A search can be started by the command
|
|
|
|
|
;;
|
|
|
|
|
;; M-x xesam-search
|
|
|
|
|
;;
|
|
|
|
|
;; When several search engines are registered, the engine to be used
|
|
|
|
|
;; can be selected via minibuffer completion. Afterwards, the query
|
|
|
|
|
;; shall be entered in the minibuffer.
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
;; D-Bus support in the Emacs core can be disabled with configuration
|
|
|
|
|
;; option "--without-dbus". Declare used subroutines and variables.
|
|
|
|
|
(declare-function dbus-call-method "dbusbind.c")
|
|
|
|
|
(declare-function dbus-register-signal "dbusbind.c")
|
|
|
|
|
|
|
|
|
|
(require 'dbus)
|
|
|
|
|
|
|
|
|
|
;; Pacify byte compiler.
|
|
|
|
|
(eval-when-compile
|
|
|
|
|
(require 'cl))
|
|
|
|
|
|
|
|
|
|
;; Widgets are used to highlight the search results.
|
|
|
|
|
(require 'widget)
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(require 'wid-edit)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; `run-at-time' is used in the signal handler.
|
|
|
|
|
(require 'timer)
|
|
|
|
|
|
|
|
|
|
;; The default search field is "xesam:url". It must be inspected.
|
|
|
|
|
(require 'url)
|
|
|
|
|
|
|
|
|
|
(defgroup xesam nil
|
|
|
|
|
"Xesam compatible interface to search engines."
|
|
|
|
|
:group 'extensions
|
|
|
|
|
:group 'hypermedia
|
|
|
|
|
:version "23.1")
|
|
|
|
|
|
|
|
|
|
(defcustom xesam-query-type 'user-query
|
|
|
|
|
"Xesam query language type."
|
|
|
|
|
:group 'xesam
|
|
|
|
|
:type '(choice
|
|
|
|
|
(const :tag "Xesam user query" user-query)
|
|
|
|
|
(const :tag "Xesam fulltext query" fulltext-query)))
|
|
|
|
|
|
|
|
|
|
(defcustom xesam-hits-per-page 20
|
2008-08-05 19:49:17 +00:00
|
|
|
|
"Number of search hits to be displayed in the result buffer."
|
2008-07-24 21:45:01 +00:00
|
|
|
|
:group 'xesam
|
|
|
|
|
:type 'integer)
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(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)
|
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(defvar xesam-debug nil
|
2008-07-26 18:55:02 +00:00
|
|
|
|
"Insert debug information in the help echo.")
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
(defconst xesam-service-search "org.freedesktop.xesam.searcher"
|
|
|
|
|
"The D-Bus name used to talk to Xesam.")
|
|
|
|
|
|
|
|
|
|
(defconst xesam-path-search "/org/freedesktop/xesam/searcher/main"
|
|
|
|
|
"The D-Bus object path used to talk to Xesam.")
|
|
|
|
|
|
|
|
|
|
;; Methods: "NewSession", "SetProperty", "GetProperty",
|
|
|
|
|
;; "CloseSession", "NewSearch", "StartSearch", "GetHitCount",
|
|
|
|
|
;; "GetHits", "GetHitData", "CloseSearch" and "GetState".
|
|
|
|
|
;; Signals: "HitsAdded", "HitsRemoved", "HitsModified", "SearchDone"
|
|
|
|
|
;; and "StateChanged".
|
|
|
|
|
(defconst xesam-interface-search "org.freedesktop.xesam.Search"
|
|
|
|
|
"The D-Bus Xesam search interface.")
|
|
|
|
|
|
|
|
|
|
(defconst xesam-all-fields
|
2008-08-01 18:56:08 +00:00
|
|
|
|
'("xesam:35mmEquivalent" "xesam:aimContactMedium" "xesam:aperture"
|
|
|
|
|
"xesam:aspectRatio" "xesam:attachmentEncoding" "xesam:attendee"
|
|
|
|
|
"xesam:audioBirate" "xesam:audioChannels" "xesam:audioCodec"
|
|
|
|
|
"xesam:audioCodecType" "xesam:audioSampleFormat" "xesam:audioSampleRate"
|
|
|
|
|
"xesam:author" "xesam:bcc" "xesam:birthDate" "xesam:blogContactURL"
|
2008-07-24 21:45:01 +00:00
|
|
|
|
"xesam:cameraManufacturer" "xesam:cameraModel" "xesam:cc" "xesam:ccdWidth"
|
|
|
|
|
"xesam:cellPhoneNumber" "xesam:characterCount" "xesam:charset"
|
|
|
|
|
"xesam:colorCount" "xesam:colorSpace" "xesam:columnCount" "xesam:comment"
|
|
|
|
|
"xesam:commentCharacterCount" "xesam:conflicts" "xesam:contactMedium"
|
|
|
|
|
"xesam:contactName" "xesam:contactNick" "xesam:contactPhoto"
|
|
|
|
|
"xesam:contactURL" "xesam:contains" "xesam:contenKeyword"
|
|
|
|
|
"xesam:contentComment" "xesam:contentCreated" "xesam:contentModified"
|
|
|
|
|
"xesam:contentType" "xesam:contributor" "xesam:copyright" "xesam:creator"
|
|
|
|
|
"xesam:definesClass" "xesam:definesFunction" "xesam:definesGlobalVariable"
|
|
|
|
|
"xesam:deletionTime" "xesam:depends" "xesam:description" "xesam:device"
|
|
|
|
|
"xesam:disclaimer" "xesam:documentCategory" "xesam:duration"
|
|
|
|
|
"xesam:emailAddress" "xesam:eventEnd" "xesam:eventLocation"
|
|
|
|
|
"xesam:eventStart" "xesam:exposureBias" "xesam:exposureProgram"
|
|
|
|
|
"xesam:exposureTime" "xesam:faxPhoneNumber" "xesam:fileExtension"
|
|
|
|
|
"xesam:fileSystemType" "xesam:flashUsed" "xesam:focalLength"
|
|
|
|
|
"xesam:focusDistance" "xesam:formatSubtype" "xesam:frameCount"
|
|
|
|
|
"xesam:frameRate" "xesam:freeSpace" "xesam:gender" "xesam:generator"
|
|
|
|
|
"xesam:generatorOptions" "xesam:group" "xesam:hash" "xesam:hash"
|
|
|
|
|
"xesam:height" "xesam:homeEmailAddress" "xesam:homePhoneNumber"
|
|
|
|
|
"xesam:homePostalAddress" "xesam:homepageContactURL"
|
|
|
|
|
"xesam:horizontalResolution" "xesam:icqContactMedium" "xesam:id"
|
|
|
|
|
"xesam:imContactMedium" "xesam:interests" "xesam:interlaceMode"
|
|
|
|
|
"xesam:isEncrypted" "xesam:isImportant" "xesam:isInProgress"
|
|
|
|
|
"xesam:isPasswordProtected" "xesam:isRead" "xesam:isoEquivalent"
|
|
|
|
|
"xesam:jabberContactMedium" "xesam:keyword" "xesam:language" "xesam:legal"
|
|
|
|
|
"xesam:license" "xesam:licenseType" "xesam:lineCount" "xesam:links"
|
|
|
|
|
"xesam:mailingPostalAddress" "xesam:maintainer" "xesam:md5Hash"
|
|
|
|
|
"xesam:mediaCodec" "xesam:mediaCodecBitrate" "xesam:mediaCodecType"
|
|
|
|
|
"xesam:meteringMode" "xesam:mimeType" "xesam:mountPoint"
|
|
|
|
|
"xesam:msnContactMedium" "xesam:name" "xesam:occupiedSpace"
|
|
|
|
|
"xesam:orientation" "xesam:originalLocation" "xesam:owner"
|
|
|
|
|
"xesam:pageCount" "xesam:permissions" "xesam:phoneNumber"
|
|
|
|
|
"xesam:physicalAddress" "xesam:pixelFormat" "xesam:primaryRecipient"
|
|
|
|
|
"xesam:programmingLanguage" "xesam:rating" "xesam:receptionTime"
|
|
|
|
|
"xesam:recipient" "xesam:related" "xesam:remoteUser" "xesam:rowCount"
|
|
|
|
|
"xesam:sampleBitDepth" "xesam:sampleFormat" "xesam:secondaryRecipient"
|
|
|
|
|
"xesam:sha1Hash" "xesam:size" "xesam:skypeContactMedium"
|
|
|
|
|
"xesam:sourceCreated" "xesam:sourceModified" "xesam:storageSize"
|
|
|
|
|
"xesam:subject" "xesam:supercedes" "xesam:title" "xesam:to"
|
|
|
|
|
"xesam:totalSpace" "xesam:totalUncompressedSize" "xesam:url"
|
|
|
|
|
"xesam:usageIntensity" "xesam:userComment" "xesam:userKeyword"
|
|
|
|
|
"xesam:uuid" "xesam:version" "xesam:verticalResolution" "xesam:videoBirate"
|
|
|
|
|
"xesam:videoCodec" "xesam:videoCodecType" "xesam:whiteBalance"
|
|
|
|
|
"xesam:width" "xesam:wordCount" "xesam:workEmailAddress"
|
|
|
|
|
"xesam:workPhoneNumber" "xesam:workPostalAddress"
|
|
|
|
|
"xesam:yahooContactMedium")
|
|
|
|
|
"All fields from the Xesam Core Ontology.
|
|
|
|
|
This defconst can be used to check for a new search engine, which
|
|
|
|
|
fields are supported.")
|
|
|
|
|
|
|
|
|
|
(defconst xesam-user-query
|
|
|
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
|
|
|
|
<request xmlns=\"http://freedesktop.org/standards/xesam/1.0/query\">
|
|
|
|
|
<userQuery>
|
|
|
|
|
%s
|
|
|
|
|
</userQuery>
|
|
|
|
|
</request>"
|
|
|
|
|
"The Xesam user query XML.")
|
|
|
|
|
|
|
|
|
|
(defconst xesam-fulltext-query
|
|
|
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
|
|
|
|
<request xmlns=\"http://freedesktop.org/standards/xesam/1.0/query\">
|
|
|
|
|
<query content=\"xesam:Document\" source=\"xesam:File\">
|
|
|
|
|
<fullText>
|
|
|
|
|
<string>%s</string>
|
|
|
|
|
</fullText>
|
|
|
|
|
</query>
|
|
|
|
|
</request>"
|
|
|
|
|
"The Xesam fulltext query XML.")
|
|
|
|
|
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(defvar xesam-dbus-unique-names
|
|
|
|
|
(list (cons :system (dbus-get-unique-name :system))
|
|
|
|
|
(cons :session (dbus-get-unique-name :session)))
|
|
|
|
|
"The unique names, under which Emacs is registered at D-Bus.")
|
|
|
|
|
|
|
|
|
|
(defun xesam-dbus-call-method (&rest args)
|
|
|
|
|
"Apply a D-Bus method call.
|
|
|
|
|
`dbus-call-method' is to be preferred, because it is more
|
|
|
|
|
performant. If the target D-Bus service is owned by Emacs, this
|
|
|
|
|
is not applicable, and `dbus-call-method-non-blocking' must be
|
|
|
|
|
used instead. ARGS are identical to the argument list of both
|
|
|
|
|
functions."
|
|
|
|
|
(apply
|
|
|
|
|
;; The first argument is the bus, the second argument the targt service.
|
|
|
|
|
(if (string-equal (cdr (assoc (car args) xesam-dbus-unique-names))
|
|
|
|
|
(cadr args))
|
|
|
|
|
'dbus-call-method-non-blocking 'dbus-call-method)
|
|
|
|
|
args))
|
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(defun xesam-get-property (engine property)
|
|
|
|
|
"Return the PROPERTY value of ENGINE."
|
|
|
|
|
;; "GetProperty" returns a variant, so we must use the car.
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(car (xesam-dbus-call-method
|
2008-07-24 21:45:01 +00:00
|
|
|
|
:session (car engine) xesam-path-search
|
|
|
|
|
xesam-interface-search "GetProperty"
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(xesam-get-cached-property engine "session") property)))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
(defun xesam-set-property (engine property value)
|
|
|
|
|
"Set the PROPERTY of ENGINE to VALUE.
|
|
|
|
|
VALUE can be a string, a non-negative integer, a boolean
|
|
|
|
|
value (nil or t), or a list of them. It returns the new value of
|
|
|
|
|
PROPERTY in the search engine. This new value can be different
|
|
|
|
|
from VALUE, depending on what the search engine accepts."
|
|
|
|
|
;; "SetProperty" returns a variant, so we must use the car.
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(car (xesam-dbus-call-method
|
2008-07-24 21:45:01 +00:00
|
|
|
|
:session (car engine) xesam-path-search
|
|
|
|
|
xesam-interface-search "SetProperty"
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(xesam-get-cached-property engine "session") property
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; The value must be a variant. It can be only a string, an
|
|
|
|
|
;; unsigned int, a boolean, or an array of them. So we need
|
|
|
|
|
;; no type keyword; we let the type check to the search
|
|
|
|
|
;; engine.
|
|
|
|
|
(list :variant value))))
|
|
|
|
|
|
|
|
|
|
(defvar xesam-minibuffer-vendor-history nil
|
|
|
|
|
"Interactive vendor history.")
|
|
|
|
|
|
|
|
|
|
(defvar xesam-minibuffer-query-history nil
|
|
|
|
|
"Interactive query history.")
|
|
|
|
|
|
|
|
|
|
;; Pacify byte compiler.
|
|
|
|
|
(defvar xesam-engine nil)
|
|
|
|
|
(defvar xesam-search nil)
|
2008-07-31 19:30:14 +00:00
|
|
|
|
(defvar xesam-type nil)
|
|
|
|
|
(defvar xesam-query nil)
|
|
|
|
|
(defvar xesam-xml-string nil)
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(defvar xesam-objects nil)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(defvar xesam-current nil)
|
|
|
|
|
(defvar xesam-count nil)
|
|
|
|
|
(defvar xesam-to nil)
|
|
|
|
|
(defvar xesam-refreshing nil)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Search engines.
|
|
|
|
|
|
|
|
|
|
(defvar xesam-search-engines nil
|
|
|
|
|
"List of available Xesam search engines.
|
2008-08-01 18:56:08 +00:00
|
|
|
|
Every entry is an association list, with a car denoting the
|
|
|
|
|
unique D-Bus service name of the engine. The rest of the entry
|
|
|
|
|
are cached associations of engine attributes, like the session
|
|
|
|
|
identifier, and the display name. Example:
|
|
|
|
|
|
|
|
|
|
\(\(\":1.59\"
|
|
|
|
|
\(\"session\" . \"0t1214948020ut358230u0p2698r3912347765k3213849828\")
|
|
|
|
|
\(\"vendor.display\" . \"Tracker Xesam Service\"))
|
|
|
|
|
\(\":1.27\"
|
|
|
|
|
\(\"session\" . \"strigisession1369133069\")
|
|
|
|
|
\(\"vendor.display\" . \"Strigi Desktop Search\")))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
A Xesam-compatible search engine is identified as a queued D-Bus
|
2008-08-01 18:56:08 +00:00
|
|
|
|
service of the known service `xesam-service-search'.")
|
|
|
|
|
|
|
|
|
|
(defun xesam-get-cached-property (engine property)
|
|
|
|
|
"Return the PROPERTY value of ENGINE from the cache.
|
|
|
|
|
If PROPERTY is not existing, retrieve it from ENGINE first."
|
|
|
|
|
;; If the property has not been cached yet, we retrieve it from the
|
|
|
|
|
;; engine, and cache it.
|
|
|
|
|
(unless (assoc property engine)
|
|
|
|
|
(xesam-set-cached-property
|
|
|
|
|
engine property (xesam-get-property engine property)))
|
|
|
|
|
(cdr (assoc property engine)))
|
|
|
|
|
|
|
|
|
|
(defun xesam-set-cached-property (engine property value)
|
|
|
|
|
"Set the PROPERTY of ENGINE to VALUE in the cache."
|
|
|
|
|
(setcdr engine (append (cdr engine) (list (cons property value)))))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
(defun xesam-delete-search-engine (&rest args)
|
2008-08-01 18:56:08 +00:00
|
|
|
|
"Remove service from `xesam-search-engines'."
|
|
|
|
|
(setq xesam-search-engines
|
|
|
|
|
(delete (assoc (car args) xesam-search-engines) xesam-search-engines)))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
(defun xesam-search-engines ()
|
|
|
|
|
"Return Xesam search engines, stored in `xesam-search-engines'.
|
|
|
|
|
The first search engine is the name owner of `xesam-service-search'.
|
|
|
|
|
If there is no registered search engine at all, the function returns `nil'."
|
|
|
|
|
(let ((services (dbus-ignore-errors
|
|
|
|
|
(dbus-list-queued-owners
|
|
|
|
|
:session xesam-service-search)))
|
|
|
|
|
engine vendor-id hit-fields)
|
|
|
|
|
(dolist (service services)
|
|
|
|
|
(unless (assoc-string service xesam-search-engines)
|
|
|
|
|
|
|
|
|
|
;; Open a new session, and add it to the search engines list.
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(add-to-list 'xesam-search-engines (list service) 'append)
|
|
|
|
|
(setq engine (assoc service xesam-search-engines))
|
|
|
|
|
|
|
|
|
|
;; Add the session string.
|
|
|
|
|
(xesam-set-cached-property
|
|
|
|
|
engine "session"
|
|
|
|
|
(xesam-dbus-call-method
|
|
|
|
|
:session service xesam-path-search
|
|
|
|
|
xesam-interface-search "NewSession"))
|
|
|
|
|
|
|
|
|
|
;; Unset the "search.live" property; we don't want to be
|
|
|
|
|
;; informed by changed results.
|
|
|
|
|
(xesam-set-property engine "search.live" nil)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; Check the vendor properties.
|
|
|
|
|
(setq vendor-id (xesam-get-property engine "vendor.id")
|
|
|
|
|
hit-fields (xesam-get-property engine "hit.fields"))
|
|
|
|
|
|
|
|
|
|
;; Ususally, `hit.fields' shall describe supported fields.
|
|
|
|
|
;; That is not the case now, so we set it ourselves.
|
|
|
|
|
;; Hopefully, this will change later.
|
|
|
|
|
(setq hit-fields
|
|
|
|
|
(cond
|
|
|
|
|
((string-equal vendor-id "Beagle")
|
|
|
|
|
'("xesam:mimeType" "xesam:url"))
|
|
|
|
|
((string-equal vendor-id "Strigi")
|
2008-08-05 19:49:17 +00:00
|
|
|
|
'("xesam:author" "xesam:cc" "xesam:charset"
|
2008-07-24 21:45:01 +00:00
|
|
|
|
"xesam:contentType" "xesam:fileExtension" "xesam:id"
|
|
|
|
|
"xesam:lineCount" "xesam:links" "xesam:mimeType" "xesam:name"
|
|
|
|
|
"xesam:size" "xesam:sourceModified" "xesam:subject"
|
|
|
|
|
"xesam:to" "xesam:url"))
|
|
|
|
|
((string-equal vendor-id "TrackerXesamSession")
|
|
|
|
|
'("xesam:relevancyRating" "xesam:url"))
|
|
|
|
|
;; xesam-tools yahoo service.
|
|
|
|
|
(t '("xesam:contentModified" "xesam:mimeType" "xesam:summary"
|
|
|
|
|
"xesam:title" "xesam:url" "yahoo:displayUrl"))))
|
|
|
|
|
|
|
|
|
|
(xesam-set-property engine "hit.fields" hit-fields)
|
|
|
|
|
(xesam-set-property engine "hit.fields.extended" '("xesam:snippet"))
|
|
|
|
|
|
|
|
|
|
;; Let us notify, when the search engine disappears.
|
|
|
|
|
(dbus-register-signal
|
|
|
|
|
:session dbus-service-dbus dbus-path-dbus
|
|
|
|
|
dbus-interface-dbus "NameOwnerChanged"
|
|
|
|
|
'xesam-delete-search-engine service))))
|
|
|
|
|
xesam-search-engines)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Search buffers.
|
|
|
|
|
|
2008-07-31 19:30:14 +00:00
|
|
|
|
(define-derived-mode xesam-mode nil "Xesam"
|
2008-07-24 21:45:01 +00:00
|
|
|
|
"Major mode for presenting search results of a Xesam search.
|
|
|
|
|
In this mode, widgets represent the search results.
|
|
|
|
|
|
|
|
|
|
\\{xesam-mode-map}
|
|
|
|
|
Turning on Xesam mode runs the normal hook `xesam-mode-hook'."
|
2008-07-31 19:30:14 +00:00
|
|
|
|
;; Keymap.
|
|
|
|
|
(setq xesam-mode-map (copy-keymap special-mode-map))
|
|
|
|
|
(set-keymap-parent xesam-mode-map widget-keymap)
|
|
|
|
|
(define-key xesam-mode-map "z" 'kill-this-buffer)
|
|
|
|
|
|
|
|
|
|
;; Maybe we implement something useful, later on.
|
|
|
|
|
(set (make-local-variable 'revert-buffer-function) 'ignore)
|
|
|
|
|
;; `xesam-engine', `xesam-search', `xesam-type', `xesam-query', and
|
|
|
|
|
;; `xesam-xml-string' will be set in `xesam-new-search'.
|
|
|
|
|
(set (make-local-variable 'xesam-engine) nil)
|
|
|
|
|
(set (make-local-variable 'xesam-search) nil)
|
|
|
|
|
(set (make-local-variable 'xesam-type) "")
|
|
|
|
|
(set (make-local-variable 'xesam-query) "")
|
|
|
|
|
(set (make-local-variable 'xesam-xml-string) "")
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(set (make-local-variable 'xesam-objects) nil)
|
2008-07-31 19:30:14 +00:00
|
|
|
|
;; `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.
|
|
|
|
|
(set (make-local-variable 'xesam-count) 0)
|
|
|
|
|
;; `xesam-to' is the upper hit number to be presented.
|
|
|
|
|
(set (make-local-variable 'xesam-to) xesam-hits-per-page)
|
|
|
|
|
;; `xesam-refreshing' is an indicator, whether the buffer is just
|
|
|
|
|
;; being updated. Needed, because `xesam-refresh-search-buffer'
|
|
|
|
|
;; can be triggered by an event.
|
|
|
|
|
(set (make-local-variable 'xesam-refreshing) nil)
|
|
|
|
|
;; Mode line position returns hit counters.
|
|
|
|
|
(set (make-local-variable 'mode-line-position)
|
|
|
|
|
(list '(-3 "%p%")
|
|
|
|
|
'(10 (:eval (format " (%d/%d)" xesam-current xesam-count)))))
|
|
|
|
|
;; Header line contains the query string.
|
|
|
|
|
(set (make-local-variable 'header-line-format)
|
|
|
|
|
(list '(20
|
|
|
|
|
(:eval
|
|
|
|
|
(list "Type: "
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(propertize xesam-type 'face 'xesam-mode-line))))
|
2008-07-31 19:30:14 +00:00
|
|
|
|
'(10
|
|
|
|
|
(:eval
|
|
|
|
|
(list " Query: "
|
|
|
|
|
(propertize
|
|
|
|
|
xesam-query
|
2008-08-05 19:49:17 +00:00
|
|
|
|
'face 'xesam-mode-line
|
2008-08-01 18:56:08 +00:00
|
|
|
|
'help-echo (when xesam-debug xesam-xml-string)))))))
|
2008-07-31 19:30:14 +00:00
|
|
|
|
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(when (not (interactive-p))
|
|
|
|
|
;; Initialize buffer.
|
|
|
|
|
(setq buffer-read-only t)
|
|
|
|
|
(let ((inhibit-read-only t))
|
2008-07-31 19:30:14 +00:00
|
|
|
|
(erase-buffer))))
|
|
|
|
|
|
|
|
|
|
;; It doesn't make sense to call it interactively.
|
|
|
|
|
(put 'xesam-mode 'disabled t)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
;; 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))
|
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(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))
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(defun xesam-highlight-string (string)
|
|
|
|
|
"Highlight text enclosed by <b> and </b>."
|
|
|
|
|
(while (string-match "\\(.*\\)\\(<b>\\)\\(.*\\)\\(</b>\\)\\(.*\\)" 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)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
"Refreshes one entry in the search buffer."
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(let* ((result (nth (1- xesam-current) xesam-objects))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
widget)
|
|
|
|
|
|
|
|
|
|
;; Create widget.
|
|
|
|
|
(setq widget (widget-convert 'link))
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(when xesam-debug
|
|
|
|
|
(widget-put widget :help-echo ""))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; Take all results.
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(dolist (field (xesam-get-cached-property engine "hit.fields"))
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(when (cond
|
|
|
|
|
((stringp (caar result)) (not (zerop (length (caar result)))))
|
|
|
|
|
((numberp (caar result)) (not (zerop (caar result))))
|
|
|
|
|
((caar result) t))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(when xesam-debug
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(widget-put
|
|
|
|
|
widget :help-echo
|
|
|
|
|
(format "%s%s: %s\n"
|
|
|
|
|
(widget-get widget :help-echo) field (caar result))))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(widget-put widget (intern (concat ":" field)) (caar result)))
|
|
|
|
|
(setq result (cdr result)))
|
|
|
|
|
|
|
|
|
|
;; Strigi doesn't return URLs in xesam:url. We must fix this.
|
|
|
|
|
(when
|
|
|
|
|
(not (url-type (url-generic-parse-url (widget-get widget :xesam:url))))
|
|
|
|
|
(widget-put
|
|
|
|
|
widget :xesam:url (concat "file://" (widget-get widget :xesam:url))))
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
;; 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))))
|
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; First line: :tag.
|
|
|
|
|
(cond
|
|
|
|
|
((widget-member widget :xesam:title)
|
|
|
|
|
(widget-put widget :tag (widget-get widget :xesam:title)))
|
|
|
|
|
((widget-member widget :xesam:subject)
|
|
|
|
|
(widget-put widget :tag (widget-get widget :xesam:subject)))
|
|
|
|
|
((widget-member widget :xesam:mimeType)
|
|
|
|
|
(widget-put widget :tag (widget-get widget :xesam:mimeType)))
|
|
|
|
|
((widget-member widget :xesam:name)
|
|
|
|
|
(widget-put widget :tag (widget-get widget :xesam:name))))
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
;; Highlight the search items.
|
|
|
|
|
(when (widget-member widget :tag)
|
|
|
|
|
(widget-put
|
|
|
|
|
widget :tag (xesam-highlight-string (widget-get widget :tag))))
|
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; Last Modified.
|
|
|
|
|
(when (widget-member widget :xesam:sourceModified)
|
|
|
|
|
(widget-put
|
|
|
|
|
widget :tag
|
|
|
|
|
(format
|
|
|
|
|
"%s\nLast Modified: %s"
|
|
|
|
|
(or (widget-get widget :tag) "")
|
|
|
|
|
(format-time-string
|
|
|
|
|
"%d %B %Y, %T"
|
|
|
|
|
(seconds-to-time
|
|
|
|
|
(string-to-number (widget-get widget :xesam:sourceModified)))))))
|
|
|
|
|
|
|
|
|
|
;; Second line: :value.
|
|
|
|
|
(widget-put widget :value (widget-get widget :xesam:url))
|
|
|
|
|
|
|
|
|
|
(cond
|
|
|
|
|
;; In case of HTML, we use a URL link.
|
|
|
|
|
((and (widget-member widget :xesam:mimeType)
|
|
|
|
|
(string-equal "text/html" (widget-get widget :xesam:mimeType)))
|
|
|
|
|
(setcar widget 'url-link))
|
|
|
|
|
|
|
|
|
|
;; For local files, we will open the file as default action.
|
|
|
|
|
((string-match "file"
|
|
|
|
|
(url-type (url-generic-parse-url
|
|
|
|
|
(widget-get widget :xesam:url))))
|
|
|
|
|
(widget-put
|
|
|
|
|
widget :notify
|
|
|
|
|
'(lambda (widget &rest ignore)
|
|
|
|
|
(find-file
|
|
|
|
|
(url-filename (url-generic-parse-url (widget-value widget))))))
|
|
|
|
|
(widget-put
|
|
|
|
|
widget :value
|
|
|
|
|
(url-filename (url-generic-parse-url (widget-get widget :xesam:url))))))
|
|
|
|
|
|
|
|
|
|
;; Third line: :doc.
|
|
|
|
|
(cond
|
|
|
|
|
((widget-member widget :xesam:summary)
|
|
|
|
|
(widget-put widget :doc (widget-get widget :xesam:summary)))
|
|
|
|
|
((widget-member widget :xesam:snippet)
|
|
|
|
|
(widget-put widget :doc (widget-get widget :xesam:snippet))))
|
|
|
|
|
|
|
|
|
|
(when (widget-member widget :doc)
|
|
|
|
|
(with-temp-buffer
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(insert
|
|
|
|
|
(xesam-highlight-string (widget-get widget :doc)))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(fill-region-as-paragraph (point-min) (point-max))
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(widget-put widget :doc (buffer-string)))
|
|
|
|
|
(widget-put widget :help-echo (widget-get widget :doc)))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; Format the widget.
|
|
|
|
|
(widget-put
|
|
|
|
|
widget :format
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(format "%d. %s%%[%%v%%]\n%s\n" xesam-current
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(if (widget-member widget :tag) "%{%t%}\n" "")
|
|
|
|
|
(if (widget-member widget :doc) "%h" "")))
|
|
|
|
|
|
|
|
|
|
;; Write widget.
|
|
|
|
|
(goto-char (point-max))
|
|
|
|
|
(widget-default-create widget)
|
|
|
|
|
(set-buffer-modified-p nil)
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(force-mode-line-update)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(redisplay)))
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(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)))))
|
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(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.
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(unless (or xesam-refreshing (>= xesam-current xesam-to))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(setq xesam-refreshing t)
|
|
|
|
|
(unwind-protect
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(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.
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(while (< xesam-current (min xesam-to xesam-count))
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(setq xesam-current (1+ xesam-current))
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(xesam-refresh-entry engine search))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; Add "NEXT" widget.
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(when (> xesam-count xesam-to)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(goto-char (point-max))
|
|
|
|
|
(widget-create
|
|
|
|
|
'link
|
|
|
|
|
:notify
|
|
|
|
|
'(lambda (widget &rest ignore)
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(setq xesam-to (+ xesam-to xesam-hits-per-page))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(widget-delete widget)
|
|
|
|
|
(xesam-refresh-search-buffer xesam-engine xesam-search))
|
|
|
|
|
"NEXT")
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(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))))))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; Return with save settings.
|
|
|
|
|
(setq xesam-refreshing nil)))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Search functions.
|
|
|
|
|
|
|
|
|
|
(defun xesam-signal-handler (&rest args)
|
|
|
|
|
"Handles the different D-Bus signals of a Xesam search."
|
|
|
|
|
(let* ((service (dbus-event-service-name last-input-event))
|
|
|
|
|
(member (dbus-event-member-name last-input-event))
|
|
|
|
|
(search (nth 0 args))
|
|
|
|
|
(buffer (xesam-buffer-name service search)))
|
|
|
|
|
|
|
|
|
|
(when (get-buffer buffer)
|
|
|
|
|
(with-current-buffer buffer
|
|
|
|
|
(cond
|
|
|
|
|
|
|
|
|
|
((string-equal member "HitsAdded")
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(setq xesam-count (+ xesam-count (nth 1 args)))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; We use `run-at-time' in order to not block the event queue.
|
|
|
|
|
(run-at-time
|
|
|
|
|
0 nil
|
|
|
|
|
'xesam-refresh-search-buffer
|
|
|
|
|
(assoc service xesam-search-engines) search))
|
|
|
|
|
|
|
|
|
|
((string-equal member "SearchDone")
|
|
|
|
|
(setq mode-line-process
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(propertize " Done" 'face 'xesam-mode-line))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(force-mode-line-update)))))))
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(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)))
|
|
|
|
|
|
2008-07-31 19:30:14 +00:00
|
|
|
|
(defun xesam-new-search (engine type query)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
"Create a new search session.
|
2008-07-31 19:30:14 +00:00
|
|
|
|
ENGINE identifies the search engine. TYPE is the query type, it
|
|
|
|
|
can be either `fulltext-query', or `user-query'. QUERY is a
|
|
|
|
|
string in the Xesam query language. A string, identifying the
|
|
|
|
|
search, is returned."
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(let* ((service (car engine))
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(session (xesam-get-cached-property engine "session"))
|
2008-07-31 19:30:14 +00:00
|
|
|
|
(xml-string
|
|
|
|
|
(format
|
|
|
|
|
(if (eq type 'user-query) xesam-user-query xesam-fulltext-query)
|
|
|
|
|
query))
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(search (xesam-dbus-call-method
|
2008-07-24 21:45:01 +00:00
|
|
|
|
:session service xesam-path-search
|
2008-07-31 19:30:14 +00:00
|
|
|
|
xesam-interface-search "NewSearch" session xml-string)))
|
2008-07-26 18:55:02 +00:00
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; Let us notify for relevant signals. We ignore "HitsRemoved",
|
|
|
|
|
;; "HitsModified" and "StateChanged"; there is nothing to do for
|
|
|
|
|
;; us.
|
|
|
|
|
(dbus-register-signal
|
|
|
|
|
:session service xesam-path-search
|
|
|
|
|
xesam-interface-search "HitsAdded"
|
|
|
|
|
'xesam-signal-handler search)
|
|
|
|
|
(dbus-register-signal
|
|
|
|
|
:session service xesam-path-search
|
|
|
|
|
xesam-interface-search "SearchDone"
|
|
|
|
|
'xesam-signal-handler search)
|
2008-07-26 18:55:02 +00:00
|
|
|
|
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; Create the search buffer.
|
|
|
|
|
(with-current-buffer
|
|
|
|
|
(generate-new-buffer (xesam-buffer-name service search))
|
|
|
|
|
(switch-to-buffer-other-window (current-buffer))
|
|
|
|
|
(xesam-mode)
|
|
|
|
|
(setq xesam-engine engine
|
|
|
|
|
xesam-search search
|
2008-07-31 19:30:14 +00:00
|
|
|
|
;; `xesam-type', `xesam-query' and `xesam-xml-string'
|
|
|
|
|
;; are displayed in the header line.
|
|
|
|
|
xesam-type (symbol-name type)
|
|
|
|
|
xesam-query query
|
|
|
|
|
xesam-xml-string xml-string
|
2008-08-05 19:49:17 +00:00
|
|
|
|
xesam-objects nil
|
2008-07-26 18:55:02 +00:00
|
|
|
|
;; The buffer identification shall indicate the search
|
|
|
|
|
;; engine. The `help-echo' property is used for debug
|
|
|
|
|
;; information, when applicable.
|
2008-07-24 21:45:01 +00:00
|
|
|
|
mode-line-buffer-identification
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(if (not xesam-debug)
|
|
|
|
|
(list
|
|
|
|
|
12 (propertized-buffer-identification
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(xesam-get-cached-property engine "vendor.id")))
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(propertize
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(xesam-get-cached-property engine "vendor.id")
|
|
|
|
|
'help-echo
|
2008-07-26 18:55:02 +00:00
|
|
|
|
(mapconcat
|
2008-08-01 18:56:08 +00:00
|
|
|
|
'(lambda (x)
|
|
|
|
|
(format "%s: %s" x (xesam-get-cached-property engine x)))
|
2008-07-26 18:55:02 +00:00
|
|
|
|
'("vendor.id" "vendor.version" "vendor.display" "vendor.xesam"
|
|
|
|
|
"vendor.ontology.fields" "vendor.ontology.contents"
|
|
|
|
|
"vendor.ontology.sources" "vendor.extensions"
|
|
|
|
|
"vendor.ontologies" "vendor.maxhits")
|
2008-07-31 19:30:14 +00:00
|
|
|
|
"\n"))))
|
2008-08-05 19:49:17 +00:00
|
|
|
|
(add-hook 'kill-buffer-hook 'xesam-kill-buffer-function)
|
|
|
|
|
(force-mode-line-update))
|
2008-07-31 19:30:14 +00:00
|
|
|
|
|
|
|
|
|
;; Start the search.
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(xesam-dbus-call-method
|
2008-07-31 19:30:14 +00:00
|
|
|
|
:session (car engine) xesam-path-search
|
|
|
|
|
xesam-interface-search "StartSearch" search)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
;; Return search id.
|
|
|
|
|
search))
|
|
|
|
|
|
|
|
|
|
(defun xesam-search (engine query)
|
|
|
|
|
"Perform an interactive search.
|
|
|
|
|
ENGINE is the Xesam search engine to be applied, it must be one of the
|
|
|
|
|
entries of `xesam-search-engines'. QUERY is the search string in the
|
|
|
|
|
Xesam user query language. If the search engine does not support
|
|
|
|
|
the Xesam user query language, a Xesam fulltext search is applied.
|
|
|
|
|
|
|
|
|
|
The default search engine is the first entry in `xesam-search-engines'.
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
|
|
(xesam-search (car (xesam-search-engines)) \"emacs\")"
|
|
|
|
|
(interactive
|
|
|
|
|
(let* ((vendors (mapcar
|
2008-08-01 18:56:08 +00:00
|
|
|
|
'(lambda (x) (xesam-get-cached-property x "vendor.display"))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(xesam-search-engines)))
|
|
|
|
|
(vendor
|
|
|
|
|
(if (> (length vendors) 1)
|
|
|
|
|
(completing-read
|
|
|
|
|
"Enter search engine: " vendors nil t
|
|
|
|
|
(try-completion "" vendors) 'xesam-minibuffer-vendor-history)
|
|
|
|
|
(car vendors))))
|
|
|
|
|
(list
|
|
|
|
|
;; ENGINE.
|
|
|
|
|
(when vendor
|
|
|
|
|
(dolist (elt (xesam-search-engines) engine)
|
2008-08-01 18:56:08 +00:00
|
|
|
|
(when (string-equal
|
|
|
|
|
(xesam-get-cached-property elt "vendor.display") vendor)
|
2008-07-24 21:45:01 +00:00
|
|
|
|
(setq engine elt))))
|
|
|
|
|
;; QUERY.
|
|
|
|
|
(when vendor
|
|
|
|
|
(read-from-minibuffer
|
|
|
|
|
"Enter search string: " nil nil nil
|
|
|
|
|
'xesam-minibuffer-query-history)))))
|
|
|
|
|
|
2008-07-31 19:30:14 +00:00
|
|
|
|
(if (null engine)
|
|
|
|
|
(message "No search engine running")
|
|
|
|
|
(if (zerop (length query))
|
|
|
|
|
(message "No query applied")
|
|
|
|
|
(xesam-new-search engine xesam-query-type query))))
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
(provide 'xesam)
|
|
|
|
|
|
|
|
|
|
;;; TODO:
|
|
|
|
|
|
2008-08-05 19:49:17 +00:00
|
|
|
|
;; * Accept input while retrieving prefetched hits. `run-at-time'?
|
2008-08-01 18:56:08 +00:00
|
|
|
|
;; * With prefix, let's choose search engine.
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; * Minibuffer completion for user queries.
|
2008-07-26 18:55:02 +00:00
|
|
|
|
;; * `revert-buffer-function' implementation.
|
|
|
|
|
;;
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;; * Mid term
|
|
|
|
|
;; - If available, use ontologies for field selection.
|
|
|
|
|
;; - Search engines for Emacs bugs database, wikipedia, google,
|
|
|
|
|
;; yahoo, ebay, ...
|
2008-08-05 19:49:17 +00:00
|
|
|
|
;; - Construct complex queries via widgets, like in mairix.el.
|
2008-07-24 21:45:01 +00:00
|
|
|
|
|
2008-07-24 23:46:50 +00:00
|
|
|
|
;; arch-tag: 7fb9fc6c-c2ff-4bc7-bb42-bacb80cce2b2
|
2008-07-24 21:45:01 +00:00
|
|
|
|
;;; xesam.el ends here
|