diff options
-rw-r--r-- | dot_emacs.d/local/dictem/AUTHORS | 2 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/COPYING | 3 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/NEWS | 252 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/README | 558 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/TODO | 6 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/dictem-elisp.el | 102 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/dictem-lingvo-dsl.el | 67 | ||||
-rw-r--r-- | dot_emacs.d/local/dictem/dictem.el | 2028 |
8 files changed, 3018 insertions, 0 deletions
diff --git a/dot_emacs.d/local/dictem/AUTHORS b/dot_emacs.d/local/dictem/AUTHORS new file mode 100644 index 0000000..b4dd7b6 --- /dev/null +++ b/dot_emacs.d/local/dictem/AUTHORS @@ -0,0 +1,2 @@ +Mon, 20 Oct 2003 20:40:46 +0300 +DictEm was written by Aleksey Cheusov <vle@gmx.net> diff --git a/dot_emacs.d/local/dictem/COPYING b/dot_emacs.d/local/dictem/COPYING new file mode 100644 index 0000000..bacce4d --- /dev/null +++ b/dot_emacs.d/local/dictem/COPYING @@ -0,0 +1,3 @@ +GNU GPL 2.0 +http://www.gnu.org/licenses/gpl-2.0.html +http://opensource.org/licenses/gpl-2.0.php diff --git a/dot_emacs.d/local/dictem/NEWS b/dot_emacs.d/local/dictem/NEWS new file mode 100644 index 0000000..46f946b --- /dev/null +++ b/dot_emacs.d/local/dictem/NEWS @@ -0,0 +1,252 @@ +Version 1.0.4, Sat, 25 Aug 2012 23:23:24 +0300 + + - Flag (interactive) was removed from the following functions: + dictem-select-strategy, dictem-select-database, dictem-read-query + and dictem-run. This fixes Debian bug #564251. + +Version 1.0.3, Sun, 22 Jul 2012 13:12:00 +0300 + + - fix: "dictem-get-matches" function returns dictionary names + without ":" in the end. + + - fix. insertion of text produced by "dict" client of by user's + database is always made IN THE END of dictem buffer. This fixes + the problems with hightlighting in match/define mixed results. + + - Fix failure when dictem-use-user-databases-only is t. The problem + was that dictem-last-database variable was initialized + incorrectly. + +Version 1.0.2, Sun, 22 Mar 2009 17:20:12 +0200 + + Another fix in dictem-postprocess-definition-remove-header. + +Version 1.0.1, Fri, 20 Mar 2009 12:43:15 +0200 + + - fix in dictem-postprocess-definition-remove-header. + It wrongly deleted extra line + +Version 1.0.0, Sat, 11 Oct 2008 18:59:15 +0300 + + - Running dictem-initialize everytime your network/internet is up + (if case you have no permanent connection to Internet, + e.g. dial-up, adsl etc.) is a bit annoying. To avoid this dictem + is (re)initialized (if needed) automatically from + dictem-select-strategy and dictem-select-database functions. As + a result, running dictem-initialize in .emacs becomes unnecessary + + - New function (dictem-reinitialize-err) added + + - Minor fix in dictem-initialize-databases-alist function. Now it + returns error data in case of failure, not nil. + (just like dictem-initialize-strategies-alist) + +Version 0.82, Mon, 28 Jan 2008 22:59:07 +0200 + + - FIX for emacs-22 (insert-string is replaced with insert) + - Minor fixes in README + +Version 0.81, Sat, 22 Jul 2006 15:45:53 +0300 + + - dictem-server variable can be equal to nil, in this case + 'dict' command line tool will be called without -h option, i.e. + default _list of servers_ specified in .dictrc (or dict.conf) + will be used. + + dict:///dictionary_name (in dictem-user-databases-alist) also means + that default server list will be used, see Ex.4 for the sample of use. + + - dictem-server variable now defaults to nil, old value was "dict.org". + dictem-strategy-alist and dictem-database-alist also defaults to nil. + +Version 0.8, Mon, Sun, 28 May 2006 00:23:43 +0300 + + - removed: ./configure / make / make install + See installation section in README if you are in trouble + + - added: dictem-exclude-databases variable to disable some databases + from autocompletion menu, see example 15 in README file. + + example for those who uses dict://dict.org: + + (setq dictem-exclude-databases + '("tur-" "afr-" "ara-" "cro-" "cze-" "dan-" "hin-" "hun-" + "iri-" "ita-" "kha-" "lat-" "nld-" "por-" "sco-" "scr-" + "slo-" "swa-" "swe-" "tur-" "rom-" "wel-" + + "-tur" "-afr" "-ara" "-cro" "-cze" "-dan" "-hin" "-hun" + "-iri" "-ita" "-kha" "-lat" "-nld" "-por" "-sco" "-scr" + "-slo" "-swa" "-swe" "-tur" "-rom" "-wel")) + + - errors messages obtained from 'dict' command are printed + in case initialization failure but the constant string. + +Version 0.7, Mon, 3 Apr 2006 15:11:57 +0300 + + - DICTEM can handle dictionaries defined by user. + This allows to use dictem not only for accessing DICT servers, + but also for accesing user's databases. + See Ex.14 in README file for a simple example. + + - added: dictem-client-prog-args-list variable + that keeps a list of additional + arguments to the command line 'dict' client. + This may be helpful in case you use 'dict' wrappers (having additional + options) or new versions of 'dict' program. + + - added: dictem-option-mime variable. + If `t' the OPTION MIME command (see RFC-2229 for details) + will be sent to the DICT server. i.e. 'dict' program + will be run with '-M' option. + As a result server's response will be prepanded with MIME header + followed by a blank line. + Because of bugs in dict -M (dict version < 1.10.3), + dict-1.10.3 or later is STRONGLY recommended. + + MIME-ized content can be postprocessed by functions called from + dictem-postprocess-xxxx hooks. Because the current version of dictem + doesn't contain such kind of functions, this variable should be used + by those who program in Emacs. + Suggestions and code are welcomed as always. + Have a lot of fun ;-) + + - added: dictem-run-show-strategies function, + similar to dictem-run-show-databases. + + - more complete dictem-mode's help string (documentation for dictem mode) + + - new examples of dictem usage in Ex.9 section + + - minor fixes in documentation and README + +Version 0.0.5, Wed, 8 Jun 2005 19:56:56 +0300 + + - new examples in README file: Ex.12-13 + + - `dictem-postprocess-collect-hyperlinks' function + (when added to `dictem-postprocess-definition-hook', + `dictem-postprocess-show-info-hook' or + `dictem-postprocess-show-server-hook' hooks) collects hyperlinks + in the variable `dictem-hyperlinks-alist'. + This variable is used by the function `dictem-hyperlinks-menu' + which implements + the autocompletion-based menu the same way `Info-menu' does. + + "e" is assigned to call the function `dictem-hyperlinks-menu'. + The variable `dictem-hyperlinks-alist' is local to buffer. + + - If `dictem-use-existing-buffer' variable is `t' + and dictem-use-content-history is not nil, + the entire buffer content and (point) + is stored in `dictem-content-history' variable when you click + on hyperlink and thus you can easily return to the previous + buffer by pressing "l" (`dictem-last' function). + + "l" is assigned to function `dictem-last'. + It works just like the button <BACK> in the WEB browsers. + + - added: `dictem-postprocess-definition-remove-header', + function for postprocessing DEFINE buffer. + It is intended to remove header `XXX definition[s] found' + at the beginning of dict's output + and can be added to the hook `dictem-postprocess-definition-hook'. + + - fixes: + `dictem-kill-all-buffers' has been reimplemented for using + `dolist' macros instead of recursion. + Recursion-bases implementation causes dictem to fail + when lots of buffers exist. + Thanks to Juri Linkov for bug reports and lots of suggestions. + + - String that begins hyperlink + is stored in the variable `dictem-hyperlink-beginning', defaults to "{" + String that ends hyperlink + is stored in the variable `dictem-hyperlink-end, defaults to "}" + Function that is called when hyperlink "define" is activated + is stored in the variable `dictem-hyperlink-define-func', + defaults to `dictem-base-define' + + All this stuff may be useful for more complex buffer postprocessing. + Hyperlinks are not always enclosed in '{' and '}' braces. + +Version 0.0.4, Thu, 24 Feb 2005 19:40:24 +0200 + + dictem-default-database (dictem-default-strategy) variables override + value of dictem-last-database (dictem-last-strategy) variable, + i.e. when dictem-default-xxx is set to non-nil + this database (strategy) is always used by default, + otherwise the last used database (strategy) is used. + + All examples in README file are know numbered. + + New examples #10 and #11 in README file. + + By default dictem uses the default query as an initial + input, this may be very useful. + To disable this behaviour set `dictem-empty-initial-input' to `t'. + See (describe-variable 'dictem-empty-initial-input) + and REAME example #11. + + FIXED: `dictem-last-database' keeps "low-level" database name + but the user's virtual one. As a result virtual dictionary + could not be the default one (kept in dictem-last-database or + dictem-default-database variable ). + +Version 0.0.3, Tue, 14 Dec 2004 20:43:34 +0200 + + DictEm has been ported to XEmacs + + Virtual dictionaries can access databases from different DICT servers + + (setq dictem-user-databases-alist + '(("_translate" . ("dict://mova.org/mueller7" + "dict://dict.org:2628/web1913")) + ("_ru-ru" . ("beslov" "dict://mova.org:2628/religion")) + )) + + See README file for more information. + + The following commands can be run non-interactively. + `dictem-run-show-info', `dictem-run-search' and + `dictem-run-define' + + `dictem-next-link' and `dictem-previous-link' skip hyperlinks on + database names. + + Renamed: `dictem-url' to `dictem-make-url' + `link-create-link' to `dictem-create-link' + + DictEm's prompt looks like this: `<string> [<default>]:' + + New default faces + + Lots of README updates. + + A few fixes + +Version 0.0.2, Tue, 30 Nov 2004 16:40:00 +0200 + + added: new function `dictem-kill-all-buffers' killing all dictem buffers. + The key "x" press in dictem buffer use it. + + dictem-postprocess-definition-hyperlinks function: + When a substring {foo|bar} is encountered in a definition, + `foo' is used for highlighting and `bar' is used for subsearch. + + new functions: `dictem-next-link' and `dictem-previous-link' which + set pointer to the next (or previous) hyper link + \M-n and \M-p key + are assigned to `dictem-next-link' and `dictem-previous-link' + When pressing RET (C-m) key on hyper link, subsearch + DICT server is sent a DEFINE command + + added: new customizable variable: `dictem-use-existing-buffer' + which can be used + to use existing dictem buffer instead of creating a new one + for subsearches. This variable is local to buffer. + + Documentation update + +Version 0.0.1, Thu, 08 Jul 2004 13:58:59 +0300 + + first publicly available release diff --git a/dot_emacs.d/local/dictem/README b/dot_emacs.d/local/dictem/README new file mode 100644 index 0000000..c1d6e78 --- /dev/null +++ b/dot_emacs.d/local/dictem/README @@ -0,0 +1,558 @@ +DictEm is a Dictionary protocol client for GNU Emacs. + +It uses a console dict client (http://sf.net/projects/dict) and +implements all functions of the client part of DICT protocol +(RFC-2229, www.dict.org), i.e. looking up words and definitions, +obtaining information about available strategies, provided databases, +information about DICT server etc. + +Unlike dictionary.el +(http://www.myrkr.in-berlin.de/dictionary/index.html) DictEm widely +uses autocompletion that is used for selecting dictionary and search +strategy. Moreover, DictEm provides several hooks which may be used +for buffer postprocessing. For example, inbuilt hyperlinking and +highlighting mechanisms are based on this possibility. Another example +is that information obtained from DICT server that is in HTML, ROFF or +INFO format can be easily viewed by Emacs+DictEm if the user supplies +appropriate conversion functions. Of course DictEm can be differently +configured for different Emacs modes (major, minor or buffer +oriented), that allows modularized access to all data serviced by DICT +servers. This makes it ideal tool for translating articles between a +series of foreign languages, browsing manuals and other tasks +depending on Emacs mode user currently works with. + +Additionally DictEm supports accessing so called virtual dictionaries (a set +of dictionaries provided by DICT server that user prefers to treat as +a single one). + +Yet another feature DictEm provides is a set of useful functions with +a help of which user can extend DictEm functionality such as to define +new search strategies or even provide new functionality such as to use +another sources of data other than DICT servers. + +See below for a set of example configuration and extensions. + +Also DictEm uses customization mechanism provided by Emacs that helps +Emacs users to easily configure DictEm. + +COPYING +============ + +See the file COPYING + +DOWNLOAD +======== + +Latest sources can be downloaded from +http://sourceforge.net/projects/dictem +or +http://freshmeat.net/projects/dictem + +INSTALLATION +============ + +* In order to uncompress dictem tarball run the following. + + tar xfv dictem-x.y.z.tar.gz + + If you read this file, you probably have already done this. + +* Change your current directory to dictem. + + cd dictem-x.y.z + +* Copy *.el file to the directory you want. + + cp *.el /path/to/emacs/el/files + +* Make sure that DICT client named dict + (available at http://sf.net/projects/dict) + is installed on your system. + Console dict client is used by DictEm for accessing the DICT server. + dict-1.9.14 or later is strongly recommended. + If you'll set dictem-option-mime variable to t (read below), + dict-1.10.3 or later MUST be used. + +REPORTING BUGS +============== + + Please send all bug reports and suggestions directly to + Aleksey Cheusov <vle@gmx.net>. + Reporting bugs at sf.net is also good. + + Also note that there exists dict-beta@dict.org mailing list (low + traffic) where you can ask questions about DICT protocol and + software. + +CONFIGURING +============= + +Customization group +------------------- + +Take note, that DictEm defines customization group "dictem". +So, it may be easier for you to customize DictEm by running +M-x customize-group <RET> dictem <RET> + +Manual Configuration +-------------------- + +Ex.1 + +The easiest configuration of dictem may look like this + +; Add to load-path variable a new directory with files of dictem +(add-to-list 'load-path "/path/you/installed/dictem/to") + +; Loading dictem functions +(require 'dictem) + +; Setting the dictionary server hostname. +; This part is optional, if dictem-server is nil (the default value) +; "dict" command line utility will use its ows config file +; ~/.dictrc or PREFIX/etc/dict.conf. +; Keeping dictem-server variable unset is recomended because +; this allows to try _list of_ servers until connection is made, +; see dict(1) for details. +;(setq dictem-server "localhost") +;(setq dictem-server "dict.org") + + +; Setting the dictionary server port. +; Setting dictem-port is usually not necessary because +; most DICT servers use the default port 2628. +;(setq dictem-port "2628") + +; Code necessary to obtain database and strategy list from DICT +; server. As of version 0.90, dictem runs this function from +; dictem-select-database and dictem-select-strategy if an +; initialization was not completed or failed previously, that is +; running dictem-initialize is optional +(dictem-initialize) + +; Assigning hot keys for accessing DICT server + +; SEARCH = MATCH + DEFINE +; Ask for word, database and search strategy +; and show definitions found +(global-set-key "\C-cs" 'dictem-run-search) + +; MATCH +; Ask for word, database and search strategy +; and show matches found +(global-set-key "\C-cm" 'dictem-run-match) + +; DEFINE +; Ask for word and database name +; and show definitions found +(global-set-key "\C-cd" 'dictem-run-define) + +; SHOW SERVER +; Show information about DICT server +(global-set-key "\C-c\M-r" 'dictem-run-show-server) + +; SHOW INFO +; Show information about the database +(global-set-key "\C-c\M-i" 'dictem-run-show-info) + +; SHOW DB +; Show a list of databases provided by DICT server +(global-set-key "\C-c\M-b" 'dictem-run-show-databases) + +------- +Ex.2 + +There are a few functions that can make dictem look +a bit nicer and be more functional. They should +be added to special hooks like the following. + +; For creating hyperlinks on database names +; and found matches. +; Click on them with mouse-2 +(add-hook 'dictem-postprocess-match-hook + 'dictem-postprocess-match) + +; For highlighting the separator between the definitions found. +; This also creates hyperlink on database names. +(add-hook 'dictem-postprocess-definition-hook + 'dictem-postprocess-definition-separator) + +; For creating hyperlinks in dictem buffer +; that contains definitions. +(add-hook 'dictem-postprocess-definition-hook + 'dictem-postprocess-definition-hyperlinks) + +; For creating hyperlinks in dictem buffer +; that contains information about a database. +(add-hook 'dictem-postprocess-show-info-hook + 'dictem-postprocess-definition-hyperlinks) + +------- +Ex.3 + +If you want to combine some databases in you own "virtual" dictionary, +create them like this + +(setq dictem-user-databases-alist + '(("_en-ru" . ("mueller7" "korolew_en-ru")) + ("_en-en" . ("foldoc" "gcide" "wn")) + ("_ru-ru" . ("beslov" "ushakov" "ozhegov" "brok_and_efr")) + ("_unidoc" . ("susv3" "man" "info" "howto" "rfc")) + )) + +As a result four new special database collections will be created +and new names will appear when +dictem-run function will ask you about database name. + +------- +Ex.4 + +You can even create virtual dictionaries which consist of +databases from different DICT server. +The dict url form dict:///religion means 'dict' command line tool +will be called without -h option, i.e. a list of dictionary servers +from .dictrc (or dict.conf) will be used. + +(setq dictem-user-databases-alist + '(("_en-ru" . ("dict://mova.org/mueller7" + "dict://dict.org:2628/web1913")) + ("_ru-ru" . ("beslov" "dict:///religion")) + )) + +another example: + +(setq dictem-user-databases-alist + `(("en-en" . ("dict://dict.org:2628/english")) + ("en-ru" . ("dict:///en-ru" + "dict://dict.org:2628/eng-rus" + )) + )) + +------- +Ex.5 + +If your DICT server provides too many databases and most of which +are of no interest for you, you can disable them +and use only those specified in dictem-user-databases-alist variable. + +(setq dictem-use-user-databases-only t) + +------- +Ex.6 + +Of course, you can assign your own key bindings in dictem buffer + +(define-key dictem-mode-map [tab] 'dictem-next-link) +(define-key dictem-mode-map [(backtab)] 'dictem-previous-link) + +------- +Ex.7 + +You are not limited to the default DICT server only. +The following code will allow you to access any server you want. +You'll be asked for host and port. + +; DEFINE +(global-set-key + "\C-c\M-d" + '(lambda () + (interactive) + (save-dictem + (let* ((dictem-server (read-string "server: " + dictem-server nil "dict.org")) + (dictem-port (read-string "port: " + (dictem-get-port) nil "2628"))) + (dictem-initialize) + (call-interactively 'dictem-run-define))))) + +; MATCH +(global-set-key + "\C-c\M-m" + '(lambda () + (interactive) + (save-dictem + (let* ((dictem-server (read-string "server: " + dictem-server nil "dict.org")) + (dictem-port (read-string "port: " + (dictem-get-port) nil "2628"))) + (dictem-initialize) + (call-interactively 'dictem-run-match))))) + +; SEARCH = MATCH+DEFINE +(global-set-key + "\C-c\M-s" + '(lambda () + (interactive) + (save-dictem + (let* ((dictem-server (read-string "server: " + dictem-server nil "dict.org")) + (dictem-port (read-string "port: " + (dictem-get-port) nil "2628"))) + (dictem-initialize) + (call-interactively 'dictem-run-search))))) + +; SHOW INFO +(global-set-key + "\C-c\M-i" + '(lambda () + (interactive) + (save-dictem + (let* ((dictem-server (read-string "server: " + dictem-server nil "dict.org")) + (dictem-port (read-string "port: " + (dictem-get-port) nil "2628"))) + (dictem-initialize) + (call-interactively 'dictem-run-show-info))))) + +; SHOW SERVER +(global-set-key + "\C-c\M-r" + '(lambda () + (interactive) + (save-dictem + (let* ((dictem-server (read-string "server: " + dictem-server nil "dict.org")) + (dictem-port (read-string "port: " + (dictem-get-port) nil "2628"))) + (dictem-initialize) + (call-interactively 'dictem-run-show-server))))) + +------- +Ex.8 + +Some databases may have specially formatted definitions, +for example, HTML, MIME, DICF or ROFF formats. +It is easy to postprocess them. + +; All functions from dictem-postprocess-each-definition-hook +; will be run for each definition which in turn will be narrowed. +; Current database name is kept in dictem-current-dbname variable. +; The following code demonstrates how to highlight SUSV3 and ROFF +; definitions. +(add-hook 'dictem-postprocess-definition-hook + 'dictem-postprocess-each-definition) + +; Function for highlighting definition from the database "susv3". +(defun dictem-highlight-susv3-definition () + (cond ((string= "susv3" dictem-current-dbname) + (goto-char (point-min)) + (while (search-forward-regexp + "^ *[QWERTYUIOPASDFGHJKLZXCVBNM ]+$" nil t) + (put-text-property + (match-beginning 0) (match-end 0) 'face 'bold) + )))) + +; Function to show roff-formatted text from the database "man". +(require 'woman) +(defun dictem-highlight-man-definition () + (cond ((string= "man" dictem-current-dbname) + (goto-char (point-min)) + (while (search-forward-regexp "^ " nil t) + (replace-match "")) + (goto-char (point-min)) + (forward-line 2) + (woman-decode-region (point) (point-max)) + ))) + +(add-hook 'dictem-postprocess-each-definition-hook + 'dictem-highlight-susv3-definition) +(add-hook 'dictem-postprocess-each-definition-hook + 'dictem-highlight-man-definition) + +------- +Ex.9 + +; The dictem's top level function is 'dictem-run'. +; By using it more advanced ELISP programmers +; can create their own search scenaria. Look at this code. + +(dictem-run + 'dictem-base-search + "gcide" "apple" "lev") + +(dictem-run + 'dictem-base-match + "dict://mova.org/mueller7" "apple" "exact") + +(dictem-run + 'dictem-base-define + '("dict://mova.org/mueller7" "dict://dict.org/gcide") + "apple" "exact") + +(dictem-run 'dictem-base-show-info "dict://dict.org/gcide") + +(let ((dictem-server "localhost")) + (dictem-run + '(lambda (a b c) + (dictem-base-show-strategies nil nil nil) + (dictem-base-show-databases nil nil nil) + (dictem-base-show-server nil nil nil) + ))) + +(dictem-run + '(lambda (a b c) + (dictem-base-define + '("man" "susv3") + (dictem-read-query (thing-at-point 'word)) + nil )) + nil nil) + +(let ((query (dictem-read-query (thing-at-point 'word)))) + (dictem-run + `((lambda (a b c) + (dictem-base-match + '("gcide" "wn") + ,query "exact")) + (lambda (a b c) + (dictem-base-search + '("mueller7" "korolew_en-ru") + ,query "word"))))) + +------- +Ex.10 + +By default dictem remembers the database name and strategy that +was used last time. +The dictem-select-database and dictem-select-strategy functions +will use these values as a default in the minibuffer. +If you dislike this behaviour, set variables +dictem-default-database and/or dictem-default-strategy. + +(add-hook 'c-mode-common-hook + '(lambda () + (interactive) + (make-local-variable 'dictem-default-database) + (setq dictem-default-database "man") + )) + +The example above sets default database to "man" +in C buffers. + +------- +Ex.11 + +As of dictem-0.0.4 dictem-empty-initial-input customizable variable +tells dictem-read-query whether to leave initial input empty or not. +It is `nil' by default. +For emulating behaviour of older releases, set it to `t'. + +(setq dictem-empty-initial-input t) + +------- +Ex. 12 + +By default dictem-postprocess-definition-hyperlinks function +assumes that hyperlinks have the following form: {foo} or {foo|bar}. +Sometimes "{" and "}" characters are general characters +in definitions. The following code changes "{" and "}" for +"{link-beg " and " link-end" respectively +inside definitions obtained from the databases "^infopage-..." + +; new function is used for creating hyperlinks +; which works differently depending on database name +(defun my-dictem-postprocess-definition-hyperlinks () + "Creating hyperlinks according to database name" + (interactive) + (cond ( + ((string-match "^infopage-" dictem-current-dbname) + (let ((dictem-hyperlink-beginning "{link-beg ") + (dictem-hyperlink-end " link-end}") + ) + (dictem-postprocess-definition-hyperlinks))) + (t (dictem-postprocess-definition-hyperlinks))))) + +; definitions from each database are processed separately +(add-hook 'dictem-postprocess-definition-hook + 'dictem-postprocess-each-definition) +(add-hook 'dictem-postprocess-each-definition-hook + 'my-dictem-postprocess-definition-hyperlinks) + +------- +Ex. 13 + +You may want to remove "XXX definition[s] found" header +from the DEFINE buffers. +It may be done with a help of +dictem-postprocess-definition-remove-header function. + +(add-hook 'dictem-postprocess-definition-hook + 'dictem-postprocess-definition-remove-header) + +------- +Ex. 14 + +As of version 0.7 dictem can handle dictionaries defined by user. +This allows to use dictem not only for accessing DICT servers, +but also for accesing users' databases. + +; DEFINE function for the database "mysuperdb" +(defun dictem-mysuperdb-DEFINE (query) + (cond + ((string= query "apple") '("Apples grow on the trees" + "Apple may be green, yellow or red")) + ((string= query "potato") '("Potato is a vegetable" + "Potato is a traditional Belarusian food")) + (t (dictem-make-error + 20 (format "No definitions for %s" query))) + )) + +; MATCH function for the database "mysuperdb" +(defun dictem-mysuperdb-MATCH (query strategy) + ; the name of strategy is ignored + (let ((apple (string-match query "apple")) + (potato (string-match query "potato"))) + (cond + ((and (string= strategy "exact") (string= query "apple")) + '("apple")) + ((and (string= strategy "exact") (string= query "potato")) + '("potato")) + ((and apple potato) + '("apple" "potato")) + (apple + '("apple")) + (potato + '("potato")) + (t (dictem-make-error + 20 (format "No matches for %s/%s" query strategy))) + ))) + +; Initializing a list of user-defined databases +(setq dictem-user-databases-alist + `(("_en-en" . ("foldoc" "gcide" "wn")) + ("_ru-ru" . ("beslov" "ushakov" "ozhegov" "brok_and_efr")) + ,(dictem-make-userdb + ; the name of the database + "mysuperdb" + ; short description + "My super database" + ; MATCH function + (symbol-function 'dictem-mysuperdb-MATCH) + ; DEFINE function + (symbol-function 'dictem-mysuperdb-DEFINE)) + )) + +------- +Ex. 15 + +Last years many dictionary servers provide too many bilingual dictionaries, +most of which may be not very interesting for you. +DictEm allows to exclude such dictionaries from an autocompletion menu +by setting a list of regular expressions in dictem-exclude-databases +variable. +If, for example, you don't speak french and german and use +dict://dict.org server, your config may look like this + +(setq dictem-server "dict.org") +(setq dictem-exclude-databases '("ger-" "-ger" "fra-" "-fra")) +(dictem-initialize) + +Note that, (dictem-initialize) is placed after initializing +dictem-exclude-databases variable. + +------- +If you have read to this point and all the examples above seem easy, +you are probably a ELISP Guru. +So, I have nothing more to tell you ;-) +Feel free to inspect the code, and I hope you'll find DictEm useful. + +Dict'em All! ;-) diff --git a/dot_emacs.d/local/dictem/TODO b/dot_emacs.d/local/dictem/TODO new file mode 100644 index 0000000..38b7ccf --- /dev/null +++ b/dot_emacs.d/local/dictem/TODO @@ -0,0 +1,6 @@ +- "er" dictionary + geek +- antonym for "l". "n" and "p"? +- keep p/n history in buffers with numbers. +- does dictem-use-existing-buffer work properly? + +Do you have ideas, want new features, see bugs? Let me know ;-) diff --git a/dot_emacs.d/local/dictem/dictem-elisp.el b/dot_emacs.d/local/dictem/dictem-elisp.el new file mode 100644 index 0000000..7ee6cbc --- /dev/null +++ b/dot_emacs.d/local/dictem/dictem-elisp.el @@ -0,0 +1,102 @@ +(require 'dictem) + +(defun dictem-elisp-variable-documentation (func) + (let* ((help-buffer "*Help*") + (temp-buffer-show-function (lambda (b) ())) + ) + (if (boundp func) + (save-excursion + (describe-variable func) + (set-buffer help-buffer) + (prog1 + (buffer-substring (point-min) (point-max)) + (kill-this-buffer help-buffer)) + ) + nil))) + +(defun dictem-elisp-function-documentation (func) + (let* ((help-buffer "*Help*") + (temp-buffer-show-function (lambda (b) ())) + ) + (if (functionp func) + (save-excursion + (describe-function func) + (set-buffer help-buffer) + (prog1 + (buffer-substring (point-min) (point-max)) + (kill-this-buffer)) + ) + nil))) + +(defun dictem-elisp-DEFINE (query) + (let ((sym (intern-soft query)) + (doc nil)) +; (ret (if (and sym (functionp sym)) +; (documentation sym) +; nil))) + (cond ((null sym) + (dictem-make-error + 20 (format "SYmbol '%s is not defined" query))) + ((functionp sym) + (setq doc (dictem-elisp-function-documentation sym)) + (if doc doc + (dictem-make-error + 20 (format "'%s is not documented as a function" query)))) + (t + (setq doc (dictem-elisp-function-documentation sym)) + (if doc doc + (dictem-make-error + 20 (format "'%s is documented as neither function not variable" query))) + )))) +; (documentation sym)) +; (t (dictem-make-error +; 20 (format "There is no function '%s" query)))))) + +(defun dictem-string-match-prefix (pattern string) + (eq 0 (string-match (regexp-quote pattern) string))) +(defun dictem-string-match-substring (pattern string) + (string-match (regexp-quote pattern) string)) +(defun dictem-string-match-suffix (pattern string) + (string-match (regexp-quote pattern) string) + (= (length string) (match-end 0))) +(defun dictem-string-match-word (pattern string) + (string-match (concat "\\b\\(" (regexp-quote pattern) "\\)\\b") + string)) + +(defun dictem-elisp-MATCH-UNI (query fun) + (let ((i 0) + (l nil) +; (re (regexp-quote query)) + (item nil)) + (while (< i (length obarray)) + (progn + (setq item (symbol-name (elt obarray i))) + (if (funcall fun (regexp-quote query) item) + (setq l (cons item l))) + (setq i (+ i 1)))) + l)) + +(defun dictem-elisp-MATCH (query strategy) + (let ((l (dictem-elisp-MATCH-UNI + query + (cond ((string= strategy "exact") + (symbol-function 'string=)) + ((string= strategy "word") + (symbol-function 'dictem-string-match-word)) + ((string= strategy "prefix") + (symbol-function 'dictem-string-match-prefix)) + ((string= strategy "suffix") + (symbol-function 'dictem-string-match-suffix)) + ((string= strategy "substring") + (symbol-function 'dictem-string-match-substring)))))) + (if l l + (dictem-make-error + 20 (format "No matches for %s/%s" query strategy))))) + +;(dictem-elisp-MATCH "at" "word") +;(dictem-elisp-MATCH "file" "suffix") +;(dictem-elisp-MATCH "dictem" "prefix") +;(dictem-elisp-MATCH "s-s" "substring") +;(dictem-elisp-MATCH "pike" "substring") + +(provide 'dictem-elisp) diff --git a/dot_emacs.d/local/dictem/dictem-lingvo-dsl.el b/dot_emacs.d/local/dictem/dictem-lingvo-dsl.el new file mode 100644 index 0000000..35f92d5 --- /dev/null +++ b/dot_emacs.d/local/dictem/dictem-lingvo-dsl.el @@ -0,0 +1,67 @@ +;; -*- coding: utf-8; -*- + +(require 'dictem) + +(defun dictem-lingvo-dsl-highlight () + ; trn/ex/com/* + (goto-char (point-min)) + (while (search-forward-regexp "\\[/?trn\\]\\|\\[/?p\\]\\|\\[/?c\\]\\|\\[/?com\\]\\|\\[/?[*]\\]\\|\\[/?b\\]\\|\\[/?i\\]\\|\\[/?m[0-9]?\\]\\|\\[/?ex\\]" nil t) + (replace-match "" t t)) + + ; [ex] [/ex] +; (goto-char (point-min)) +; (while (search-forward-regexp "\\[ex\\]\\([][]*\\)\\[/ex\\]" nil t) +; (add-text-properties (match-beginning 0) (match-end 0) +; '(face dictem-lingvo-dsl-example-face)) +; (let* ((beg (match-beginning 1)) +; (end (match-end 1)) +; (repl (buffer-substring beg end))) +; (replace-match repl 1 1))) + + ; <<>> + (goto-char (point-min)) + (while (search-forward-regexp "\\(<<\\|\\[ref\\]\\)\\([^\n]*\\)\\(>>\\|\\[/ref\\]\\)" nil t) + (let* ((beg (match-beginning 2)) + (end (match-end 2)) + (repl (buffer-substring beg end))) + (replace-match (concat "{" repl "}") t t))) + + ; hyperlinks + (dictem-postprocess-definition-hyperlinks) + ) + +(progn + (set-buffer "*dsl-buffer*") + (dictem-lingvo-dsl-highlight)) + +(defface dictem-lingvo-dsl-italic-face + '((((background light)) (:italic true)) + (((background dark)) (:italic true))) + "Face for italic" + ) + +(defface dictem-lingvo-dsl-color-face + '((((background light)) (:italic true)) + (((background dark)) (:italic true))) + "Face for color" + ) + +(defface dictem-lingvo-dsl-example-face + '((((background light)) (:italic true)) + (((background dark)) (:italic true))) + "Face for color" + ) + +(defface dictem-lingvo-dsl-bold-face + '((((background light)) (:bold true)) + (((background dark)) (:bold true))) + "Face for bold" + ) + +(defface dictem-lingvo-dsl-trn-face + '((((background light)) (:bold true :italic true)) + (((background dark)) (:bold true :italic true))) + "Face for trn" + ) + +(provide 'dictem-lingvo-dsl) diff --git a/dot_emacs.d/local/dictem/dictem.el b/dot_emacs.d/local/dictem/dictem.el new file mode 100644 index 0000000..8602ca3 --- /dev/null +++ b/dot_emacs.d/local/dictem/dictem.el @@ -0,0 +1,2028 @@ +;;; dictem.el --- DICT protocol client (rfc-2229) for [X]Emacs + +;; This code was initially based on +;; dictionary.el written by Torsten Hilbrich <Torsten.Hilbrich@gmx.net> +;; but now probably doesn't contain original code. +;; Most of the code has been written +;; from scratch by Aleksey Cheusov <vle@gmx.net>, 2004-2008. +;; +;; DictEm is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2 of the License, or +;; (at your option) any later version. +;; +;; DictEm 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 +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA + +;;; Commentary: + +;; DICT protocol client (rfc-2229) for [X]Emacs + +;; NOTE! Documentation is in README file. +;; +;; Latest information about dictem project and sources +;; are available at +;; +;; http://freshmeat.net/projects/dictem +;; http://sourceforge.net/projects/dictem +;; http://mova.org/~cheusov/pub/dictem + +;;; Code: + +(require 'cl) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Custom Things ;;;;; + +(defgroup dictem nil + "Client for accessing the DICT server." + :tag "DictEm" + :group 'help + :group 'hypermedia) + +(defgroup dictem-faces nil + "Face options for dictem DICT client." + :tag "DictEm faces" + :group 'dictem + :group 'faces) + +(defcustom dictem-server nil + "The DICT server" + :group 'dictem + :type '(restricted-sexp :match-alternatives (stringp 'nil))) + +(defcustom dictem-port 2628 + "The port of the DICT server" + :group 'dictem + :type 'number) + +(defcustom dictem-client-prog "dict" + "The command line DICT client. +dictem accesses DICT server through this executable. +dict-1.9.14 or later (or compatible) is strongly recomented." + :group 'dictem + :type 'string) + +(defcustom dictem-client-prog-args-list nil + "A list of additional arguments (strings) passed to dict client. +For example '(\"--some-option\")." + :group 'dictem + :type 'list) + +(defcustom dictem-option-mime nil + "If `t' the OPTION MIME command (see RFC-2229 for details) +will be sent to the DICT server. i.e. \"dict\" program +will be run with \"-M\" option. +As a result server's response will be prepanded with MIME header +followed by a blank line. +Because of bugs in dict -M (version < 1.10.3) utility, +dict-1.10.3 or later is strongly recommended +" + :group 'dictem + :type 'boolean) + +(defcustom dictem-default-strategy nil + "The default search strategy." + :group 'dictem + :type 'string) + +(defcustom dictem-default-database nil + "The default database name." + :group 'dictem + :type 'string) + +(defcustom dictem-user-databases-alist + nil + "ALIST of user's \"virtual\"databases. +Valid value looks like this: +'((\"en-ru\" . (\"mueller7\" \"korolew_en-ru\")) + ((\"en-en\" . (\"foldoc\" \"gcide\" \"wn\"))) + ((\"gazetteer\" . \"gaz\"))) +" + :group 'dictem + :type '(alist :key-type string)) + +(defcustom dictem-exclude-databases + nil + "ALIST of regexps for databases +that will not appear in autocompletion list. +" + :group 'dictem + :type '(alist :key-type string)) + +(defcustom dictem-use-user-databases-only + nil + "If `t', only user's dictionaries from dictem-user-databases-alist +will be used by dictem-select-database" + :group 'dictem + :type 'boolean) + +(defcustom dictem-mode-hook + nil + "Hook run in dictem mode buffers." + :group 'dictem + :type 'hook) + +(defcustom dictem-use-existing-buffer + nil + "If `t' the `dictem-run' function will not create new *dictem* buffer. +Instead, existing buffer will be erased and used to show results. +" + :group 'dictem + :type 'boolean) + +(defcustom dictem-empty-initial-input + nil + "If `t' the `dictem-read-query' leave initial input empty" + :group 'dictem + :type 'boolean) + +(defcustom dictem-use-content-history t + "If not nil and dictem-use-existing-buffer is also not nil, +buffer content and (point) is saved in dictem-content-history variable +when DEFINE hyperlinks are accessed. +It is restored by dictem-last function. +On slow machines it may better to set this variable to nil" + :group 'dictem) + +;;;;; Faces ;;;;; + +(defface dictem-reference-definition-face + '((((background light)) (:foreground "blue")) + (((background dark)) (:foreground "cyan"))) + + "The face that is used for displaying a reference to +a phrase in a DEFINE search." + :group 'dictem-faces) + +(defface dictem-reference-m1-face + '((((background light)) (:foreground "darkgreen")) + (((background dark)) (:foreground "lightblue"))) + + "The face that is used for displaying a reference to +a phrase in a MATCH search." + :group 'dictem-faces) + +(defface dictem-reference-m2-face + '((((background light)) (:foreground "blue")) + (((background dark)) (:bold true :foreground "gray"))) + + "The face that is used for displaying a reference to +a single word in a MATCH search." + :group 'dictem-faces) + +(defface dictem-reference-dbname-face + '((((background light)) (:foreground "darkgreen")) + (((background dark)) (:bold t :foreground "white"))) + + "The face that is used for displaying a reference to database" + :group 'dictem-faces) + +(defface dictem-database-description-face + '((((background light)) (:bold t :foreground "darkblue")) + (((background dark)) (:bold t :foreground "white"))) + + "The face that is used for displaying a database description" + :group 'dictem-faces) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Variables ;;;;; + +(defconst dictem-version "1.0.4" + "DictEm version information.") + +(defvar dictem-strategy-alist + nil + "ALIST of search strategies") + +(defvar dictem-database-alist + nil + "ALIST of databases") + +(defvar dictem-strategy-history + nil + "List of strategies entered from minibuffer") + +(defvar dictem-database-history + nil + "List of database names entered from minibuffer") + +(defvar dictem-query-history + nil + "List of queries entered from minibuffer") + +(defvar dictem-last-database + "*" + "Last used database name") + +(defvar dictem-last-strategy + "." + "Last used strategy name") + +(defvar dictem-mode-map + nil + "Keymap for dictem mode") + +(defvar dictem-temp-buffer-name + "*dict-temp*" + "Temporary dictem buffer name") + +(defvar dictem-current-dbname + nil + "This variable keeps a database name of the definition +currently processed +by functions run from dictem-postprocess-each-definition-hook.") + +(defvar dictem-error-messages + nil + "A list of error messages collected by dictem-run") + +(defvar dictem-hyperlinks-alist + nil + "ALIST of hyperlinks collected from dictem buffer by +the function dictem-postprocess-collect-hyperlinks +(add this function to the hook dictem-postprocess-definition-hook). +This variable is local to buffer") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-prepand-special-strats (l) + (cons '(".") l)) + +(defun dictem-prepand-special-dbs (l) + (cons '("*") (cons '("!") l))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Functions ;;;;;; + +(defmacro save-dictem (&rest funs) + `(let ((dictem-port 2628) + (dictem-server nil) + (dictem-database-alist nil) + (dictem-strategy-alist nil) + (dictem-use-user-databases-only nil) + (dictem-user-databases-alist nil) + ) + (progn ,@funs) + )) + +(defun dictem-client-text () + "Returns a portion of text sent to the server for identifying a client" + (concat "dictem " dictem-version ", DICT client for emacs")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Functions related to userdb ;; + +(defun dictem-make-userdb (name short-name match define) + "Make user database object" + (list name 'dictem-userdb + short-name match define)) + +(defun dictem-userdb-p (obj) + "Returns t if obj is the dictem error object" + (and obj (listp obj) (cdr obj) (listp (cdr obj)) + (eq (cadr obj) 'dictem-userdb))) + +(defun dictem-userdb-member (obj name) + "Extract member from userdb object by its name" + (cond ((dictem-userdb-p obj) + (nth (cdr (assoc name + '(("name" . 0) ("short-name" . 2) + ("match" . 3) ("define" . 4)))) + obj)) + (t (error "Invalid type of argument")))) + +(defun dictem-userdb-DEFINE (buffer db query host port) + (let* ((fun (dictem-userdb-member db "define")) + (name (dictem-userdb-member db "name")) + (sname (dictem-userdb-member db "short-name")) + (ret (save-excursion (funcall fun query))) + (buf (dictem-get-buffer buffer))) + (save-excursion + (set-buffer buf) + (cond ((dictem-error-p ret) +; (insert "From " sname " [" name "]:\n\n" +; (dictem-error-message ret) "\n\n") +; (insert (dictem-error-message ret) "\n") + (insert (dictem-error-message ret) "\n") + (dictem-error-status ret)) + ((null ret) + (insert "No matches found" "\n") + 20) + ((listp ret) + (dolist (definition ret) + (insert "From " sname " [" name "]:\n\n" + (dictem-indent-string definition) "\n\n")) + 0) + ((stringp ret) + (insert "From " sname " [" name "]:\n\n" + (dictem-indent-string ret) "\n\n") + 0) + (t + (error "Invalid type of returned value1")))))) + +(defun dictem-userdb-MATCH (buffer db query strat host port) + (let* ((fun (dictem-userdb-member db "match")) + (name (dictem-userdb-member db "name")) + (ret (save-excursion (funcall fun query strat))) + (buf (dictem-get-buffer buffer))) + (save-excursion + (set-buffer buf) + (cond ((dictem-error-p ret) + (insert (dictem-error-message ret) "\n") + (dictem-error-status ret)) + ((listp ret) + (insert (concat name ":\n")) + (dolist (match ret); (insert (car db) ":\n" )) + (progn + (insert " " match "\n")) + ) + 0) + (t + (error "Invalid type of returned value2")))))) + +(defun dictem-userdb-SEARCH (buffer db query strat host port) + (let* ((funm (dictem-userdb-member db "match")) + (name (dictem-userdb-member db "name")) + (sname (dictem-userdb-member db "short-name")) + (sname nil) + (ret (funcall funm query strat)) + (buf (dictem-get-buffer buffer))) + (save-excursion + (set-buffer buf) + (cond ((dictem-error-p ret) + (insert (dictem-error-message ret) "\n") + (dictem-error-status ret)) + ((listp ret) + (dolist (match ret) + (dictem-userdb-DEFINE buffer db + match host port)) + 0) + (t + (error "Something strange happened")) + )))) + +(defun dictem-userdb-SHOW-INFO (buffer db host port) + (let ((sname (dictem-userdb-member db "short-name")) + (buf (dictem-get-buffer buffer))) + (save-excursion + (set-buffer buf) + (cond ((dictem-error-p sname) + (insert (dictem-error-message sname) "\n") + (dictem-error-status sname)) + ((stringp sname) + (insert sname) + 0) + (t + (error "Something strange happened")) + )))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Functions related to error object ;; + +(defun dictem-make-error (error_status &optional buffer-or-string) + "Creates dictem error object" + (cond + ((stringp buffer-or-string) + (list 'dictem-error error_status buffer-or-string)) + ((bufferp buffer-or-string) + (dictem-make-error + error_status + (save-excursion + (set-buffer buffer-or-string) + (goto-char (point-min)) + (dictem-get-line) + ))) + ((eq nil buffer-or-string) + (list 'dictem-error error_status buffer-or-string)) + (t + (error "Invalid type of argument")) + )) + +(defun dictem-error-p (OBJECT) + "Returns t if OBJECT is the dictem error object" + (and + (not (null OBJECT)) + (listp OBJECT) + (eq (car OBJECT) 'dictem-error) + )) + +(defun dictem-error-message (err) + "Extract error message from dictem error object" + (cond + ((dictem-error-p err) + (nth 2 err)) + (t + (error "Invalid type of argument")) + )) + +(defun dictem-error-status (err) + "Extract error status from dictem error object" + (cond + ((dictem-error-p err) + (nth 1 err)) + (t + (error "Invalid type of argument")) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-collect-matches () + ; nreverse, setcar and nconc are used to reduce a number of cons + (goto-char (point-min)) + (let ((dictem-temp nil)) + (loop + (let ((line (dictem-get-line))) + (if (string-match "^[^ ]+:" line) + (progn + (if (consp dictem-temp) + (setcar (cdar dictem-temp) + (nreverse (cadar dictem-temp)))) + (setq + dictem-temp + (cons + (list + (substring line (match-beginning 0) (- (match-end 0) 1)) + (nreverse + (dictem-tokenize (substring line (match-end 0))))) + dictem-temp))) + (if (consp dictem-temp) + (setcar (cdar dictem-temp) + (nconc (nreverse (dictem-tokenize line)) + (cadar dictem-temp)) + )) + )) + (if (or (> (forward-line 1) 0) + (> (current-column) 0)) + (return (nreverse dictem-temp))) + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-get-buffer (buf) + (cond + ((bufferp buf) buf) + (buf (current-buffer)) + (t (get-buffer-create dictem-temp-buffer-name)) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; call-process functions + +(defun dictem-local-dict-basic-option (host port option-mime) + (let ((server-host (if host host (dictem-get-server)))) + (append + (list "-P" "-") + (if server-host + (list "-h" server-host "-p" (dictem-get-port port))) + (if option-mime '("-M")) + dictem-client-prog-args-list + ))) + +(defun dictem-call-process (buffer host port args) + (let (coding-system + coding-system-for-read + coding-system-for-write) + (if (and (functionp 'coding-system-list) + (member 'utf-8 (coding-system-list))) + (setq coding-system 'utf-8)) + (setq coding-system-for-read coding-system) + (setq coding-system-for-write coding-system) + (apply 'call-process + `(,dictem-client-prog + nil + ,(dictem-get-buffer buffer) + nil + ,@(dictem-local-dict-basic-option host port nil) + ,@args + )))) + +(defun dictem-call-process-SHOW-SERVER (buffer host port) + (dictem-call-process buffer host port '("-I"))) + +(defun dictem-call-process-SHOW-INFO (buffer db host port) + (dictem-call-process buffer host port (list "-i" db))) + +(defun dictem-call-process-SHOW-STRAT (buffer host port) + (dictem-call-process buffer host port '("-S"))) + +(defun dictem-call-process-SHOW-DB (buffer host port) + (dictem-call-process buffer host port '("-D"))) + +(defun dictem-call-process-MATCH (buffer db query strat host port) + (dictem-call-process + buffer host port + (list "-m" + "-d" (if db db "*") + "-s" (if strat strat ".") + query))) + +(defun dictem-call-process-DEFINE (buffer db query host port) + (dictem-call-process + buffer host port + (list "-d" (if db db "*") query))) + +(defun dictem-call-process-SEARCH (buffer db query strat host port) + (dictem-call-process + buffer host port + (list "-d" (if db db "*") + "-s" (if strat strat ".") + query))) + +;;;;; GET Functions ;;;;; + +(defun dictem-get-matches (query &optional database strategy server port) + "Returns ALIST of matches" + (let ((exit_status + (dictem-call-process-MATCH nil database query strategy server port) + )) + (cond + ((= exit_status 20) ;20 means "no matches found", See dict(1) + (kill-buffer dictem-temp-buffer-name) + nil) + ((= exit_status 0) + (progn + (save-excursion + (set-buffer dictem-temp-buffer-name) + (let ((matches (dictem-collect-matches))) + (kill-buffer dictem-temp-buffer-name) + matches)))) + (t + (let + ((err (dictem-make-error exit_status + (get-buffer dictem-temp-buffer-name)))) + (kill-buffer dictem-temp-buffer-name) + err)) + ))) + +(defun dictem-get-strategies (&optional server port) + "Obtains strategy ALIST from a DICT server +and returns alist containing strategies and their descriptions" + (let ((exit_status + (dictem-call-process-SHOW-STRAT nil server port) + )) + (cond + ((= exit_status 0) + (save-excursion + (set-buffer dictem-temp-buffer-name) + (goto-char (point-min)) + (let ((regexp "^ \\([^ ]+\\) +\\(.*\\)$") + (l nil)) + (while (search-forward-regexp regexp nil t) + (setq l (cons + (list + (buffer-substring-no-properties + (match-beginning 1) (match-end 1)) + (buffer-substring-no-properties + (match-beginning 2) (match-end 2))) + l))) + (kill-buffer dictem-temp-buffer-name) + l))) + (t + (let + ((err (dictem-make-error exit_status + (get-buffer dictem-temp-buffer-name)))) + (kill-buffer dictem-temp-buffer-name) + err)) + ))) + +(defun dictem-get-databases (&optional server port) + "Obtains database ALIST from a DICT server +and returns alist containing database names and descriptions" + (let ((exit_status + (dictem-call-process-SHOW-DB nil server port) + )) + (cond + ((= exit_status 0) + (save-excursion + (set-buffer dictem-temp-buffer-name) + (goto-char (point-min)) + (let ((regexp "^ \\([^ ]+\\) +\\(.*\\)$") + (l nil)) + (while (search-forward-regexp regexp nil t) + (let ((dbname (buffer-substring-no-properties + (match-beginning 1) (match-end 1))) + (dbdescr (buffer-substring-no-properties + (match-beginning 2) (match-end 2)))) + (if (not (string= "--exit--" dbname)) + (setq l (cons (list dbname dbdescr) l))))) + (kill-buffer dictem-temp-buffer-name) + l))) + (t + (let + ((err (dictem-make-error exit_status + (get-buffer dictem-temp-buffer-name)))) + (kill-buffer dictem-temp-buffer-name) + err)) + ))) + +(defun dictem-get-default-strategy (&optional def-strat) + "Gets the default search strategy" + (if def-strat + def-strat + (if dictem-default-strategy + dictem-default-strategy + (if dictem-last-strategy + dictem-last-strategy + ".")))) + +(defun dictem-extract-dbname (database) + (cond + ((consp database) (dictem-extract-dbname (car database))) + ((stringp database) database) + (t (error "The database should be either stringp or consp")) + )) + +(defun dictem-get-default-database (&optional def-db) + "Returns the default database" + + (if def-db + (dictem-extract-dbname def-db) + (if dictem-default-database + (dictem-extract-dbname dictem-default-database) + (if dictem-last-database + (dictem-extract-dbname dictem-last-database) + "*")))) + +;;;;; Low Level Functions ;;;;; + +(defun dictem-db-should-be-excluded (dbname) + "Returns t if a dbname should is not interesting for user. +See dictem-exclude-databases variable" + (let ((ret nil)) + (dolist (re dictem-exclude-databases) + (if (string-match re dbname) + (setq ret t))) + ret)) + +(defun dictem-delete-alist-predicate (l pred) + "makes a copy of l with no items for which (pred item) is true" + (let ((ret nil)) + (dolist (item l) + (if (not (funcall pred (car item))) + (setq ret (cons item ret)))) + ret)) + +(defun dictem-get-line () + "Replacement for (thing-at-point 'line)" + (save-excursion + (buffer-substring-no-properties + (progn (beginning-of-line) (point)) + (progn (end-of-line) (point))))) + +(defun dictem-list2alist (l) + (cond + ((null l) nil) + (t (cons + (list (car l) nil) + (dictem-list2alist (cdr l)))))) + +(defun dictem-indent-string (str) + (let ((start 0)) + (while (string-match "\n" str start) + (progn + (setq start ( + 2 (match-end 0))) + (setq str (replace-match "\n " t t str))))) + (concat " " str)) + +(defun dictem-replace-spaces (str) + (while (string-match "[ \n][ \n]+" str) + (setq str (replace-match " " t t str))) + (if (string-match "^ +" str) + (setq str (replace-match "" t t str))) + (if (string-match " +$" str) + (setq str (replace-match "" t t str))) + str) + +(defun dictem-remove-value-from-alist (l) + (let ((ret nil)) + (dolist (i l) + (setq ret (cons (list (car i)) ret))) + (reverse ret) + )) +;(defun dictem-remove-value-from-alist (l) +; (cond +; ((symbolp l) l) +; (t (cons (list (caar l)) +; (dictem-remove-value-from-alist (cdr l)))))) + +(defun dictem-select (prompt alist default history) + (let* + ((completion-ignore-case t) + (str (completing-read + (concat prompt " [" default "]: ") + alist nil t nil history default)) + (str-cons (assoc str alist))) + (cond + ((and str-cons (consp str-cons) (cdr str-cons)) + str-cons) + ((and str-cons (consp str-cons)) + (car str-cons)) + (t nil)))) + +(defun dictem-tokenize (s) + (if (string-match "\"[^\"]+\"\\|[^ \"]+" s ) +; (substring s (match-beginning 0) (match-end 0)) + (cons (substring s (match-beginning 0) (match-end 0)) + (dictem-tokenize (substring s (match-end 0)))) + nil)) + +;(defun dictem-search-forward-regexp-cs (REGEXP &optional BOUND NOERROR COUNT) +; "Case-sensitive variant for search-forward-regexp" +; (let ((case-replace nil) +; (case-fold-search nil)) +; (search-forward-regexp REGEXP BOUND NOERROR COUNT))) + +;(defun dictem-replace-match-cs (NEWTEXT &optional FIXEDCASE LITERAL STRING SUBEXP) +; "Case-sensitive variant for replace-match" +; (let ((case-replace nil) +; (case-fold-search nil)) +; (replace-match NEWTEXT FIXEDCASE LITERAL STRING SUBEXP))) + +(defun dictem-get-port (&optional port) + (let ((p (if port port dictem-port))) + (cond + ((and (stringp p) (string= "" p)) 2628) + ((null p) 2628) + ((stringp p) p) + ((numberp p) (number-to-string p)) + (t (error "The value of dictem-port variable should be \ +either a string or a number")) + ))) + +(defun dictem-get-server () + (cond + ((and (stringp dictem-server) (string= "" dictem-server)) nil) + ((stringp dictem-server) dictem-server) + ((null dictem-server) nil) + (t (error "The value of dictem-server variable should be \ +either a string or a nil")) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Main Functions ;;;;; + +;;;;;; Functions for Initializing ;;;;;; + +(defun dictem-initialize-strategies-alist (&optional server port) + "Obtain strategy ALIST from a DICT server +and sets dictem-strategy-alist variable." + (interactive) + (setq dictem-strategy-alist (dictem-get-strategies + server + (dictem-get-port port)))) + +(defun dictem-initialize-databases-alist (&optional server port) + "Obtain database ALIST from a DICT server +and sets dictem-database-alist variable." + (interactive) + (setq dictem-database-alist + (dictem-get-databases server (dictem-get-port port))) + (if (dictem-error-p dictem-database-alist) + dictem-database-alist + (setq dictem-database-alist + (dictem-delete-alist-predicate + dictem-database-alist + 'dictem-db-should-be-excluded)))) + +(defun dictem-initialize () + "Initializes dictem, i.e. obtains +a list of available databases and strategiss from DICT server +and makes other tasks." + (interactive) + (let ((dbs (dictem-initialize-databases-alist)) + (strats (dictem-initialize-strategies-alist))) + (if (dictem-error-p dbs) + dbs strats))) + +(defun dictem-reinitialize-err () + "Initializes dictem if it is not initialized yet +and run (error ...) if an initialization fails" + (interactive) + (if (or (dictem-error-p dictem-database-alist) + (null dictem-database-alist)) + (if (dictem-error-p (dictem-initialize)) + (error (dictem-error-message dictem-database-alist))))) + +;;; Functions related to Minibuffer ;;;; + +(defun dictem-select-strategy (&optional default-strat) + "Switches to minibuffer and asks the user +to enter a search strategy." + (dictem-reinitialize-err) + (dictem-select + "strategy" + (dictem-prepand-special-strats + (dictem-remove-value-from-alist dictem-strategy-alist)) + (dictem-get-default-strategy default-strat) + 'dictem-strategy-history)) + +(defun dictem-select-database (spec-dbs user-dbs &optional default-db) + "Switches to minibuffer and asks user +to enter a database name." + (dictem-reinitialize-err) + (let* ((dbs (dictem-remove-value-from-alist dictem-database-alist)) + (dbs2 (if user-dbs + (if dictem-use-user-databases-only + dictem-user-databases-alist + (append dictem-user-databases-alist dbs) + ) + dbs))) + (dictem-select + "db" + (if spec-dbs (dictem-prepand-special-dbs dbs2) dbs2) + (dictem-get-default-database default-db) + 'dictem-database-history))) + +(defun dictem-read-query (&optional default-query) + "Switches to minibuffer and asks user to enter a query." + (if (featurep 'xemacs) + (read-string + (concat "query [" default-query "]: ") + nil 'dictem-query-history default-query) + (read-string + (concat "query [" default-query "]: ") + (if dictem-empty-initial-input nil default-query) + 'dictem-query-history default-query t))) + + +;;;;;;;; Hooks ;;;;;;;; + +(defcustom dictem-postprocess-definition-hook + nil + "Hook run in dictem mode buffers containing DEFINE result." + :group 'dictem + :type 'hook + :options '(dictem-postprocess-definition-separator + dictem-postprocess-definition-hyperlinks + dictem-postprocess-each-definition + dictem-postprocess-definition-remove-header + dictem-postprocess-collect-hyperlinks)) + +(defcustom dictem-postprocess-match-hook + nil + "Hook run in dictem mode buffers containing MATCH result." + :group 'dictem + :type 'hook + :options '(dictem-postprocess-match)) + +(defcustom dictem-postprocess-show-info-hook + nil + "Hook run in dictem mode buffers containing SHOW INFO result." + :group 'dictem + :type 'hook + :options '(dictem-postprocess-definition-hyperlinks + dictem-postprocess-collect-hyperlinks)) + +(defcustom dictem-postprocess-show-server-hook + nil + "Hook run in dictem mode buffers containing SHOW SERVER result." + :group 'dictem + :type 'hook) + +;;;;;;;; Search Functions ;;;;;;; + +(defun dictem-call-dict-internal (fun databases) + (let ((exit-status -1)) + (cond + ((null databases) 0) + ((stringp databases) + (dictem-call-dict-internal fun (list databases))) + ((listp databases) + (dolist (db databases) + (let ((ex_st (funcall fun db))) + (cond + ((= ex_st 0) + (setq exit-status 0)) + (t (if (/= 0 exit-status) + (setq exit-status ex_st))) + ))) + (if (= exit-status -1) 0 exit-status) + ) + (t (error "wrong type of argument")) + ) + )) + +;(defun dictem-call-dict-internal (fun databases) +; (dolist (db databases) +; (funcall fun db))) +; (funcall fun databases)) + +(defun dictem-make-url (host port database cmd_sign query &optional strategy) + "Returns dict:// URL" + (concat + "dict://" host ":" + (dictem-get-port (if port port "2628")) + "/" cmd_sign ":" query ":" database + (if strategy (concat ":" (if strategy strategy "."))) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-base-do-selector (cmd hook &optional database &rest args) + (let* ((splitted-url nil) + (databases nil) + (user-db (assoc database dictem-user-databases-alist)) + ) + (goto-char (point-max)) + (cond ((dictem-userdb-p database) + (apply 'dictem-base-do-default-server + (append (list cmd hook database) args))) + + ((and database (listp database)) + (dictem-call-dict-internal + `(lambda (db) + (apply 'dictem-base-do-selector + (append (list ,cmd hook db) args))) + (cdr database)) + (setq dictem-last-database (car database))) + + ((and database (stringp database) + (setq splitted-url (dictem-parse-url database))) + (apply 'dictem-base-do-foreign-server + (append + (list cmd hook + (nth 1 splitted-url) + (dictem-get-port (nth 2 splitted-url)) + (nth 3 splitted-url)) + args))) + + (user-db + (let ((exit_status + (apply 'dictem-base-do-selector + (append + (list cmd hook user-db) args)))) + (progn + (setq dictem-last-database database) + exit_status) + )) + + (t + (apply 'dictem-base-do-default-server + (append (list cmd hook database) args))) + ))) + +(defun dictem-base-do-foreign-server (cmd hook server port database &rest args) + (let ((dictem-last-database nil) + (dictem-last-strategy nil)) + (save-dictem (setq dictem-server server) + (setq dictem-port port) + (setq database database) + (dictem-initialize) + (apply 'dictem-base-do-default-server + (append (list cmd hook database) args)) + ))) + +(defun dictem-base-do-default-server (cmd hook + &optional database query strategy) + (let* ((beg (point)) + (fun (if (dictem-userdb-p database) + (dictem-cmd2userdb cmd) + (dictem-cmd2function cmd))) + + (exit_status + (save-excursion (apply fun (append (list t) + (if database (list database)) + (if query (list query)) + (if strategy (list strategy)) + (list nil) (list nil)))) + )) + + (cond ((= 0 exit_status) + (save-excursion + (narrow-to-region beg (point-max)) + (run-hooks hook) + (widen))) + ((= 21 exit_status) + (save-excursion + (narrow-to-region beg (point-max)) + (run-hooks 'dictem-postprocess-match-hook) + (widen))) + (t + (if (/= beg (point)) + (setq dictem-error-messages + (append + (list + (dictem-make-url (dictem-get-server) + (dictem-get-port) database "?" query) + (buffer-substring-no-properties beg (point))) + dictem-error-messages))) + (kill-region beg (point)))) + + (if database (setq dictem-last-database database)) + (if strategy (setq dictem-last-strategy strategy)) + exit_status + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-base-search (databases query strategy) + "MATCH + DEFINE commands" + + (dictem-base-do-selector + "search" + 'dictem-postprocess-definition-hook + databases query strategy)) + +(defun dictem-base-define (databases query c) + "DEFINE command" + + (dictem-base-do-selector + "define" + 'dictem-postprocess-definition-hook + databases query)) + +(defun dictem-base-match (databases query strategy) + "MATCH command" + + (dictem-base-do-selector + "match" + 'dictem-postprocess-match-hook + databases query strategy)) + +(defun dictem-base-show-databases (a b c) + "SHOW DB command" + + (dictem-base-do-selector + "show-db" + nil)) + +(defun dictem-base-show-strategies (a b c) + "SHOW STRAT command" + + (dictem-base-do-selector + "show-strat" + nil)) + +(defun dictem-base-show-info (databases b c) + "SHOW INFO command" + + (dictem-base-do-selector + "show-info" + 'dictem-postprocess-show-info-hook + databases)) + +(defun dictem-base-show-server (a b c) + "SHOW SERVER command" + + (dictem-base-do-selector + "show-server" + 'dictem-postprocess-show-server-hook)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-get-error-message (exit_status) + (cond + ((= exit_status 0) "All is fine") + ((= exit_status 20) "No matches found") + ((= exit_status 21) "Approximate matches found") + ((= exit_status 22) "No databases available") + ((= exit_status 23) "No strategies available") + + ((= exit_status 30) "Unexpected response code from server") + ((= exit_status 31) "Server is temporarily unavailable") + ((= exit_status 32) "Server is shutting down") + ((= exit_status 33) "Syntax error, command not recognized") + ((= exit_status 34) "Syntax error, illegal parameters") + ((= exit_status 35) "Command not implemented") + ((= exit_status 36) "Command parameter not implemented") + ((= exit_status 37) "Access denied") + ((= exit_status 38) "Authentication failed") + ((= exit_status 39) "Invalid database name") + ((= exit_status 40) "Invalid strategy name") + ((= exit_status 41) "Connection to server failed") + (t (concat "Ooops!" (number-to-string exit_status))) + )) + +(defun dictem-local-internal (err-msgs exit_status) + (if err-msgs + (concat (car err-msgs) "\n" + (cadr err-msgs) + "\n" + (dictem-local-internal + (cddr err-msgs) + nil) + ) + (if exit_status + (dictem-get-error-message exit_status) + nil))) + +(defun dictem-generate-full-error-message (exit_status) + + (concat "Error messages:\n\n" + (dictem-local-internal dictem-error-messages exit_status))) + +(defun dictem-run (search-fun &optional database query strategy) + "Creates new *dictem* buffer and run search-fun" + + (let ((ex_status -1)) + + (defun dictem-local-run-functions (funs database query strategy) + (cond + ((functionp funs) + (let ((ex_st (funcall funs database query strategy))) + (if (/= ex_status 0) + (setq ex_status ex_st)))) + ((and (consp funs) (functionp (car funs))) + (dictem-local-run-functions (car funs) database query strategy) + (dictem-local-run-functions (cdr funs) database query strategy)) + ((null funs) + nil) + (t (error "wrong argument type")) + ) + ex_status) + + (let ((selected-window (frame-selected-window)) + ; here we remember values of variables local to buffer + (server dictem-server) + (port dictem-port) + (dbs dictem-database-alist) + (strats dictem-strategy-alist) + (user-dbs dictem-user-databases-alist) + (user-only dictem-use-user-databases-only) + (use-existing-buf dictem-use-existing-buffer) +; (option-mime dictem-option-mime) + (dict-buf nil) + ) + (cond + ((eq dictem-use-existing-buffer 'always) + (dictem-ensure-buffer)) + ((eq dictem-use-existing-buffer t) + (dictem-ensure-buffer)) + (t + (dictem)) + 0) + (setq dict-buf (buffer-name)) +; (set-buffer-file-coding-system coding-system) + (make-local-variable 'dictem-default-strategy) + (make-local-variable 'dictem-default-database) + (make-local-variable 'case-replace) + (make-local-variable 'case-fold-search) + + ; the following lines are to inherit values local to buffer + (set (make-local-variable 'dictem-server) server) + (set (make-local-variable 'dictem-port) port) + (set (make-local-variable 'dictem-database-alist) dbs) + (set (make-local-variable 'dictem-strategy-alist) strats) + (set (make-local-variable 'dictem-user-databases-alist) user-dbs) + (set (make-local-variable 'dictem-use-user-databases-only) user-only) + (set (make-local-variable 'dictem-use-existing-buffer) use-existing-buf) + +; (set (make-local-variable 'dictem-option-mime) option-mime) + + (set (make-local-variable 'dictem-hyperlinks-alist) nil) + + ;;;;;;;;;;;;;; + (setq case-replace nil) + (setq case-fold-search nil) + (setq dictem-error-messages nil) + (dictem-local-run-functions search-fun database query strategy) + (switch-to-buffer dict-buf) + (if (and (not (equal ex_status 0)) (= (point-min) (point-max))) + (insert (dictem-generate-full-error-message ex_status))) + (goto-char (point-min)) + (setq buffer-read-only t) + ex_status + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun dictem-next-section () + "Move point to the next definition" + (interactive) + (forward-char) + (if (search-forward-regexp "^From " nil t) + (beginning-of-line) + (goto-char (point-max)))) + +(defun dictem-previous-section () + "Move point to the previous definition" + (interactive) + (backward-char) + (if (search-backward-regexp "^From " nil t) + (beginning-of-line) + (goto-char (point-min)))) + +(defun dictem-hyperlinks-menu () + "Hyperlinks menu with autocompletion" + (interactive) + (let ((link (completing-read "Go to:" dictem-hyperlinks-alist))) + (if (and link (setq link (assoc link dictem-hyperlinks-alist))) + (dictem-run-define + (cadr link) + dictem-last-database)) + )) + +(defun dictem-next-link () + "Move point to the next hyperlink" + (interactive) + (let ((pt nil) + (limit (point-max))) + (if (and (setq pt (next-single-property-change + (point) 'link nil limit)) + (/= limit pt)) + (if (get-char-property pt 'link) + (goto-char pt) + (goto-char (next-single-property-change pt 'link nil limit)))) + )) + +(defun dictem-previous-link () + "Move point to the previous hyperlink" + (interactive) + (let ((pt nil) + (limit (point-min))) + (if (and (setq pt (previous-single-property-change + (point) 'link nil limit)) + (/= limit pt)) + (if (get-char-property pt 'link) + (goto-char pt) + (goto-char (previous-single-property-change pt 'link nil limit)))) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun dictem-help () + "Display a dictem help" + (interactive) + (describe-function 'dictem-mode)) + +(defun dictem-mode () + "This is a mode for dict client implementing +the protocol defined in RFC 2229. + +The following basic commands are available in the buffer. + + \\[dictem-help] display the help information + + \\[dictem-kill] kill the dictem buffer + \\[dictem-kill-all-buffers] kill all dictem buffers + \\[dictem-quit] bury the dictem buffer + + \\[dictem-last] restore content of the previously visited dictem buffer + + \\[dictem-run-search] make a new SEARCH, i.e. ask for a database, strategy and query + and show definitions + \\[dictem-run-match] make a new MATCH, i.e. ask for database, strategy and query + and show matches + \\[dictem-run-define] make a new DEFINE, i.e. ask for a database and query + and show definitions + \\[dictem-run-show-server] show information about DICT server + \\[dictem-run-show-info] ask for a database and show information about it + \\[dictem-run-show-databases] show databases DICT server provides + \\[dictem-run-show-strategies] show search strategies DICT server provides + + \\[dictem-next-section] move point to the next definition + \\[dictem-previous-section] move point to the previous definition + \\[dictem-next-link] move point to the next hyper link + \\[dictem-previous-link] move point to the previous hyper link + + \\[dictem-hyperlinks-menu] display the menu with hyperlinks + + \\[scroll-up] scroll dictem buffer up + \\[scroll-down] scroll dictem buffer down + \\[dictem-define-on-click] or \\[dictem-define-on-press] visit a link (DEFINE using all dictionaries) + + +Also some advanced commands are available. + + \\[dictem-initialize] Initializes dictem, i.e. obtains +a list of available databases and strategiss from DICT server +and makes other tasks + \\[dictem-initialize-strategies-alist] Obtain strategy ALIST from a DICT server and sets dictem-strategy-alist variable + \\[dictem-initialize-databases-alist] Obtain database ALIST from a DICT server and sets dictem-database-alist variable + + +The following key bindings are currently in effect in the buffer: +\\{dictem-mode-map} +" + + (interactive) + + (kill-all-local-variables) + (buffer-disable-undo) + (use-local-map dictem-mode-map) + (setq major-mode 'dictem-mode) + (setq mode-name "dictem") + + (add-hook 'kill-buffer-hook 'dictem-kill t t) + (run-hooks 'dictem-mode-hook) + ) + +(defvar dictem-window-configuration + nil + "The window configuration to be restored upon closing the buffer") + +(defvar dictem-selected-window + nil + "The currently selected window") + +(defvar dictem-content-history + nil + "A list of lists (buffer_content point)") + +(defconst dictem-buffer-name + "*dictem buffer*") + +(defconst dictem-url-regexp + "^\\(dict\\)://\\([^/:]*\\)\\(:\\([0-9]+\\)\\)?/\\(.*\\)$") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst dictem-cmd2function-alist + '(("show-server" dictem-call-process-SHOW-SERVER) + ("show-info" dictem-call-process-SHOW-INFO) + ("show-strat" dictem-call-process-SHOW-STRAT) + ("show-db" dictem-call-process-SHOW-DB) + ("match" dictem-call-process-MATCH) + ("define" dictem-call-process-DEFINE) + ("search" dictem-call-process-SEARCH) + )) + +(defconst dictem-cmd2userdb-alist + '(("match" dictem-userdb-MATCH) + ("define" dictem-userdb-DEFINE) + ("search" dictem-userdb-SEARCH) + ("show-info" dictem-userdb-SHOW-INFO) + )) + +(defun dictem-cmd2xxx (cmd alist) + (let ((fun (assoc cmd alist))) + (if fun + (symbol-function (cadr fun)) + (error "Unknown command \"%s\"" cmd) + ) + )) + +(defun dictem-cmd2function (cmd) + (dictem-cmd2xxx cmd dictem-cmd2function-alist)) +(defun dictem-cmd2userdb (cmd) + (dictem-cmd2xxx cmd dictem-cmd2userdb-alist)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun dictem-parse-url (url) + "Parses string like dict://dict.org:2628/foldoc +and returns a list containing protocol, server, port and path on nil if fails" + (if (string-match dictem-url-regexp url) + (list + (match-string 1 url) ; protocol + (match-string 2 url) ; host + (match-string 4 url) ; port + (match-string 5 url) ; path (database name for dict://) + ) + nil)) + +(defun dictem () + "Create a new dictem buffer and install dictem-mode" + (interactive) + + (let ( + (buffer (generate-new-buffer dictem-buffer-name)) + (window-configuration (current-window-configuration)) + (selected-window (frame-selected-window))) + (switch-to-buffer-other-window buffer) + (dictem-mode) + + (make-local-variable 'dictem-window-configuration) + (make-local-variable 'dictem-selected-window) + (make-local-variable 'dictem-content-history) + (setq dictem-window-configuration window-configuration) + (setq dictem-selected-window selected-window) + )) + +;(unless dictem-mode-map +(setq dictem-mode-map (make-sparse-keymap)) +(suppress-keymap dictem-mode-map) + +; Kill the buffer +(define-key dictem-mode-map "k" 'dictem-kill) + +; Kill all dictem buffers +(define-key dictem-mode-map "x" 'dictem-kill-all-buffers) + +; Bury the buffer +(define-key dictem-mode-map "q" 'dictem-quit) + +; LAST, works like in Info-mode +(define-key dictem-mode-map "l" 'dictem-last) + +; Show help message +(define-key dictem-mode-map "h" 'dictem-help) + +; SEARCH = MATCH + DEFINE +(define-key dictem-mode-map "s" 'dictem-run-search) + +; MATCH +(define-key dictem-mode-map "m" 'dictem-run-match) + +; DEFINE +(define-key dictem-mode-map "d" 'dictem-run-define) + +; SHOW SERVER +(define-key dictem-mode-map "r" 'dictem-run-show-server) + +; SHOW INFO +(define-key dictem-mode-map "i" 'dictem-run-show-info) + +; Move point to the next DEFINITION +(define-key dictem-mode-map "n" 'dictem-next-section) + +; Move point to the previous DEFINITION +(define-key dictem-mode-map "p" 'dictem-previous-section) + +; Move point to the next HYPER LINK +(define-key dictem-mode-map "\M-n" 'dictem-next-link) + +; Move point to the previous HYPER LINK +(define-key dictem-mode-map "\M-p" 'dictem-previous-link) + +; Hyperlinks menu +(define-key dictem-mode-map "e" 'dictem-hyperlinks-menu) + +; Scroll up dictem buffer +(define-key dictem-mode-map " " 'scroll-up) + +; Scroll down dictem buffer +(define-key dictem-mode-map "\177" 'scroll-down) + +; Define on click +(if (featurep 'xemacs) + (define-key dictem-mode-map [button2] + 'dictem-define-on-click) + (define-key dictem-mode-map [mouse-2] + 'dictem-define-on-click)) + +(define-key dictem-mode-map "\C-m" + 'dictem-define-on-press) + +(defun dictem-mode-p () + "Return non-nil if current buffer has dictem-mode" + (eq major-mode 'dictem-mode)) + +(defun dictem-ensure-buffer () + "If current buffer is not a dictem buffer, create a new one." + (if (dictem-mode-p) + (progn + (if dictem-use-content-history + (setq dictem-content-history + (cons (list (buffer-substring + (point-min) (point-max)) + (point)) dictem-content-history))) + (setq buffer-read-only nil) + (erase-buffer)) + (dictem))) + +(defun dictem-quit () + "Bury the current dictem buffer." + (interactive) + (if (featurep 'xemacs) + (bury-buffer) + (quit-window))) + +(defun dictem-kill () + "Kill the current dictem buffer." + (interactive) + + (if (eq major-mode 'dictem-mode) + (progn + (setq major-mode nil) + (let ((configuration dictem-window-configuration) + (selected-window dictem-selected-window)) + (kill-buffer (current-buffer)) + (if (window-live-p selected-window) + (progn + (select-window selected-window) + (set-window-configuration configuration))))))) + +(defun dictem-last () + "Go back to the last buffer visited visited." + (interactive) + (if (eq major-mode 'dictem-mode) + (if dictem-content-history + (progn + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) + (insert (car (car dictem-content-history))) + (goto-char (cadr (car dictem-content-history))) + (setq dictem-content-history (cdr dictem-content-history)) + ) + ) + )) + +(defun dictem-kill-all-buffers () + "Kill all dictem buffers." + (interactive) + (dolist (buffer (buffer-list)) + (let ((buf-name (buffer-name buffer))) + (if (and (<= (length dictem-buffer-name) (length buf-name)) + (string= dictem-buffer-name + (substring buf-name 0 (length dictem-buffer-name)))) + (kill-buffer buf-name)) + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Top-level Functions ;;;;;; + +(defun dictem-run-match (query database strat) + "Asks a user about database name, search strategy and query, +creates new *dictem* buffer and +shows matches in it." + (interactive + (list + (dictem-read-query (thing-at-point 'word)) + (dictem-select-database t t (dictem-get-default-database)) + (dictem-select-strategy (dictem-get-default-strategy)))) + (dictem-run 'dictem-base-match database query strat)) + +(defun dictem-run-define (query database) + "Asks a user about database name and query, +creates new *dictem* buffer and +shows definitions in it." + (interactive + (list + (dictem-read-query (thing-at-point 'word)) + (dictem-select-database t t (dictem-get-default-database)))) + (dictem-run 'dictem-base-define database query nil)) + +(defun dictem-run-search (query database strat) + "Asks a user about database name, search strategy and query, +creates new *dictem* buffer and +shows definitions in it." + (interactive + (list + (dictem-read-query (thing-at-point 'word)) + (dictem-select-database t t (dictem-get-default-database)) + (dictem-select-strategy (dictem-get-default-strategy)))) + (dictem-run 'dictem-base-search database query strat)) + +(defun dictem-run-show-info (database) + "Asks a user about database name +creates new *dictem* buffer and +shows information about it." + (interactive (list + (dictem-select-database + nil nil + (dictem-get-default-database)))) + (dictem-run 'dictem-base-show-info database)) + +(defun dictem-run-show-server () + "Creates new *dictem* buffer and +shows information about DICT server in it." + (interactive) + (dictem-run 'dictem-base-show-server)) + +(defun dictem-run-show-databases () + "Creates new *dictem* buffer and +shows a list of databases provided by DICT." + (interactive) + (dictem-run 'dictem-base-show-databases)) + +(defun dictem-run-show-strategies () + "Creates new *dictem* buffer and +shows a list of search stratgeies provided by DICT." + (interactive) + (dictem-run 'dictem-base-show-strategies)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(easy-menu-define + dictem-menu + dictem-mode-map + "DictEm Menu" + `("DictEm" + ["DictEm..." dictem-help t] + "--" + ["Next Section" dictem-next-section t] + ["Previous Section" dictem-previous-section t] + "--" + ["Match" dictem-run-match t] + ["Definition" dictem-run-define t] + ["Search" dictem-run-search t] + "--" + ["Information about server" dictem-run-show-server t] + ["Information about database" dictem-run-show-info t] + ["A list of available databases" dictem-run-show-databases t] + "--" + ["Bury Dictem Buffer" dictem-quit t] + ["Kill Dictem Buffer" dictem-kill t] + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Optional Features ;;;;; +(defun dictem-create-link (start end face function &optional data add-props) + "Create a link in the current buffer starting from `start' going to `end'. +The `face' is used for displaying, the `data' are stored together with the +link. Upon clicking the `function' is called with `data' as argument." + (let ((properties + (append (list 'face face + 'mouse-face 'highlight + 'link-data data + 'link-function function + 'dictem-server dictem-server + 'dictem-port dictem-port) + add-props))) + (remove-text-properties start end properties) + (add-text-properties start end properties))) + +;;;;;;; Postprocessing Functions ;;;;;;; + +(defun dictem-postprocess-definition-separator () + (save-excursion + (goto-char (point-min)) + (let ((regexp "^\\(From\\)\\( [^\n]+\\)\\(\\[[^\n]+\\]\\)")) + + (while (search-forward-regexp regexp nil t) + (let ((beg (match-beginning 1)) + (end (match-end 1)) + (beg-dbdescr (match-beginning 2)) + (end-dbdescr (match-end 2)) + (beg-dbname (match-beginning 3)) + (end-dbname (match-end 3)) + ) + (put-text-property beg end + 'face 'dictem-database-description-face) + (put-text-property beg-dbdescr end-dbdescr + 'face 'dictem-database-description-face) + (setq dictem-current-dbname + (dictem-replace-spaces + (buffer-substring-no-properties + (+ beg-dbname 1) (- end-dbname 1)))) + (dictem-create-link + beg-dbname end-dbname + 'dictem-reference-dbname-face + 'dictem-base-show-info + (list (cons 'dbname dictem-current-dbname)))) + )))) + +(defvar dictem-hyperlink-beginning + "{" + "String that begins hyperlink. +This variable is used by +the function 'dictem-postprocess-definition-hyperlinks'") + +(defvar dictem-hyperlink-end + "}" + "String that ends hyperlink. +This variable is used by +the function 'dictem-postprocess-definition-hyperlinks'") + +(defvar dictem-hyperlink-define-func + 'dictem-base-define + "Function called when user clicks on hyperlinks inside the definition. +This variable is used by +the function 'dictem-postprocess-definition-hyperlinks'") + +(defun dictem-postprocess-collect-hyperlinks () + (save-excursion + (goto-char (point-min)) + (let ((regexp (concat "\\(" dictem-hyperlink-beginning "\\([^{}|]+\\)" + dictem-hyperlink-end + "\\|\\(" dictem-hyperlink-beginning + "\\([^{}|\n]+\\)|\\([^{}|\n]+\\)" dictem-hyperlink-end + "\\)\\)"))) + + (while (search-forward-regexp regexp nil t) + (cond ((match-beginning 2) + (let* ((word (dictem-replace-spaces + (buffer-substring-no-properties + (match-beginning 2) + (match-end 2))))) + (setq dictem-hyperlinks-alist + (cons (list word word) dictem-hyperlinks-alist)) + )) + ((match-beginning 3) + (let* ((word-beg (match-beginning 4)) + (word-end (match-end 4)) + (link-beg (match-beginning 5)) + (link-end (match-end 5)) + (word (dictem-replace-spaces + (buffer-substring-no-properties + word-beg word-end))) + (link (dictem-replace-spaces + (buffer-substring-no-properties + link-beg link-end))) + ) + (setq dictem-hyperlinks-alist + (cons (list word link) dictem-hyperlinks-alist)) + ))))) + )) + +(defun dictem-find-brackets (re-beg re-end) + (let ((beg-beg (make-marker)) + (beg-end (make-marker)) + (end-beg (make-marker)) + (end-end (make-marker))) + (if (search-forward-regexp re-beg nil t) + (progn + (set-marker beg-beg (match-beginning 0)) + (set-marker beg-end (match-end 0)) + (if (search-forward-regexp re-end nil t) + (progn + (set-marker end-beg (match-beginning 0)) + (set-marker end-end (match-end 0)) + (list beg-beg beg-end end-beg end-end)) + nil)) + nil))) + +(defun dictem-postprocess-definition-hyperlinks-cyrlybr1 () + (save-excursion + (goto-char (point-min)) + (let ((regexp) (pos) (beg1) (beg2) (beg3) (end) (word)) + + (while (setq pos (dictem-find-brackets dictem-hyperlink-beginning + dictem-hyperlink-end)) + (delete-region (nth 0 pos) (nth 1 pos)) + (delete-region (nth 2 pos) (nth 3 pos)) + (setq word (buffer-substring-no-properties (nth 1 pos) (nth 2 pos))) + (dictem-create-link + (nth 1 pos) (nth 2 pos) + 'dictem-reference-definition-face + dictem-hyperlink-define-func + (list (cons 'word (dictem-replace-spaces word)) + (cons 'dbname dictem-current-dbname)) + '(link t)))))) + +(defun dictem-postprocess-definition-hyperlinks-curlybr2 () + (save-excursion + (goto-char (point-min)) + (let ((regexp + (concat dictem-hyperlink-beginning "\\([^{}|\n]+\\)|\\([^{}|\n]+\\)" + dictem-hyperlink-end))) + + (while (search-forward-regexp regexp nil t) + (let* ((beg (match-beginning 5)) + (end (match-end 5)) + (match-beg (match-beginning 3)) + (repl-beg (match-beginning 4)) + (repl-end (match-end 4)) + (repl (buffer-substring-no-properties repl-beg repl-end)) + (word (buffer-substring-no-properties beg end))) + (replace-match repl t t) + (dictem-create-link + match-beg (+ match-beg (length repl)) + 'dictem-reference-definition-face + dictem-hyperlink-define-func + (list (cons 'word (dictem-replace-spaces word)) + (cons 'dbname dictem-current-dbname)) + '(link t))))))) + +(defun dictem-postprocess-definition-hyperlinks () + (dictem-postprocess-definition-hyperlinks-cyrlybr1) + (dictem-postprocess-definition-hyperlinks-curlybr2) +; (dictem-postprocess-definition-hyperlinks-curlybr2) + ) + +(defun dictem-postprocess-match () + (save-excursion + (goto-char (point-min)) + (let ((last-database dictem-last-database) + (regexp "\\(\"[^\"\n]+\"\\)\\|\\([^ \"\n]+\\)")) + + (while (search-forward-regexp regexp nil t) + (let* ((beg (match-beginning 0)) + (end (match-end 0)) + (first-char (buffer-substring-no-properties beg beg))) + (cond + ((save-excursion (goto-char beg) (= 0 (current-column))) + (setq last-database + (dictem-replace-spaces + (buffer-substring-no-properties beg (- end 1)))) + (dictem-create-link + beg (- end 1) + 'dictem-reference-dbname-face 'dictem-base-show-info + (list (cons 'dbname last-database)))) + ((match-beginning 1) + (dictem-create-link + beg end + 'dictem-reference-m1-face 'dictem-base-define + (list (cons 'word + (dictem-replace-spaces + (buffer-substring-no-properties + (+ beg 1) (- end 1)))) + (cons 'dbname last-database)))) + (t + (dictem-create-link + beg end + 'dictem-reference-m2-face 'dictem-base-define + (list (cons 'word + (dictem-replace-spaces + (buffer-substring-no-properties + beg end ))) + (cons 'dbname last-database)))) + )))))) + +(defun dictem-postprocess-definition-remove-header () + (save-excursion + (goto-char (point-min)) + (end-of-line) + (let (eol (point)) + (goto-char (point-min)) + (if (search-forward-regexp "[0-9] definitions? found" eol t) + (progn + (goto-char (point-min)) + (let ((kill-whole-line t)) + (kill-line 1)) + ))))) + +(defun dictem-add-text-face-properties (start end face-add-props + &optional object) + (let (face-props) + (while (<= start end) + (progn + (setq face-props (get-text-property start 'face object)) + (if (facep face-props) + (progn + (setq face-props nil) + (add-text-properties + start (+ 1 start) + (list 'face nil) + object))) + (add-text-properties + start (+ 1 start) + (list 'face (append face-props face-add-props)) + object) + (setq start (+ start 1)))))) + +(defun dictem-add-begendre-face-propertires (re-beg re-end face-properties) + (let ((bold-beg-beg (make-marker)) + (bold-beg-end (make-marker)) + (bold-end-beg (make-marker)) + (bold-end-end (make-marker))) + (while (search-forward-regexp re-beg nil t) + (progn + (set-marker bold-beg-beg (match-beginning 0)) + (set-marker bold-beg-end (match-end 0)) + (if (search-forward-regexp re-end nil t) + (progn + (set-marker bold-end-beg (match-beginning 0)) + (set-marker bold-end-end (match-end 0)) + (dictem-add-text-face-properties + bold-beg-end (- bold-end-beg 1) face-properties) + (delete-region bold-beg-beg bold-beg-end) + (delete-region bold-end-beg bold-end-end) + )))))) + +(defun dictem-postprocess-stardict-definition () + (interactive) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<b>" "</b>" '(:weight bold)) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<k>" "</k>" '(:height 1.2 :foreground "white" :weight bold)) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<abr>" "</abr>" '(:weight bold :foreground "green")) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<dtrn>" "</dtrn>" '()) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<c c=\"green\">" "</c>" '(:foreground "green")) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<c c=\"brown\">" "</c>" '(:foreground "brown")) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<c>" "</c>" '(:foreground "green")) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<ex>" "</ex>" '(:foreground "BurlyWood")) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<i>" "</i>" '(:slant "oblique")) + + (goto-char (point-min)) + (dictem-add-begendre-face-propertires + "<c c=\"blueviolet\">" "</c>" '(:foreground "lightblue")) + + ; replaceing <tr> with [ + (goto-char (point-min)) + (while (search-forward-regexp "<tr>" nil t) + (replace-match "[" t t)) + + ; replaceing </tr> with ] + (goto-char (point-min)) + (while (search-forward-regexp "</tr>" nil t) + (replace-match "]" t t)) + + ; replaceing <co> with ( + (goto-char (point-min)) + (while (search-forward-regexp "<co>" nil t) + (replace-match "" t t)) + + ; replaceing </co> with ( + (goto-char (point-min)) + (while (search-forward-regexp "</co>" nil t) + (replace-match "" t t)) + + (let ((dictem-hyperlink-beginning "<kref>") + (dictem-hyperlink-end "</kref>")) + (dictem-postprocess-definition-hyperlinks-cyrlybr1)) + + ) + +;;;;; On-Click Functions ;;;;; +(defun dictem-define-on-press () + "Is called upon pressing Enter." + (interactive) + + (let* ( + (properties (text-properties-at (point))) + (data (plist-get properties 'link-data)) + (fun (plist-get properties 'link-function)) + (dictem-server (plist-get properties 'dictem-server)) + (dictem-port (plist-get properties 'dictem-port)) + (word (assq 'word data)) + (dbname (assq 'dbname data)) + ) + (if (or word dbname) + (dictem-run fun + (if dbname (cdr dbname) dictem-last-database) + (if word (cdr word) nil) + nil)))) + +(defun dictem-define-on-click (event) + "Is called upon clicking the link." + (interactive "@e") + + (mouse-set-point event) + (dictem-define-on-press)) + +;(defun dictem-define-with-db-on-click (event) +; "Is called upon clicking the link." +; (interactive "@e") +; +; (mouse-set-point event) +; (let* ( +; (properties (text-properties-at (point))) +; (word (plist-get properties 'link-data))) +; (if word +; (dictem-run 'dictem-base-define (dictem-select-database) word nil)))) + +;(define-key dictem-mode-map [C-down-mouse-2] +; 'dictem-define-with-db-on-click) + + +;;; Function for "narrowing" definitions ;;;;; + +(defcustom dictem-postprocess-each-definition-hook + nil + "Hook run in dictem mode buffers containing SHOW SERVER result." + :group 'dictem + :type 'hook + :options '(dictem-postprocess-definition-separator + dictem-postprocess-definition-hyperlinks)) + +(defun dictem-postprocess-each-definition () + (save-excursion + (goto-char (point-min)) + (let ((regexp-from-dbname "^From [^\n]+\\[\\([^\n]+\\)\\]") + (beg nil) + (end (make-marker)) + (dbname nil)) + (if (search-forward-regexp regexp-from-dbname nil t) + (let ((dictem-current-dbname + (buffer-substring-no-properties + (match-beginning 1) (match-end 1)))) + (setq beg (match-beginning 0)) + (while (search-forward-regexp regexp-from-dbname nil t) + (set-marker end (match-beginning 0)) +; (set-marker marker (match-end 0)) + (setq dbname + (buffer-substring-no-properties + (match-beginning 1) (match-end 1))) + + (save-excursion + (narrow-to-region beg (marker-position end)) + (run-hooks 'dictem-postprocess-each-definition-hook) + (widen)) + + (setq dictem-current-dbname dbname) + (goto-char end) + (forward-char) + (setq beg (marker-position end)) + ) + (save-excursion + (narrow-to-region beg (point-max)) + (run-hooks 'dictem-postprocess-each-definition-hook) + (widen)) + ))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'dictem) |