├── AUTHORS ├── COPYING ├── TODO ├── dictem-lingvo-dsl.el ├── dictem-elisp.el ├── NEWS ├── README └── dictem.el /AUTHORS: -------------------------------------------------------------------------------- 1 | Mon, 20 Oct 2003 20:40:46 +0300 2 | DictEm was written by Aleksey Cheusov 3 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GPL 2.0 2 | http://www.gnu.org/licenses/gpl-2.0.html 3 | http://opensource.org/licenses/gpl-2.0.php 4 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - "er" dictionary + geek 2 | - antonym for "l". "n" and "p"? 3 | - keep p/n history in buffers with numbers. 4 | - does dictem-use-existing-buffer work properly? 5 | 6 | Do you have ideas, want new features, see bugs? Let me know ;-) 7 | -------------------------------------------------------------------------------- /dictem-lingvo-dsl.el: -------------------------------------------------------------------------------- 1 | ;; -*- coding: utf-8; -*- 2 | 3 | (require 'dictem) 4 | 5 | (defun dictem-lingvo-dsl-highlight () 6 | ; trn/ex/com/* 7 | (goto-char (point-min)) 8 | (while (search-forward-regexp "\\[/?trn\\]\\|\\[/?p\\]\\|\\[/?c\\]\\|\\[/?com\\]\\|\\[/?[*]\\]\\|\\[/?b\\]\\|\\[/?i\\]\\|\\[/?m[0-9]?\\]\\|\\[/?ex\\]" nil t) 9 | (replace-match "" t t)) 10 | 11 | ; [ex] [/ex] 12 | ; (goto-char (point-min)) 13 | ; (while (search-forward-regexp "\\[ex\\]\\([][]*\\)\\[/ex\\]" nil t) 14 | ; (add-text-properties (match-beginning 0) (match-end 0) 15 | ; '(face dictem-lingvo-dsl-example-face)) 16 | ; (let* ((beg (match-beginning 1)) 17 | ; (end (match-end 1)) 18 | ; (repl (buffer-substring beg end))) 19 | ; (replace-match repl 1 1))) 20 | 21 | ; <<>> 22 | (goto-char (point-min)) 23 | (while (search-forward-regexp "\\(<<\\|\\[ref\\]\\)\\([^\n]*\\)\\(>>\\|\\[/ref\\]\\)" nil t) 24 | (let* ((beg (match-beginning 2)) 25 | (end (match-end 2)) 26 | (repl (buffer-substring beg end))) 27 | (replace-match (concat "{" repl "}") t t))) 28 | 29 | ; hyperlinks 30 | (dictem-postprocess-definition-hyperlinks) 31 | ) 32 | 33 | (progn 34 | (set-buffer "*dsl-buffer*") 35 | (dictem-lingvo-dsl-highlight)) 36 | 37 | (defface dictem-lingvo-dsl-italic-face 38 | '((((background light)) (:italic true)) 39 | (((background dark)) (:italic true))) 40 | "Face for italic" 41 | ) 42 | 43 | (defface dictem-lingvo-dsl-color-face 44 | '((((background light)) (:italic true)) 45 | (((background dark)) (:italic true))) 46 | "Face for color" 47 | ) 48 | 49 | (defface dictem-lingvo-dsl-example-face 50 | '((((background light)) (:italic true)) 51 | (((background dark)) (:italic true))) 52 | "Face for color" 53 | ) 54 | 55 | (defface dictem-lingvo-dsl-bold-face 56 | '((((background light)) (:bold true)) 57 | (((background dark)) (:bold true))) 58 | "Face for bold" 59 | ) 60 | 61 | (defface dictem-lingvo-dsl-trn-face 62 | '((((background light)) (:bold true :italic true)) 63 | (((background dark)) (:bold true :italic true))) 64 | "Face for trn" 65 | ) 66 | 67 | (provide 'dictem-lingvo-dsl) 68 | -------------------------------------------------------------------------------- /dictem-elisp.el: -------------------------------------------------------------------------------- 1 | (require 'dictem) 2 | 3 | (defun dictem-elisp-variable-documentation (func) 4 | (let* ((help-buffer "*Help*") 5 | (temp-buffer-show-function (lambda (b) ())) 6 | ) 7 | (if (boundp func) 8 | (save-excursion 9 | (describe-variable func) 10 | (set-buffer help-buffer) 11 | (prog1 12 | (buffer-substring (point-min) (point-max)) 13 | (kill-this-buffer help-buffer)) 14 | ) 15 | nil))) 16 | 17 | (defun dictem-elisp-function-documentation (func) 18 | (let* ((help-buffer "*Help*") 19 | (temp-buffer-show-function (lambda (b) ())) 20 | ) 21 | (if (functionp func) 22 | (save-excursion 23 | (describe-function func) 24 | (set-buffer help-buffer) 25 | (prog1 26 | (buffer-substring (point-min) (point-max)) 27 | (kill-this-buffer)) 28 | ) 29 | nil))) 30 | 31 | (defun dictem-elisp-DEFINE (query) 32 | (let ((sym (intern-soft query)) 33 | (doc nil)) 34 | ; (ret (if (and sym (functionp sym)) 35 | ; (documentation sym) 36 | ; nil))) 37 | (cond ((null sym) 38 | (dictem-make-error 39 | 20 (format "SYmbol '%s is not defined" query))) 40 | ((functionp sym) 41 | (setq doc (dictem-elisp-function-documentation sym)) 42 | (if doc doc 43 | (dictem-make-error 44 | 20 (format "'%s is not documented as a function" query)))) 45 | (t 46 | (setq doc (dictem-elisp-function-documentation sym)) 47 | (if doc doc 48 | (dictem-make-error 49 | 20 (format "'%s is documented as neither function not variable" query))) 50 | )))) 51 | ; (documentation sym)) 52 | ; (t (dictem-make-error 53 | ; 20 (format "There is no function '%s" query)))))) 54 | 55 | (defun dictem-string-match-prefix (pattern string) 56 | (eq 0 (string-match (regexp-quote pattern) string))) 57 | (defun dictem-string-match-substring (pattern string) 58 | (string-match (regexp-quote pattern) string)) 59 | (defun dictem-string-match-suffix (pattern string) 60 | (string-match (regexp-quote pattern) string) 61 | (= (length string) (match-end 0))) 62 | (defun dictem-string-match-word (pattern string) 63 | (string-match (concat "\\b\\(" (regexp-quote pattern) "\\)\\b") 64 | string)) 65 | 66 | (defun dictem-elisp-MATCH-UNI (query fun) 67 | (let ((i 0) 68 | (l nil) 69 | ; (re (regexp-quote query)) 70 | (item nil)) 71 | (while (< i (length obarray)) 72 | (progn 73 | (setq item (symbol-name (elt obarray i))) 74 | (if (funcall fun (regexp-quote query) item) 75 | (setq l (cons item l))) 76 | (setq i (+ i 1)))) 77 | l)) 78 | 79 | (defun dictem-elisp-MATCH (query strategy) 80 | (let ((l (dictem-elisp-MATCH-UNI 81 | query 82 | (cond ((string= strategy "exact") 83 | (symbol-function 'string=)) 84 | ((string= strategy "word") 85 | (symbol-function 'dictem-string-match-word)) 86 | ((string= strategy "prefix") 87 | (symbol-function 'dictem-string-match-prefix)) 88 | ((string= strategy "suffix") 89 | (symbol-function 'dictem-string-match-suffix)) 90 | ((string= strategy "substring") 91 | (symbol-function 'dictem-string-match-substring)))))) 92 | (if l l 93 | (dictem-make-error 94 | 20 (format "No matches for %s/%s" query strategy))))) 95 | 96 | ;(dictem-elisp-MATCH "at" "word") 97 | ;(dictem-elisp-MATCH "file" "suffix") 98 | ;(dictem-elisp-MATCH "dictem" "prefix") 99 | ;(dictem-elisp-MATCH "s-s" "substring") 100 | ;(dictem-elisp-MATCH "pike" "substring") 101 | 102 | (provide 'dictem-elisp) 103 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Version 1.0.4, Sat, 25 Aug 2012 23:23:24 +0300 2 | 3 | - Flag (interactive) was removed from the following functions: 4 | dictem-select-strategy, dictem-select-database, dictem-read-query 5 | and dictem-run. This fixes Debian bug #564251. 6 | 7 | Version 1.0.3, Sun, 22 Jul 2012 13:12:00 +0300 8 | 9 | - fix: "dictem-get-matches" function returns dictionary names 10 | without ":" in the end. 11 | 12 | - fix. insertion of text produced by "dict" client of by user's 13 | database is always made IN THE END of dictem buffer. This fixes 14 | the problems with hightlighting in match/define mixed results. 15 | 16 | - Fix failure when dictem-use-user-databases-only is t. The problem 17 | was that dictem-last-database variable was initialized 18 | incorrectly. 19 | 20 | Version 1.0.2, Sun, 22 Mar 2009 17:20:12 +0200 21 | 22 | Another fix in dictem-postprocess-definition-remove-header. 23 | 24 | Version 1.0.1, Fri, 20 Mar 2009 12:43:15 +0200 25 | 26 | - fix in dictem-postprocess-definition-remove-header. 27 | It wrongly deleted extra line 28 | 29 | Version 1.0.0, Sat, 11 Oct 2008 18:59:15 +0300 30 | 31 | - Running dictem-initialize everytime your network/internet is up 32 | (if case you have no permanent connection to Internet, 33 | e.g. dial-up, adsl etc.) is a bit annoying. To avoid this dictem 34 | is (re)initialized (if needed) automatically from 35 | dictem-select-strategy and dictem-select-database functions. As 36 | a result, running dictem-initialize in .emacs becomes unnecessary 37 | 38 | - New function (dictem-reinitialize-err) added 39 | 40 | - Minor fix in dictem-initialize-databases-alist function. Now it 41 | returns error data in case of failure, not nil. 42 | (just like dictem-initialize-strategies-alist) 43 | 44 | Version 0.82, Mon, 28 Jan 2008 22:59:07 +0200 45 | 46 | - FIX for emacs-22 (insert-string is replaced with insert) 47 | - Minor fixes in README 48 | 49 | Version 0.81, Sat, 22 Jul 2006 15:45:53 +0300 50 | 51 | - dictem-server variable can be equal to nil, in this case 52 | 'dict' command line tool will be called without -h option, i.e. 53 | default _list of servers_ specified in .dictrc (or dict.conf) 54 | will be used. 55 | 56 | dict:///dictionary_name (in dictem-user-databases-alist) also means 57 | that default server list will be used, see Ex.4 for the sample of use. 58 | 59 | - dictem-server variable now defaults to nil, old value was "dict.org". 60 | dictem-strategy-alist and dictem-database-alist also defaults to nil. 61 | 62 | Version 0.8, Mon, Sun, 28 May 2006 00:23:43 +0300 63 | 64 | - removed: ./configure / make / make install 65 | See installation section in README if you are in trouble 66 | 67 | - added: dictem-exclude-databases variable to disable some databases 68 | from autocompletion menu, see example 15 in README file. 69 | 70 | example for those who uses dict://dict.org: 71 | 72 | (setq dictem-exclude-databases 73 | '("tur-" "afr-" "ara-" "cro-" "cze-" "dan-" "hin-" "hun-" 74 | "iri-" "ita-" "kha-" "lat-" "nld-" "por-" "sco-" "scr-" 75 | "slo-" "swa-" "swe-" "tur-" "rom-" "wel-" 76 | 77 | "-tur" "-afr" "-ara" "-cro" "-cze" "-dan" "-hin" "-hun" 78 | "-iri" "-ita" "-kha" "-lat" "-nld" "-por" "-sco" "-scr" 79 | "-slo" "-swa" "-swe" "-tur" "-rom" "-wel")) 80 | 81 | - errors messages obtained from 'dict' command are printed 82 | in case initialization failure but the constant string. 83 | 84 | Version 0.7, Mon, 3 Apr 2006 15:11:57 +0300 85 | 86 | - DICTEM can handle dictionaries defined by user. 87 | This allows to use dictem not only for accessing DICT servers, 88 | but also for accesing user's databases. 89 | See Ex.14 in README file for a simple example. 90 | 91 | - added: dictem-client-prog-args-list variable 92 | that keeps a list of additional 93 | arguments to the command line 'dict' client. 94 | This may be helpful in case you use 'dict' wrappers (having additional 95 | options) or new versions of 'dict' program. 96 | 97 | - added: dictem-option-mime variable. 98 | If `t' the OPTION MIME command (see RFC-2229 for details) 99 | will be sent to the DICT server. i.e. 'dict' program 100 | will be run with '-M' option. 101 | As a result server's response will be prepanded with MIME header 102 | followed by a blank line. 103 | Because of bugs in dict -M (dict version < 1.10.3), 104 | dict-1.10.3 or later is STRONGLY recommended. 105 | 106 | MIME-ized content can be postprocessed by functions called from 107 | dictem-postprocess-xxxx hooks. Because the current version of dictem 108 | doesn't contain such kind of functions, this variable should be used 109 | by those who program in Emacs. 110 | Suggestions and code are welcomed as always. 111 | Have a lot of fun ;-) 112 | 113 | - added: dictem-run-show-strategies function, 114 | similar to dictem-run-show-databases. 115 | 116 | - more complete dictem-mode's help string (documentation for dictem mode) 117 | 118 | - new examples of dictem usage in Ex.9 section 119 | 120 | - minor fixes in documentation and README 121 | 122 | Version 0.0.5, Wed, 8 Jun 2005 19:56:56 +0300 123 | 124 | - new examples in README file: Ex.12-13 125 | 126 | - `dictem-postprocess-collect-hyperlinks' function 127 | (when added to `dictem-postprocess-definition-hook', 128 | `dictem-postprocess-show-info-hook' or 129 | `dictem-postprocess-show-server-hook' hooks) collects hyperlinks 130 | in the variable `dictem-hyperlinks-alist'. 131 | This variable is used by the function `dictem-hyperlinks-menu' 132 | which implements 133 | the autocompletion-based menu the same way `Info-menu' does. 134 | 135 | "e" is assigned to call the function `dictem-hyperlinks-menu'. 136 | The variable `dictem-hyperlinks-alist' is local to buffer. 137 | 138 | - If `dictem-use-existing-buffer' variable is `t' 139 | and dictem-use-content-history is not nil, 140 | the entire buffer content and (point) 141 | is stored in `dictem-content-history' variable when you click 142 | on hyperlink and thus you can easily return to the previous 143 | buffer by pressing "l" (`dictem-last' function). 144 | 145 | "l" is assigned to function `dictem-last'. 146 | It works just like the button in the WEB browsers. 147 | 148 | - added: `dictem-postprocess-definition-remove-header', 149 | function for postprocessing DEFINE buffer. 150 | It is intended to remove header `XXX definition[s] found' 151 | at the beginning of dict's output 152 | and can be added to the hook `dictem-postprocess-definition-hook'. 153 | 154 | - fixes: 155 | `dictem-kill-all-buffers' has been reimplemented for using 156 | `dolist' macros instead of recursion. 157 | Recursion-bases implementation causes dictem to fail 158 | when lots of buffers exist. 159 | Thanks to Juri Linkov for bug reports and lots of suggestions. 160 | 161 | - String that begins hyperlink 162 | is stored in the variable `dictem-hyperlink-beginning', defaults to "{" 163 | String that ends hyperlink 164 | is stored in the variable `dictem-hyperlink-end, defaults to "}" 165 | Function that is called when hyperlink "define" is activated 166 | is stored in the variable `dictem-hyperlink-define-func', 167 | defaults to `dictem-base-define' 168 | 169 | All this stuff may be useful for more complex buffer postprocessing. 170 | Hyperlinks are not always enclosed in '{' and '}' braces. 171 | 172 | Version 0.0.4, Thu, 24 Feb 2005 19:40:24 +0200 173 | 174 | dictem-default-database (dictem-default-strategy) variables override 175 | value of dictem-last-database (dictem-last-strategy) variable, 176 | i.e. when dictem-default-xxx is set to non-nil 177 | this database (strategy) is always used by default, 178 | otherwise the last used database (strategy) is used. 179 | 180 | All examples in README file are know numbered. 181 | 182 | New examples #10 and #11 in README file. 183 | 184 | By default dictem uses the default query as an initial 185 | input, this may be very useful. 186 | To disable this behaviour set `dictem-empty-initial-input' to `t'. 187 | See (describe-variable 'dictem-empty-initial-input) 188 | and REAME example #11. 189 | 190 | FIXED: `dictem-last-database' keeps "low-level" database name 191 | but the user's virtual one. As a result virtual dictionary 192 | could not be the default one (kept in dictem-last-database or 193 | dictem-default-database variable ). 194 | 195 | Version 0.0.3, Tue, 14 Dec 2004 20:43:34 +0200 196 | 197 | DictEm has been ported to XEmacs 198 | 199 | Virtual dictionaries can access databases from different DICT servers 200 | 201 | (setq dictem-user-databases-alist 202 | '(("_translate" . ("dict://mova.org/mueller7" 203 | "dict://dict.org:2628/web1913")) 204 | ("_ru-ru" . ("beslov" "dict://mova.org:2628/religion")) 205 | )) 206 | 207 | See README file for more information. 208 | 209 | The following commands can be run non-interactively. 210 | `dictem-run-show-info', `dictem-run-search' and 211 | `dictem-run-define' 212 | 213 | `dictem-next-link' and `dictem-previous-link' skip hyperlinks on 214 | database names. 215 | 216 | Renamed: `dictem-url' to `dictem-make-url' 217 | `link-create-link' to `dictem-create-link' 218 | 219 | DictEm's prompt looks like this: ` []:' 220 | 221 | New default faces 222 | 223 | Lots of README updates. 224 | 225 | A few fixes 226 | 227 | Version 0.0.2, Tue, 30 Nov 2004 16:40:00 +0200 228 | 229 | added: new function `dictem-kill-all-buffers' killing all dictem buffers. 230 | The key "x" press in dictem buffer use it. 231 | 232 | dictem-postprocess-definition-hyperlinks function: 233 | When a substring {foo|bar} is encountered in a definition, 234 | `foo' is used for highlighting and `bar' is used for subsearch. 235 | 236 | new functions: `dictem-next-link' and `dictem-previous-link' which 237 | set pointer to the next (or previous) hyper link 238 | \M-n and \M-p key 239 | are assigned to `dictem-next-link' and `dictem-previous-link' 240 | When pressing RET (C-m) key on hyper link, subsearch 241 | DICT server is sent a DEFINE command 242 | 243 | added: new customizable variable: `dictem-use-existing-buffer' 244 | which can be used 245 | to use existing dictem buffer instead of creating a new one 246 | for subsearches. This variable is local to buffer. 247 | 248 | Documentation update 249 | 250 | Version 0.0.1, Thu, 08 Jul 2004 13:58:59 +0300 251 | 252 | first publicly available release 253 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | DictEm is a Dictionary protocol client for GNU Emacs. 2 | 3 | It uses a console dict client (http://sf.net/projects/dict) and 4 | implements all functions of the client part of DICT protocol 5 | (RFC-2229, www.dict.org), i.e. looking up words and definitions, 6 | obtaining information about available strategies, provided databases, 7 | information about DICT server etc. 8 | 9 | Unlike dictionary.el 10 | (http://www.myrkr.in-berlin.de/dictionary/index.html) DictEm widely 11 | uses autocompletion that is used for selecting dictionary and search 12 | strategy. Moreover, DictEm provides several hooks which may be used 13 | for buffer postprocessing. For example, inbuilt hyperlinking and 14 | highlighting mechanisms are based on this possibility. Another example 15 | is that information obtained from DICT server that is in HTML, ROFF or 16 | INFO format can be easily viewed by Emacs+DictEm if the user supplies 17 | appropriate conversion functions. Of course DictEm can be differently 18 | configured for different Emacs modes (major, minor or buffer 19 | oriented), that allows modularized access to all data serviced by DICT 20 | servers. This makes it ideal tool for translating articles between a 21 | series of foreign languages, browsing manuals and other tasks 22 | depending on Emacs mode user currently works with. 23 | 24 | Additionally DictEm supports accessing so called virtual dictionaries (a set 25 | of dictionaries provided by DICT server that user prefers to treat as 26 | a single one). 27 | 28 | Yet another feature DictEm provides is a set of useful functions with 29 | a help of which user can extend DictEm functionality such as to define 30 | new search strategies or even provide new functionality such as to use 31 | another sources of data other than DICT servers. 32 | 33 | See below for a set of example configuration and extensions. 34 | 35 | Also DictEm uses customization mechanism provided by Emacs that helps 36 | Emacs users to easily configure DictEm. 37 | 38 | COPYING 39 | ============ 40 | 41 | See the file COPYING 42 | 43 | DOWNLOAD 44 | ======== 45 | 46 | Latest sources can be downloaded from 47 | http://sourceforge.net/projects/dictem 48 | or 49 | http://freshmeat.net/projects/dictem 50 | 51 | INSTALLATION 52 | ============ 53 | 54 | * In order to uncompress dictem tarball run the following. 55 | 56 | tar xfv dictem-x.y.z.tar.gz 57 | 58 | If you read this file, you probably have already done this. 59 | 60 | * Change your current directory to dictem. 61 | 62 | cd dictem-x.y.z 63 | 64 | * Copy *.el file to the directory you want. 65 | 66 | cp *.el /path/to/emacs/el/files 67 | 68 | * Make sure that DICT client named dict 69 | (available at http://sf.net/projects/dict) 70 | is installed on your system. 71 | Console dict client is used by DictEm for accessing the DICT server. 72 | dict-1.9.14 or later is strongly recommended. 73 | If you'll set dictem-option-mime variable to t (read below), 74 | dict-1.10.3 or later MUST be used. 75 | 76 | REPORTING BUGS 77 | ============== 78 | 79 | Please send all bug reports and suggestions directly to 80 | Aleksey Cheusov . 81 | Reporting bugs at sf.net is also good. 82 | 83 | Also note that there exists dict-beta@dict.org mailing list (low 84 | traffic) where you can ask questions about DICT protocol and 85 | software. 86 | 87 | CONFIGURING 88 | ============= 89 | 90 | Customization group 91 | ------------------- 92 | 93 | Take note, that DictEm defines customization group "dictem". 94 | So, it may be easier for you to customize DictEm by running 95 | M-x customize-group dictem 96 | 97 | Manual Configuration 98 | -------------------- 99 | 100 | Ex.1 101 | 102 | The easiest configuration of dictem may look like this 103 | 104 | ; Add to load-path variable a new directory with files of dictem 105 | (add-to-list 'load-path "/path/you/installed/dictem/to") 106 | 107 | ; Loading dictem functions 108 | (require 'dictem) 109 | 110 | ; Setting the dictionary server hostname. 111 | ; This part is optional, if dictem-server is nil (the default value) 112 | ; "dict" command line utility will use its ows config file 113 | ; ~/.dictrc or PREFIX/etc/dict.conf. 114 | ; Keeping dictem-server variable unset is recomended because 115 | ; this allows to try _list of_ servers until connection is made, 116 | ; see dict(1) for details. 117 | ;(setq dictem-server "localhost") 118 | ;(setq dictem-server "dict.org") 119 | 120 | 121 | ; Setting the dictionary server port. 122 | ; Setting dictem-port is usually not necessary because 123 | ; most DICT servers use the default port 2628. 124 | ;(setq dictem-port "2628") 125 | 126 | ; Code necessary to obtain database and strategy list from DICT 127 | ; server. As of version 0.90, dictem runs this function from 128 | ; dictem-select-database and dictem-select-strategy if an 129 | ; initialization was not completed or failed previously, that is 130 | ; running dictem-initialize is optional 131 | (dictem-initialize) 132 | 133 | ; Assigning hot keys for accessing DICT server 134 | 135 | ; SEARCH = MATCH + DEFINE 136 | ; Ask for word, database and search strategy 137 | ; and show definitions found 138 | (global-set-key "\C-cs" 'dictem-run-search) 139 | 140 | ; MATCH 141 | ; Ask for word, database and search strategy 142 | ; and show matches found 143 | (global-set-key "\C-cm" 'dictem-run-match) 144 | 145 | ; DEFINE 146 | ; Ask for word and database name 147 | ; and show definitions found 148 | (global-set-key "\C-cd" 'dictem-run-define) 149 | 150 | ; SHOW SERVER 151 | ; Show information about DICT server 152 | (global-set-key "\C-c\M-r" 'dictem-run-show-server) 153 | 154 | ; SHOW INFO 155 | ; Show information about the database 156 | (global-set-key "\C-c\M-i" 'dictem-run-show-info) 157 | 158 | ; SHOW DB 159 | ; Show a list of databases provided by DICT server 160 | (global-set-key "\C-c\M-b" 'dictem-run-show-databases) 161 | 162 | ------- 163 | Ex.2 164 | 165 | There are a few functions that can make dictem look 166 | a bit nicer and be more functional. They should 167 | be added to special hooks like the following. 168 | 169 | ; For creating hyperlinks on database names 170 | ; and found matches. 171 | ; Click on them with mouse-2 172 | (add-hook 'dictem-postprocess-match-hook 173 | 'dictem-postprocess-match) 174 | 175 | ; For highlighting the separator between the definitions found. 176 | ; This also creates hyperlink on database names. 177 | (add-hook 'dictem-postprocess-definition-hook 178 | 'dictem-postprocess-definition-separator) 179 | 180 | ; For creating hyperlinks in dictem buffer 181 | ; that contains definitions. 182 | (add-hook 'dictem-postprocess-definition-hook 183 | 'dictem-postprocess-definition-hyperlinks) 184 | 185 | ; For creating hyperlinks in dictem buffer 186 | ; that contains information about a database. 187 | (add-hook 'dictem-postprocess-show-info-hook 188 | 'dictem-postprocess-definition-hyperlinks) 189 | 190 | ------- 191 | Ex.3 192 | 193 | If you want to combine some databases in you own "virtual" dictionary, 194 | create them like this 195 | 196 | (setq dictem-user-databases-alist 197 | '(("_en-ru" . ("mueller7" "korolew_en-ru")) 198 | ("_en-en" . ("foldoc" "gcide" "wn")) 199 | ("_ru-ru" . ("beslov" "ushakov" "ozhegov" "brok_and_efr")) 200 | ("_unidoc" . ("susv3" "man" "info" "howto" "rfc")) 201 | )) 202 | 203 | As a result four new special database collections will be created 204 | and new names will appear when 205 | dictem-run function will ask you about database name. 206 | 207 | ------- 208 | Ex.4 209 | 210 | You can even create virtual dictionaries which consist of 211 | databases from different DICT server. 212 | The dict url form dict:///religion means 'dict' command line tool 213 | will be called without -h option, i.e. a list of dictionary servers 214 | from .dictrc (or dict.conf) will be used. 215 | 216 | (setq dictem-user-databases-alist 217 | '(("_en-ru" . ("dict://mova.org/mueller7" 218 | "dict://dict.org:2628/web1913")) 219 | ("_ru-ru" . ("beslov" "dict:///religion")) 220 | )) 221 | 222 | another example: 223 | 224 | (setq dictem-user-databases-alist 225 | `(("en-en" . ("dict://dict.org:2628/english")) 226 | ("en-ru" . ("dict:///en-ru" 227 | "dict://dict.org:2628/eng-rus" 228 | )) 229 | )) 230 | 231 | ------- 232 | Ex.5 233 | 234 | If your DICT server provides too many databases and most of which 235 | are of no interest for you, you can disable them 236 | and use only those specified in dictem-user-databases-alist variable. 237 | 238 | (setq dictem-use-user-databases-only t) 239 | 240 | ------- 241 | Ex.6 242 | 243 | Of course, you can assign your own key bindings in dictem buffer 244 | 245 | (define-key dictem-mode-map [tab] 'dictem-next-link) 246 | (define-key dictem-mode-map [(backtab)] 'dictem-previous-link) 247 | 248 | ------- 249 | Ex.7 250 | 251 | You are not limited to the default DICT server only. 252 | The following code will allow you to access any server you want. 253 | You'll be asked for host and port. 254 | 255 | ; DEFINE 256 | (global-set-key 257 | "\C-c\M-d" 258 | '(lambda () 259 | (interactive) 260 | (save-dictem 261 | (let* ((dictem-server (read-string "server: " 262 | dictem-server nil "dict.org")) 263 | (dictem-port (read-string "port: " 264 | (dictem-get-port) nil "2628"))) 265 | (dictem-initialize) 266 | (call-interactively 'dictem-run-define))))) 267 | 268 | ; MATCH 269 | (global-set-key 270 | "\C-c\M-m" 271 | '(lambda () 272 | (interactive) 273 | (save-dictem 274 | (let* ((dictem-server (read-string "server: " 275 | dictem-server nil "dict.org")) 276 | (dictem-port (read-string "port: " 277 | (dictem-get-port) nil "2628"))) 278 | (dictem-initialize) 279 | (call-interactively 'dictem-run-match))))) 280 | 281 | ; SEARCH = MATCH+DEFINE 282 | (global-set-key 283 | "\C-c\M-s" 284 | '(lambda () 285 | (interactive) 286 | (save-dictem 287 | (let* ((dictem-server (read-string "server: " 288 | dictem-server nil "dict.org")) 289 | (dictem-port (read-string "port: " 290 | (dictem-get-port) nil "2628"))) 291 | (dictem-initialize) 292 | (call-interactively 'dictem-run-search))))) 293 | 294 | ; SHOW INFO 295 | (global-set-key 296 | "\C-c\M-i" 297 | '(lambda () 298 | (interactive) 299 | (save-dictem 300 | (let* ((dictem-server (read-string "server: " 301 | dictem-server nil "dict.org")) 302 | (dictem-port (read-string "port: " 303 | (dictem-get-port) nil "2628"))) 304 | (dictem-initialize) 305 | (call-interactively 'dictem-run-show-info))))) 306 | 307 | ; SHOW SERVER 308 | (global-set-key 309 | "\C-c\M-r" 310 | '(lambda () 311 | (interactive) 312 | (save-dictem 313 | (let* ((dictem-server (read-string "server: " 314 | dictem-server nil "dict.org")) 315 | (dictem-port (read-string "port: " 316 | (dictem-get-port) nil "2628"))) 317 | (dictem-initialize) 318 | (call-interactively 'dictem-run-show-server))))) 319 | 320 | ------- 321 | Ex.8 322 | 323 | Some databases may have specially formatted definitions, 324 | for example, HTML, MIME, DICF or ROFF formats. 325 | It is easy to postprocess them. 326 | 327 | ; All functions from dictem-postprocess-each-definition-hook 328 | ; will be run for each definition which in turn will be narrowed. 329 | ; Current database name is kept in dictem-current-dbname variable. 330 | ; The following code demonstrates how to highlight SUSV3 and ROFF 331 | ; definitions. 332 | (add-hook 'dictem-postprocess-definition-hook 333 | 'dictem-postprocess-each-definition) 334 | 335 | ; Function for highlighting definition from the database "susv3". 336 | (defun dictem-highlight-susv3-definition () 337 | (cond ((string= "susv3" dictem-current-dbname) 338 | (goto-char (point-min)) 339 | (while (search-forward-regexp 340 | "^ *[QWERTYUIOPASDFGHJKLZXCVBNM ]+$" nil t) 341 | (put-text-property 342 | (match-beginning 0) (match-end 0) 'face 'bold) 343 | )))) 344 | 345 | ; Function to show roff-formatted text from the database "man". 346 | (require 'woman) 347 | (defun dictem-highlight-man-definition () 348 | (cond ((string= "man" dictem-current-dbname) 349 | (goto-char (point-min)) 350 | (while (search-forward-regexp "^ " nil t) 351 | (replace-match "")) 352 | (goto-char (point-min)) 353 | (forward-line 2) 354 | (woman-decode-region (point) (point-max)) 355 | ))) 356 | 357 | (add-hook 'dictem-postprocess-each-definition-hook 358 | 'dictem-highlight-susv3-definition) 359 | (add-hook 'dictem-postprocess-each-definition-hook 360 | 'dictem-highlight-man-definition) 361 | 362 | ------- 363 | Ex.9 364 | 365 | ; The dictem's top level function is 'dictem-run'. 366 | ; By using it more advanced ELISP programmers 367 | ; can create their own search scenaria. Look at this code. 368 | 369 | (dictem-run 370 | 'dictem-base-search 371 | "gcide" "apple" "lev") 372 | 373 | (dictem-run 374 | 'dictem-base-match 375 | "dict://mova.org/mueller7" "apple" "exact") 376 | 377 | (dictem-run 378 | 'dictem-base-define 379 | '("dict://mova.org/mueller7" "dict://dict.org/gcide") 380 | "apple" "exact") 381 | 382 | (dictem-run 'dictem-base-show-info "dict://dict.org/gcide") 383 | 384 | (let ((dictem-server "localhost")) 385 | (dictem-run 386 | '(lambda (a b c) 387 | (dictem-base-show-strategies nil nil nil) 388 | (dictem-base-show-databases nil nil nil) 389 | (dictem-base-show-server nil nil nil) 390 | ))) 391 | 392 | (dictem-run 393 | '(lambda (a b c) 394 | (dictem-base-define 395 | '("man" "susv3") 396 | (dictem-read-query (thing-at-point 'word)) 397 | nil )) 398 | nil nil) 399 | 400 | (let ((query (dictem-read-query (thing-at-point 'word)))) 401 | (dictem-run 402 | `((lambda (a b c) 403 | (dictem-base-match 404 | '("gcide" "wn") 405 | ,query "exact")) 406 | (lambda (a b c) 407 | (dictem-base-search 408 | '("mueller7" "korolew_en-ru") 409 | ,query "word"))))) 410 | 411 | ------- 412 | Ex.10 413 | 414 | By default dictem remembers the database name and strategy that 415 | was used last time. 416 | The dictem-select-database and dictem-select-strategy functions 417 | will use these values as a default in the minibuffer. 418 | If you dislike this behaviour, set variables 419 | dictem-default-database and/or dictem-default-strategy. 420 | 421 | (add-hook 'c-mode-common-hook 422 | '(lambda () 423 | (interactive) 424 | (make-local-variable 'dictem-default-database) 425 | (setq dictem-default-database "man") 426 | )) 427 | 428 | The example above sets default database to "man" 429 | in C buffers. 430 | 431 | ------- 432 | Ex.11 433 | 434 | As of dictem-0.0.4 dictem-empty-initial-input customizable variable 435 | tells dictem-read-query whether to leave initial input empty or not. 436 | It is `nil' by default. 437 | For emulating behaviour of older releases, set it to `t'. 438 | 439 | (setq dictem-empty-initial-input t) 440 | 441 | ------- 442 | Ex. 12 443 | 444 | By default dictem-postprocess-definition-hyperlinks function 445 | assumes that hyperlinks have the following form: {foo} or {foo|bar}. 446 | Sometimes "{" and "}" characters are general characters 447 | in definitions. The following code changes "{" and "}" for 448 | "{link-beg " and " link-end" respectively 449 | inside definitions obtained from the databases "^infopage-..." 450 | 451 | ; new function is used for creating hyperlinks 452 | ; which works differently depending on database name 453 | (defun my-dictem-postprocess-definition-hyperlinks () 454 | "Creating hyperlinks according to database name" 455 | (interactive) 456 | (cond ( 457 | ((string-match "^infopage-" dictem-current-dbname) 458 | (let ((dictem-hyperlink-beginning "{link-beg ") 459 | (dictem-hyperlink-end " link-end}") 460 | ) 461 | (dictem-postprocess-definition-hyperlinks))) 462 | (t (dictem-postprocess-definition-hyperlinks))))) 463 | 464 | ; definitions from each database are processed separately 465 | (add-hook 'dictem-postprocess-definition-hook 466 | 'dictem-postprocess-each-definition) 467 | (add-hook 'dictem-postprocess-each-definition-hook 468 | 'my-dictem-postprocess-definition-hyperlinks) 469 | 470 | ------- 471 | Ex. 13 472 | 473 | You may want to remove "XXX definition[s] found" header 474 | from the DEFINE buffers. 475 | It may be done with a help of 476 | dictem-postprocess-definition-remove-header function. 477 | 478 | (add-hook 'dictem-postprocess-definition-hook 479 | 'dictem-postprocess-definition-remove-header) 480 | 481 | ------- 482 | Ex. 14 483 | 484 | As of version 0.7 dictem can handle dictionaries defined by user. 485 | This allows to use dictem not only for accessing DICT servers, 486 | but also for accesing users' databases. 487 | 488 | ; DEFINE function for the database "mysuperdb" 489 | (defun dictem-mysuperdb-DEFINE (query) 490 | (cond 491 | ((string= query "apple") '("Apples grow on the trees" 492 | "Apple may be green, yellow or red")) 493 | ((string= query "potato") '("Potato is a vegetable" 494 | "Potato is a traditional Belarusian food")) 495 | (t (dictem-make-error 496 | 20 (format "No definitions for %s" query))) 497 | )) 498 | 499 | ; MATCH function for the database "mysuperdb" 500 | (defun dictem-mysuperdb-MATCH (query strategy) 501 | ; the name of strategy is ignored 502 | (let ((apple (string-match query "apple")) 503 | (potato (string-match query "potato"))) 504 | (cond 505 | ((and (string= strategy "exact") (string= query "apple")) 506 | '("apple")) 507 | ((and (string= strategy "exact") (string= query "potato")) 508 | '("potato")) 509 | ((and apple potato) 510 | '("apple" "potato")) 511 | (apple 512 | '("apple")) 513 | (potato 514 | '("potato")) 515 | (t (dictem-make-error 516 | 20 (format "No matches for %s/%s" query strategy))) 517 | ))) 518 | 519 | ; Initializing a list of user-defined databases 520 | (setq dictem-user-databases-alist 521 | `(("_en-en" . ("foldoc" "gcide" "wn")) 522 | ("_ru-ru" . ("beslov" "ushakov" "ozhegov" "brok_and_efr")) 523 | ,(dictem-make-userdb 524 | ; the name of the database 525 | "mysuperdb" 526 | ; short description 527 | "My super database" 528 | ; MATCH function 529 | (symbol-function 'dictem-mysuperdb-MATCH) 530 | ; DEFINE function 531 | (symbol-function 'dictem-mysuperdb-DEFINE)) 532 | )) 533 | 534 | ------- 535 | Ex. 15 536 | 537 | Last years many dictionary servers provide too many bilingual dictionaries, 538 | most of which may be not very interesting for you. 539 | DictEm allows to exclude such dictionaries from an autocompletion menu 540 | by setting a list of regular expressions in dictem-exclude-databases 541 | variable. 542 | If, for example, you don't speak french and german and use 543 | dict://dict.org server, your config may look like this 544 | 545 | (setq dictem-server "dict.org") 546 | (setq dictem-exclude-databases '("ger-" "-ger" "fra-" "-fra")) 547 | (dictem-initialize) 548 | 549 | Note that, (dictem-initialize) is placed after initializing 550 | dictem-exclude-databases variable. 551 | 552 | ------- 553 | If you have read to this point and all the examples above seem easy, 554 | you are probably a ELISP Guru. 555 | So, I have nothing more to tell you ;-) 556 | Feel free to inspect the code, and I hope you'll find DictEm useful. 557 | 558 | Dict'em All! ;-) 559 | -------------------------------------------------------------------------------- /dictem.el: -------------------------------------------------------------------------------- 1 | ;;; dictem.el --- DICT protocol client (rfc-2229) for [X]Emacs 2 | 3 | ;; This code was initially based on 4 | ;; dictionary.el written by Torsten Hilbrich 5 | ;; but now probably doesn't contain original code. 6 | ;; Most of the code has been written 7 | ;; from scratch by Aleksey Cheusov , 2004-2008. 8 | ;; 9 | ;; DictEm is free software; you can redistribute it and/or modify it 10 | ;; under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation; either version 2 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; DictEm is distributed in the hope that it will be useful, but 15 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | ;; General Public License for more details. 18 | ;; 19 | ;; You should have received a copy of the GNU General Public License 20 | ;; along with this program; if not, write to the Free Software 21 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 22 | ;; 02111-1307, USA 23 | 24 | ;;; Commentary: 25 | 26 | ;; DICT protocol client (rfc-2229) for [X]Emacs 27 | 28 | ;; NOTE! Documentation is in README file. 29 | ;; 30 | ;; Latest information about dictem project and sources 31 | ;; are available at 32 | ;; 33 | ;; http://freshmeat.net/projects/dictem 34 | ;; http://sourceforge.net/projects/dictem 35 | ;; http://mova.org/~cheusov/pub/dictem 36 | 37 | ;;; Code: 38 | 39 | (require 'cl) 40 | 41 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 42 | ;;;;; Custom Things ;;;;; 43 | 44 | (defgroup dictem nil 45 | "Client for accessing the DICT server." 46 | :tag "DictEm" 47 | :group 'help 48 | :group 'hypermedia) 49 | 50 | (defgroup dictem-faces nil 51 | "Face options for dictem DICT client." 52 | :tag "DictEm faces" 53 | :group 'dictem 54 | :group 'faces) 55 | 56 | (defcustom dictem-server nil 57 | "The DICT server" 58 | :group 'dictem 59 | :type '(restricted-sexp :match-alternatives (stringp 'nil))) 60 | 61 | (defcustom dictem-port 2628 62 | "The port of the DICT server" 63 | :group 'dictem 64 | :type 'number) 65 | 66 | (defcustom dictem-client-prog "dict" 67 | "The command line DICT client. 68 | dictem accesses DICT server through this executable. 69 | dict-1.9.14 or later (or compatible) is strongly recomented." 70 | :group 'dictem 71 | :type 'string) 72 | 73 | (defcustom dictem-client-prog-args-list nil 74 | "A list of additional arguments (strings) passed to dict client. 75 | For example '(\"--some-option\")." 76 | :group 'dictem 77 | :type 'list) 78 | 79 | (defcustom dictem-option-mime nil 80 | "If `t' the OPTION MIME command (see RFC-2229 for details) 81 | will be sent to the DICT server. i.e. \"dict\" program 82 | will be run with \"-M\" option. 83 | As a result server's response will be prepanded with MIME header 84 | followed by a blank line. 85 | Because of bugs in dict -M (version < 1.10.3) utility, 86 | dict-1.10.3 or later is strongly recommended 87 | " 88 | :group 'dictem 89 | :type 'boolean) 90 | 91 | (defcustom dictem-default-strategy nil 92 | "The default search strategy." 93 | :group 'dictem 94 | :type 'string) 95 | 96 | (defcustom dictem-default-database nil 97 | "The default database name." 98 | :group 'dictem 99 | :type 'string) 100 | 101 | (defcustom dictem-user-databases-alist 102 | nil 103 | "ALIST of user's \"virtual\"databases. 104 | Valid value looks like this: 105 | '((\"en-ru\" . (\"mueller7\" \"korolew_en-ru\")) 106 | ((\"en-en\" . (\"foldoc\" \"gcide\" \"wn\"))) 107 | ((\"gazetteer\" . \"gaz\"))) 108 | " 109 | :group 'dictem 110 | :type '(alist :key-type string)) 111 | 112 | (defcustom dictem-exclude-databases 113 | nil 114 | "ALIST of regexps for databases 115 | that will not appear in autocompletion list. 116 | " 117 | :group 'dictem 118 | :type '(alist :key-type string)) 119 | 120 | (defcustom dictem-use-user-databases-only 121 | nil 122 | "If `t', only user's dictionaries from dictem-user-databases-alist 123 | will be used by dictem-select-database" 124 | :group 'dictem 125 | :type 'boolean) 126 | 127 | (defcustom dictem-mode-hook 128 | nil 129 | "Hook run in dictem mode buffers." 130 | :group 'dictem 131 | :type 'hook) 132 | 133 | (defcustom dictem-use-existing-buffer 134 | nil 135 | "If `t' the `dictem-run' function will not create new *dictem* buffer. 136 | Instead, existing buffer will be erased and used to show results. 137 | " 138 | :group 'dictem 139 | :type 'boolean) 140 | 141 | (defcustom dictem-empty-initial-input 142 | nil 143 | "If `t' the `dictem-read-query' leave initial input empty" 144 | :group 'dictem 145 | :type 'boolean) 146 | 147 | (defcustom dictem-use-content-history t 148 | "If not nil and dictem-use-existing-buffer is also not nil, 149 | buffer content and (point) is saved in dictem-content-history variable 150 | when DEFINE hyperlinks are accessed. 151 | It is restored by dictem-last function. 152 | On slow machines it may better to set this variable to nil" 153 | :group 'dictem) 154 | 155 | ;;;;; Faces ;;;;; 156 | 157 | (defface dictem-reference-definition-face 158 | '((((background light)) (:foreground "blue")) 159 | (((background dark)) (:foreground "cyan"))) 160 | 161 | "The face that is used for displaying a reference to 162 | a phrase in a DEFINE search." 163 | :group 'dictem-faces) 164 | 165 | (defface dictem-reference-m1-face 166 | '((((background light)) (:foreground "darkgreen")) 167 | (((background dark)) (:foreground "lightblue"))) 168 | 169 | "The face that is used for displaying a reference to 170 | a phrase in a MATCH search." 171 | :group 'dictem-faces) 172 | 173 | (defface dictem-reference-m2-face 174 | '((((background light)) (:foreground "blue")) 175 | (((background dark)) (:bold true :foreground "gray"))) 176 | 177 | "The face that is used for displaying a reference to 178 | a single word in a MATCH search." 179 | :group 'dictem-faces) 180 | 181 | (defface dictem-reference-dbname-face 182 | '((((background light)) (:foreground "darkgreen")) 183 | (((background dark)) (:bold t :foreground "white"))) 184 | 185 | "The face that is used for displaying a reference to database" 186 | :group 'dictem-faces) 187 | 188 | (defface dictem-database-description-face 189 | '((((background light)) (:bold t :foreground "darkblue")) 190 | (((background dark)) (:bold t :foreground "white"))) 191 | 192 | "The face that is used for displaying a database description" 193 | :group 'dictem-faces) 194 | 195 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 196 | ;;;;; Variables ;;;;; 197 | 198 | (defconst dictem-version "1.0.4" 199 | "DictEm version information.") 200 | 201 | (defvar dictem-strategy-alist 202 | nil 203 | "ALIST of search strategies") 204 | 205 | (defvar dictem-database-alist 206 | nil 207 | "ALIST of databases") 208 | 209 | (defvar dictem-strategy-history 210 | nil 211 | "List of strategies entered from minibuffer") 212 | 213 | (defvar dictem-database-history 214 | nil 215 | "List of database names entered from minibuffer") 216 | 217 | (defvar dictem-query-history 218 | nil 219 | "List of queries entered from minibuffer") 220 | 221 | (defvar dictem-last-database 222 | "*" 223 | "Last used database name") 224 | 225 | (defvar dictem-last-strategy 226 | "." 227 | "Last used strategy name") 228 | 229 | (defvar dictem-mode-map 230 | nil 231 | "Keymap for dictem mode") 232 | 233 | (defvar dictem-temp-buffer-name 234 | "*dict-temp*" 235 | "Temporary dictem buffer name") 236 | 237 | (defvar dictem-current-dbname 238 | nil 239 | "This variable keeps a database name of the definition 240 | currently processed 241 | by functions run from dictem-postprocess-each-definition-hook.") 242 | 243 | (defvar dictem-error-messages 244 | nil 245 | "A list of error messages collected by dictem-run") 246 | 247 | (defvar dictem-hyperlinks-alist 248 | nil 249 | "ALIST of hyperlinks collected from dictem buffer by 250 | the function dictem-postprocess-collect-hyperlinks 251 | (add this function to the hook dictem-postprocess-definition-hook). 252 | This variable is local to buffer") 253 | 254 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 255 | 256 | (defun dictem-prepand-special-strats (l) 257 | (cons '(".") l)) 258 | 259 | (defun dictem-prepand-special-dbs (l) 260 | (cons '("*") (cons '("!") l))) 261 | 262 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 263 | ;;;;; Functions ;;;;;; 264 | 265 | (defmacro save-dictem (&rest funs) 266 | `(let ((dictem-port 2628) 267 | (dictem-server nil) 268 | (dictem-database-alist nil) 269 | (dictem-strategy-alist nil) 270 | (dictem-use-user-databases-only nil) 271 | (dictem-user-databases-alist nil) 272 | ) 273 | (progn ,@funs) 274 | )) 275 | 276 | (defun dictem-client-text () 277 | "Returns a portion of text sent to the server for identifying a client" 278 | (concat "dictem " dictem-version ", DICT client for emacs")) 279 | 280 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 281 | ;; Functions related to userdb ;; 282 | 283 | (defun dictem-make-userdb (name short-name match define) 284 | "Make user database object" 285 | (list name 'dictem-userdb 286 | short-name match define)) 287 | 288 | (defun dictem-userdb-p (obj) 289 | "Returns t if obj is the dictem error object" 290 | (and obj (listp obj) (cdr obj) (listp (cdr obj)) 291 | (eq (cadr obj) 'dictem-userdb))) 292 | 293 | (defun dictem-userdb-member (obj name) 294 | "Extract member from userdb object by its name" 295 | (cond ((dictem-userdb-p obj) 296 | (nth (cdr (assoc name 297 | '(("name" . 0) ("short-name" . 2) 298 | ("match" . 3) ("define" . 4)))) 299 | obj)) 300 | (t (error "Invalid type of argument")))) 301 | 302 | (defun dictem-userdb-DEFINE (buffer db query host port) 303 | (let* ((fun (dictem-userdb-member db "define")) 304 | (name (dictem-userdb-member db "name")) 305 | (sname (dictem-userdb-member db "short-name")) 306 | (ret (save-excursion (funcall fun query))) 307 | (buf (dictem-get-buffer buffer))) 308 | (save-excursion 309 | (set-buffer buf) 310 | (cond ((dictem-error-p ret) 311 | ; (insert "From " sname " [" name "]:\n\n" 312 | ; (dictem-error-message ret) "\n\n") 313 | ; (insert (dictem-error-message ret) "\n") 314 | (insert (dictem-error-message ret) "\n") 315 | (dictem-error-status ret)) 316 | ((null ret) 317 | (insert "No matches found" "\n") 318 | 20) 319 | ((listp ret) 320 | (dolist (definition ret) 321 | (insert "From " sname " [" name "]:\n\n" 322 | (dictem-indent-string definition) "\n\n")) 323 | 0) 324 | ((stringp ret) 325 | (insert "From " sname " [" name "]:\n\n" 326 | (dictem-indent-string ret) "\n\n") 327 | 0) 328 | (t 329 | (error "Invalid type of returned value1")))))) 330 | 331 | (defun dictem-userdb-MATCH (buffer db query strat host port) 332 | (let* ((fun (dictem-userdb-member db "match")) 333 | (name (dictem-userdb-member db "name")) 334 | (ret (save-excursion (funcall fun query strat))) 335 | (buf (dictem-get-buffer buffer))) 336 | (save-excursion 337 | (set-buffer buf) 338 | (cond ((dictem-error-p ret) 339 | (insert (dictem-error-message ret) "\n") 340 | (dictem-error-status ret)) 341 | ((listp ret) 342 | (insert (concat name ":\n")) 343 | (dolist (match ret); (insert (car db) ":\n" )) 344 | (progn 345 | (insert " " match "\n")) 346 | ) 347 | 0) 348 | (t 349 | (error "Invalid type of returned value2")))))) 350 | 351 | (defun dictem-userdb-SEARCH (buffer db query strat host port) 352 | (let* ((funm (dictem-userdb-member db "match")) 353 | (name (dictem-userdb-member db "name")) 354 | (sname (dictem-userdb-member db "short-name")) 355 | (sname nil) 356 | (ret (funcall funm query strat)) 357 | (buf (dictem-get-buffer buffer))) 358 | (save-excursion 359 | (set-buffer buf) 360 | (cond ((dictem-error-p ret) 361 | (insert (dictem-error-message ret) "\n") 362 | (dictem-error-status ret)) 363 | ((listp ret) 364 | (dolist (match ret) 365 | (dictem-userdb-DEFINE buffer db 366 | match host port)) 367 | 0) 368 | (t 369 | (error "Something strange happened")) 370 | )))) 371 | 372 | (defun dictem-userdb-SHOW-INFO (buffer db host port) 373 | (let ((sname (dictem-userdb-member db "short-name")) 374 | (buf (dictem-get-buffer buffer))) 375 | (save-excursion 376 | (set-buffer buf) 377 | (cond ((dictem-error-p sname) 378 | (insert (dictem-error-message sname) "\n") 379 | (dictem-error-status sname)) 380 | ((stringp sname) 381 | (insert sname) 382 | 0) 383 | (t 384 | (error "Something strange happened")) 385 | )))) 386 | 387 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 388 | ;; Functions related to error object ;; 389 | 390 | (defun dictem-make-error (error_status &optional buffer-or-string) 391 | "Creates dictem error object" 392 | (cond 393 | ((stringp buffer-or-string) 394 | (list 'dictem-error error_status buffer-or-string)) 395 | ((bufferp buffer-or-string) 396 | (dictem-make-error 397 | error_status 398 | (save-excursion 399 | (set-buffer buffer-or-string) 400 | (goto-char (point-min)) 401 | (dictem-get-line) 402 | ))) 403 | ((eq nil buffer-or-string) 404 | (list 'dictem-error error_status buffer-or-string)) 405 | (t 406 | (error "Invalid type of argument")) 407 | )) 408 | 409 | (defun dictem-error-p (OBJECT) 410 | "Returns t if OBJECT is the dictem error object" 411 | (and 412 | (not (null OBJECT)) 413 | (listp OBJECT) 414 | (eq (car OBJECT) 'dictem-error) 415 | )) 416 | 417 | (defun dictem-error-message (err) 418 | "Extract error message from dictem error object" 419 | (cond 420 | ((dictem-error-p err) 421 | (nth 2 err)) 422 | (t 423 | (error "Invalid type of argument")) 424 | )) 425 | 426 | (defun dictem-error-status (err) 427 | "Extract error status from dictem error object" 428 | (cond 429 | ((dictem-error-p err) 430 | (nth 1 err)) 431 | (t 432 | (error "Invalid type of argument")) 433 | )) 434 | 435 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 436 | 437 | (defun dictem-collect-matches () 438 | ; nreverse, setcar and nconc are used to reduce a number of cons 439 | (goto-char (point-min)) 440 | (let ((dictem-temp nil)) 441 | (loop 442 | (let ((line (dictem-get-line))) 443 | (if (string-match "^[^ ]+:" line) 444 | (progn 445 | (if (consp dictem-temp) 446 | (setcar (cdar dictem-temp) 447 | (nreverse (cadar dictem-temp)))) 448 | (setq 449 | dictem-temp 450 | (cons 451 | (list 452 | (substring line (match-beginning 0) (- (match-end 0) 1)) 453 | (nreverse 454 | (dictem-tokenize (substring line (match-end 0))))) 455 | dictem-temp))) 456 | (if (consp dictem-temp) 457 | (setcar (cdar dictem-temp) 458 | (nconc (nreverse (dictem-tokenize line)) 459 | (cadar dictem-temp)) 460 | )) 461 | )) 462 | (if (or (> (forward-line 1) 0) 463 | (> (current-column) 0)) 464 | (return (nreverse dictem-temp))) 465 | ))) 466 | 467 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 468 | 469 | (defun dictem-get-buffer (buf) 470 | (cond 471 | ((bufferp buf) buf) 472 | (buf (current-buffer)) 473 | (t (get-buffer-create dictem-temp-buffer-name)) 474 | )) 475 | 476 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 477 | ;;; call-process functions 478 | 479 | (defun dictem-local-dict-basic-option (host port option-mime) 480 | (let ((server-host (if host host (dictem-get-server)))) 481 | (append 482 | (list "-P" "-") 483 | (if server-host 484 | (list "-h" server-host "-p" (dictem-get-port port))) 485 | (if option-mime '("-M")) 486 | dictem-client-prog-args-list 487 | ))) 488 | 489 | (defun dictem-call-process (buffer host port args) 490 | (let (coding-system 491 | coding-system-for-read 492 | coding-system-for-write) 493 | (if (and (functionp 'coding-system-list) 494 | (member 'utf-8 (coding-system-list))) 495 | (setq coding-system 'utf-8)) 496 | (setq coding-system-for-read coding-system) 497 | (setq coding-system-for-write coding-system) 498 | (apply 'call-process 499 | `(,dictem-client-prog 500 | nil 501 | ,(dictem-get-buffer buffer) 502 | nil 503 | ,@(dictem-local-dict-basic-option host port nil) 504 | ,@args 505 | )))) 506 | 507 | (defun dictem-call-process-SHOW-SERVER (buffer host port) 508 | (dictem-call-process buffer host port '("-I"))) 509 | 510 | (defun dictem-call-process-SHOW-INFO (buffer db host port) 511 | (dictem-call-process buffer host port (list "-i" db))) 512 | 513 | (defun dictem-call-process-SHOW-STRAT (buffer host port) 514 | (dictem-call-process buffer host port '("-S"))) 515 | 516 | (defun dictem-call-process-SHOW-DB (buffer host port) 517 | (dictem-call-process buffer host port '("-D"))) 518 | 519 | (defun dictem-call-process-MATCH (buffer db query strat host port) 520 | (dictem-call-process 521 | buffer host port 522 | (list "-m" 523 | "-d" (if db db "*") 524 | "-s" (if strat strat ".") 525 | query))) 526 | 527 | (defun dictem-call-process-DEFINE (buffer db query host port) 528 | (dictem-call-process 529 | buffer host port 530 | (list "-d" (if db db "*") query))) 531 | 532 | (defun dictem-call-process-SEARCH (buffer db query strat host port) 533 | (dictem-call-process 534 | buffer host port 535 | (list "-d" (if db db "*") 536 | "-s" (if strat strat ".") 537 | query))) 538 | 539 | ;;;;; GET Functions ;;;;; 540 | 541 | (defun dictem-get-matches (query &optional database strategy server port) 542 | "Returns ALIST of matches" 543 | (let ((exit_status 544 | (dictem-call-process-MATCH nil database query strategy server port) 545 | )) 546 | (cond 547 | ((= exit_status 20) ;20 means "no matches found", See dict(1) 548 | (kill-buffer dictem-temp-buffer-name) 549 | nil) 550 | ((= exit_status 0) 551 | (progn 552 | (save-excursion 553 | (set-buffer dictem-temp-buffer-name) 554 | (let ((matches (dictem-collect-matches))) 555 | (kill-buffer dictem-temp-buffer-name) 556 | matches)))) 557 | (t 558 | (let 559 | ((err (dictem-make-error exit_status 560 | (get-buffer dictem-temp-buffer-name)))) 561 | (kill-buffer dictem-temp-buffer-name) 562 | err)) 563 | ))) 564 | 565 | (defun dictem-get-strategies (&optional server port) 566 | "Obtains strategy ALIST from a DICT server 567 | and returns alist containing strategies and their descriptions" 568 | (let ((exit_status 569 | (dictem-call-process-SHOW-STRAT nil server port) 570 | )) 571 | (cond 572 | ((= exit_status 0) 573 | (save-excursion 574 | (set-buffer dictem-temp-buffer-name) 575 | (goto-char (point-min)) 576 | (let ((regexp "^ \\([^ ]+\\) +\\(.*\\)$") 577 | (l nil)) 578 | (while (search-forward-regexp regexp nil t) 579 | (setq l (cons 580 | (list 581 | (buffer-substring-no-properties 582 | (match-beginning 1) (match-end 1)) 583 | (buffer-substring-no-properties 584 | (match-beginning 2) (match-end 2))) 585 | l))) 586 | (kill-buffer dictem-temp-buffer-name) 587 | l))) 588 | (t 589 | (let 590 | ((err (dictem-make-error exit_status 591 | (get-buffer dictem-temp-buffer-name)))) 592 | (kill-buffer dictem-temp-buffer-name) 593 | err)) 594 | ))) 595 | 596 | (defun dictem-get-databases (&optional server port) 597 | "Obtains database ALIST from a DICT server 598 | and returns alist containing database names and descriptions" 599 | (let ((exit_status 600 | (dictem-call-process-SHOW-DB nil server port) 601 | )) 602 | (cond 603 | ((= exit_status 0) 604 | (save-excursion 605 | (set-buffer dictem-temp-buffer-name) 606 | (goto-char (point-min)) 607 | (let ((regexp "^ \\([^ ]+\\) +\\(.*\\)$") 608 | (l nil)) 609 | (while (search-forward-regexp regexp nil t) 610 | (let ((dbname (buffer-substring-no-properties 611 | (match-beginning 1) (match-end 1))) 612 | (dbdescr (buffer-substring-no-properties 613 | (match-beginning 2) (match-end 2)))) 614 | (if (not (string= "--exit--" dbname)) 615 | (setq l (cons (list dbname dbdescr) l))))) 616 | (kill-buffer dictem-temp-buffer-name) 617 | l))) 618 | (t 619 | (let 620 | ((err (dictem-make-error exit_status 621 | (get-buffer dictem-temp-buffer-name)))) 622 | (kill-buffer dictem-temp-buffer-name) 623 | err)) 624 | ))) 625 | 626 | (defun dictem-get-default-strategy (&optional def-strat) 627 | "Gets the default search strategy" 628 | (if def-strat 629 | def-strat 630 | (if dictem-default-strategy 631 | dictem-default-strategy 632 | (if dictem-last-strategy 633 | dictem-last-strategy 634 | ".")))) 635 | 636 | (defun dictem-extract-dbname (database) 637 | (cond 638 | ((consp database) (dictem-extract-dbname (car database))) 639 | ((stringp database) database) 640 | (t (error "The database should be either stringp or consp")) 641 | )) 642 | 643 | (defun dictem-get-default-database (&optional def-db) 644 | "Returns the default database" 645 | 646 | (if def-db 647 | (dictem-extract-dbname def-db) 648 | (if dictem-default-database 649 | (dictem-extract-dbname dictem-default-database) 650 | (if dictem-last-database 651 | (dictem-extract-dbname dictem-last-database) 652 | "*")))) 653 | 654 | ;;;;; Low Level Functions ;;;;; 655 | 656 | (defun dictem-db-should-be-excluded (dbname) 657 | "Returns t if a dbname should is not interesting for user. 658 | See dictem-exclude-databases variable" 659 | (let ((ret nil)) 660 | (dolist (re dictem-exclude-databases) 661 | (if (string-match re dbname) 662 | (setq ret t))) 663 | ret)) 664 | 665 | (defun dictem-delete-alist-predicate (l pred) 666 | "makes a copy of l with no items for which (pred item) is true" 667 | (let ((ret nil)) 668 | (dolist (item l) 669 | (if (not (funcall pred (car item))) 670 | (setq ret (cons item ret)))) 671 | ret)) 672 | 673 | (defun dictem-get-line () 674 | "Replacement for (thing-at-point 'line)" 675 | (save-excursion 676 | (buffer-substring-no-properties 677 | (progn (beginning-of-line) (point)) 678 | (progn (end-of-line) (point))))) 679 | 680 | (defun dictem-list2alist (l) 681 | (cond 682 | ((null l) nil) 683 | (t (cons 684 | (list (car l) nil) 685 | (dictem-list2alist (cdr l)))))) 686 | 687 | (defun dictem-indent-string (str) 688 | (let ((start 0)) 689 | (while (string-match "\n" str start) 690 | (progn 691 | (setq start ( + 2 (match-end 0))) 692 | (setq str (replace-match "\n " t t str))))) 693 | (concat " " str)) 694 | 695 | (defun dictem-replace-spaces (str) 696 | (while (string-match "[ \n][ \n]+" str) 697 | (setq str (replace-match " " t t str))) 698 | (if (string-match "^ +" str) 699 | (setq str (replace-match "" t t str))) 700 | (if (string-match " +$" str) 701 | (setq str (replace-match "" t t str))) 702 | str) 703 | 704 | (defun dictem-remove-value-from-alist (l) 705 | (let ((ret nil)) 706 | (dolist (i l) 707 | (setq ret (cons (list (car i)) ret))) 708 | (reverse ret) 709 | )) 710 | ;(defun dictem-remove-value-from-alist (l) 711 | ; (cond 712 | ; ((symbolp l) l) 713 | ; (t (cons (list (caar l)) 714 | ; (dictem-remove-value-from-alist (cdr l)))))) 715 | 716 | (defun dictem-select (prompt alist default history) 717 | (let* 718 | ((completion-ignore-case t) 719 | (str (completing-read 720 | (concat prompt " [" default "]: ") 721 | alist nil t nil history default)) 722 | (str-cons (assoc str alist))) 723 | (cond 724 | ((and str-cons (consp str-cons) (cdr str-cons)) 725 | str-cons) 726 | ((and str-cons (consp str-cons)) 727 | (car str-cons)) 728 | (t nil)))) 729 | 730 | (defun dictem-tokenize (s) 731 | (if (string-match "\"[^\"]+\"\\|[^ \"]+" s ) 732 | ; (substring s (match-beginning 0) (match-end 0)) 733 | (cons (substring s (match-beginning 0) (match-end 0)) 734 | (dictem-tokenize (substring s (match-end 0)))) 735 | nil)) 736 | 737 | ;(defun dictem-search-forward-regexp-cs (REGEXP &optional BOUND NOERROR COUNT) 738 | ; "Case-sensitive variant for search-forward-regexp" 739 | ; (let ((case-replace nil) 740 | ; (case-fold-search nil)) 741 | ; (search-forward-regexp REGEXP BOUND NOERROR COUNT))) 742 | 743 | ;(defun dictem-replace-match-cs (NEWTEXT &optional FIXEDCASE LITERAL STRING SUBEXP) 744 | ; "Case-sensitive variant for replace-match" 745 | ; (let ((case-replace nil) 746 | ; (case-fold-search nil)) 747 | ; (replace-match NEWTEXT FIXEDCASE LITERAL STRING SUBEXP))) 748 | 749 | (defun dictem-get-port (&optional port) 750 | (let ((p (if port port dictem-port))) 751 | (cond 752 | ((and (stringp p) (string= "" p)) 2628) 753 | ((null p) 2628) 754 | ((stringp p) p) 755 | ((numberp p) (number-to-string p)) 756 | (t (error "The value of dictem-port variable should be \ 757 | either a string or a number")) 758 | ))) 759 | 760 | (defun dictem-get-server () 761 | (cond 762 | ((and (stringp dictem-server) (string= "" dictem-server)) nil) 763 | ((stringp dictem-server) dictem-server) 764 | ((null dictem-server) nil) 765 | (t (error "The value of dictem-server variable should be \ 766 | either a string or a nil")) 767 | )) 768 | 769 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 770 | ;;;;; Main Functions ;;;;; 771 | 772 | ;;;;;; Functions for Initializing ;;;;;; 773 | 774 | (defun dictem-initialize-strategies-alist (&optional server port) 775 | "Obtain strategy ALIST from a DICT server 776 | and sets dictem-strategy-alist variable." 777 | (interactive) 778 | (setq dictem-strategy-alist (dictem-get-strategies 779 | server 780 | (dictem-get-port port)))) 781 | 782 | (defun dictem-initialize-databases-alist (&optional server port) 783 | "Obtain database ALIST from a DICT server 784 | and sets dictem-database-alist variable." 785 | (interactive) 786 | (setq dictem-database-alist 787 | (dictem-get-databases server (dictem-get-port port))) 788 | (if (dictem-error-p dictem-database-alist) 789 | dictem-database-alist 790 | (setq dictem-database-alist 791 | (dictem-delete-alist-predicate 792 | dictem-database-alist 793 | 'dictem-db-should-be-excluded)))) 794 | 795 | (defun dictem-initialize () 796 | "Initializes dictem, i.e. obtains 797 | a list of available databases and strategiss from DICT server 798 | and makes other tasks." 799 | (interactive) 800 | (let ((dbs (dictem-initialize-databases-alist)) 801 | (strats (dictem-initialize-strategies-alist))) 802 | (if (dictem-error-p dbs) 803 | dbs strats))) 804 | 805 | (defun dictem-reinitialize-err () 806 | "Initializes dictem if it is not initialized yet 807 | and run (error ...) if an initialization fails" 808 | (interactive) 809 | (if (or (dictem-error-p dictem-database-alist) 810 | (null dictem-database-alist)) 811 | (if (dictem-error-p (dictem-initialize)) 812 | (error (dictem-error-message dictem-database-alist))))) 813 | 814 | ;;; Functions related to Minibuffer ;;;; 815 | 816 | (defun dictem-select-strategy (&optional default-strat) 817 | "Switches to minibuffer and asks the user 818 | to enter a search strategy." 819 | (dictem-reinitialize-err) 820 | (dictem-select 821 | "strategy" 822 | (dictem-prepand-special-strats 823 | (dictem-remove-value-from-alist dictem-strategy-alist)) 824 | (dictem-get-default-strategy default-strat) 825 | 'dictem-strategy-history)) 826 | 827 | (defun dictem-select-database (spec-dbs user-dbs &optional default-db) 828 | "Switches to minibuffer and asks user 829 | to enter a database name." 830 | (dictem-reinitialize-err) 831 | (let* ((dbs (dictem-remove-value-from-alist dictem-database-alist)) 832 | (dbs2 (if user-dbs 833 | (if dictem-use-user-databases-only 834 | dictem-user-databases-alist 835 | (append dictem-user-databases-alist dbs) 836 | ) 837 | dbs))) 838 | (dictem-select 839 | "db" 840 | (if spec-dbs (dictem-prepand-special-dbs dbs2) dbs2) 841 | (dictem-get-default-database default-db) 842 | 'dictem-database-history))) 843 | 844 | (defun dictem-read-query (&optional default-query) 845 | "Switches to minibuffer and asks user to enter a query." 846 | (if (featurep 'xemacs) 847 | (read-string 848 | (concat "query [" default-query "]: ") 849 | nil 'dictem-query-history default-query) 850 | (read-string 851 | (concat "query [" default-query "]: ") 852 | (if dictem-empty-initial-input nil default-query) 853 | 'dictem-query-history default-query t))) 854 | 855 | 856 | ;;;;;;;; Hooks ;;;;;;;; 857 | 858 | (defcustom dictem-postprocess-definition-hook 859 | nil 860 | "Hook run in dictem mode buffers containing DEFINE result." 861 | :group 'dictem 862 | :type 'hook 863 | :options '(dictem-postprocess-definition-separator 864 | dictem-postprocess-definition-hyperlinks 865 | dictem-postprocess-each-definition 866 | dictem-postprocess-definition-remove-header 867 | dictem-postprocess-collect-hyperlinks)) 868 | 869 | (defcustom dictem-postprocess-match-hook 870 | nil 871 | "Hook run in dictem mode buffers containing MATCH result." 872 | :group 'dictem 873 | :type 'hook 874 | :options '(dictem-postprocess-match)) 875 | 876 | (defcustom dictem-postprocess-show-info-hook 877 | nil 878 | "Hook run in dictem mode buffers containing SHOW INFO result." 879 | :group 'dictem 880 | :type 'hook 881 | :options '(dictem-postprocess-definition-hyperlinks 882 | dictem-postprocess-collect-hyperlinks)) 883 | 884 | (defcustom dictem-postprocess-show-server-hook 885 | nil 886 | "Hook run in dictem mode buffers containing SHOW SERVER result." 887 | :group 'dictem 888 | :type 'hook) 889 | 890 | ;;;;;;;; Search Functions ;;;;;;; 891 | 892 | (defun dictem-call-dict-internal (fun databases) 893 | (let ((exit-status -1)) 894 | (cond 895 | ((null databases) 0) 896 | ((stringp databases) 897 | (dictem-call-dict-internal fun (list databases))) 898 | ((listp databases) 899 | (dolist (db databases) 900 | (let ((ex_st (funcall fun db))) 901 | (cond 902 | ((= ex_st 0) 903 | (setq exit-status 0)) 904 | (t (if (/= 0 exit-status) 905 | (setq exit-status ex_st))) 906 | ))) 907 | (if (= exit-status -1) 0 exit-status) 908 | ) 909 | (t (error "wrong type of argument")) 910 | ) 911 | )) 912 | 913 | ;(defun dictem-call-dict-internal (fun databases) 914 | ; (dolist (db databases) 915 | ; (funcall fun db))) 916 | ; (funcall fun databases)) 917 | 918 | (defun dictem-make-url (host port database cmd_sign query &optional strategy) 919 | "Returns dict:// URL" 920 | (concat 921 | "dict://" host ":" 922 | (dictem-get-port (if port port "2628")) 923 | "/" cmd_sign ":" query ":" database 924 | (if strategy (concat ":" (if strategy strategy "."))) 925 | )) 926 | 927 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 928 | 929 | (defun dictem-base-do-selector (cmd hook &optional database &rest args) 930 | (let* ((splitted-url nil) 931 | (databases nil) 932 | (user-db (assoc database dictem-user-databases-alist)) 933 | ) 934 | (goto-char (point-max)) 935 | (cond ((dictem-userdb-p database) 936 | (apply 'dictem-base-do-default-server 937 | (append (list cmd hook database) args))) 938 | 939 | ((and database (listp database)) 940 | (dictem-call-dict-internal 941 | `(lambda (db) 942 | (apply 'dictem-base-do-selector 943 | (append (list ,cmd hook db) args))) 944 | (cdr database)) 945 | (setq dictem-last-database (car database))) 946 | 947 | ((and database (stringp database) 948 | (setq splitted-url (dictem-parse-url database))) 949 | (apply 'dictem-base-do-foreign-server 950 | (append 951 | (list cmd hook 952 | (nth 1 splitted-url) 953 | (dictem-get-port (nth 2 splitted-url)) 954 | (nth 3 splitted-url)) 955 | args))) 956 | 957 | (user-db 958 | (let ((exit_status 959 | (apply 'dictem-base-do-selector 960 | (append 961 | (list cmd hook user-db) args)))) 962 | (progn 963 | (setq dictem-last-database database) 964 | exit_status) 965 | )) 966 | 967 | (t 968 | (apply 'dictem-base-do-default-server 969 | (append (list cmd hook database) args))) 970 | ))) 971 | 972 | (defun dictem-base-do-foreign-server (cmd hook server port database &rest args) 973 | (let ((dictem-last-database nil) 974 | (dictem-last-strategy nil)) 975 | (save-dictem (setq dictem-server server) 976 | (setq dictem-port port) 977 | (setq database database) 978 | (dictem-initialize) 979 | (apply 'dictem-base-do-default-server 980 | (append (list cmd hook database) args)) 981 | ))) 982 | 983 | (defun dictem-base-do-default-server (cmd hook 984 | &optional database query strategy) 985 | (let* ((beg (point)) 986 | (fun (if (dictem-userdb-p database) 987 | (dictem-cmd2userdb cmd) 988 | (dictem-cmd2function cmd))) 989 | 990 | (exit_status 991 | (save-excursion (apply fun (append (list t) 992 | (if database (list database)) 993 | (if query (list query)) 994 | (if strategy (list strategy)) 995 | (list nil) (list nil)))) 996 | )) 997 | 998 | (cond ((= 0 exit_status) 999 | (save-excursion 1000 | (narrow-to-region beg (point-max)) 1001 | (run-hooks hook) 1002 | (widen))) 1003 | ((= 21 exit_status) 1004 | (save-excursion 1005 | (narrow-to-region beg (point-max)) 1006 | (run-hooks 'dictem-postprocess-match-hook) 1007 | (widen))) 1008 | (t 1009 | (if (/= beg (point)) 1010 | (setq dictem-error-messages 1011 | (append 1012 | (list 1013 | (dictem-make-url (dictem-get-server) 1014 | (dictem-get-port) database "?" query) 1015 | (buffer-substring-no-properties beg (point))) 1016 | dictem-error-messages))) 1017 | (kill-region beg (point)))) 1018 | 1019 | (if database (setq dictem-last-database database)) 1020 | (if strategy (setq dictem-last-strategy strategy)) 1021 | exit_status 1022 | )) 1023 | 1024 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1025 | 1026 | (defun dictem-base-search (databases query strategy) 1027 | "MATCH + DEFINE commands" 1028 | 1029 | (dictem-base-do-selector 1030 | "search" 1031 | 'dictem-postprocess-definition-hook 1032 | databases query strategy)) 1033 | 1034 | (defun dictem-base-define (databases query c) 1035 | "DEFINE command" 1036 | 1037 | (dictem-base-do-selector 1038 | "define" 1039 | 'dictem-postprocess-definition-hook 1040 | databases query)) 1041 | 1042 | (defun dictem-base-match (databases query strategy) 1043 | "MATCH command" 1044 | 1045 | (dictem-base-do-selector 1046 | "match" 1047 | 'dictem-postprocess-match-hook 1048 | databases query strategy)) 1049 | 1050 | (defun dictem-base-show-databases (a b c) 1051 | "SHOW DB command" 1052 | 1053 | (dictem-base-do-selector 1054 | "show-db" 1055 | nil)) 1056 | 1057 | (defun dictem-base-show-strategies (a b c) 1058 | "SHOW STRAT command" 1059 | 1060 | (dictem-base-do-selector 1061 | "show-strat" 1062 | nil)) 1063 | 1064 | (defun dictem-base-show-info (databases b c) 1065 | "SHOW INFO command" 1066 | 1067 | (dictem-base-do-selector 1068 | "show-info" 1069 | 'dictem-postprocess-show-info-hook 1070 | databases)) 1071 | 1072 | (defun dictem-base-show-server (a b c) 1073 | "SHOW SERVER command" 1074 | 1075 | (dictem-base-do-selector 1076 | "show-server" 1077 | 'dictem-postprocess-show-server-hook)) 1078 | 1079 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1080 | 1081 | (defun dictem-get-error-message (exit_status) 1082 | (cond 1083 | ((= exit_status 0) "All is fine") 1084 | ((= exit_status 20) "No matches found") 1085 | ((= exit_status 21) "Approximate matches found") 1086 | ((= exit_status 22) "No databases available") 1087 | ((= exit_status 23) "No strategies available") 1088 | 1089 | ((= exit_status 30) "Unexpected response code from server") 1090 | ((= exit_status 31) "Server is temporarily unavailable") 1091 | ((= exit_status 32) "Server is shutting down") 1092 | ((= exit_status 33) "Syntax error, command not recognized") 1093 | ((= exit_status 34) "Syntax error, illegal parameters") 1094 | ((= exit_status 35) "Command not implemented") 1095 | ((= exit_status 36) "Command parameter not implemented") 1096 | ((= exit_status 37) "Access denied") 1097 | ((= exit_status 38) "Authentication failed") 1098 | ((= exit_status 39) "Invalid database name") 1099 | ((= exit_status 40) "Invalid strategy name") 1100 | ((= exit_status 41) "Connection to server failed") 1101 | (t (concat "Ooops!" (number-to-string exit_status))) 1102 | )) 1103 | 1104 | (defun dictem-local-internal (err-msgs exit_status) 1105 | (if err-msgs 1106 | (concat (car err-msgs) "\n" 1107 | (cadr err-msgs) 1108 | "\n" 1109 | (dictem-local-internal 1110 | (cddr err-msgs) 1111 | nil) 1112 | ) 1113 | (if exit_status 1114 | (dictem-get-error-message exit_status) 1115 | nil))) 1116 | 1117 | (defun dictem-generate-full-error-message (exit_status) 1118 | 1119 | (concat "Error messages:\n\n" 1120 | (dictem-local-internal dictem-error-messages exit_status))) 1121 | 1122 | (defun dictem-run (search-fun &optional database query strategy) 1123 | "Creates new *dictem* buffer and run search-fun" 1124 | 1125 | (let ((ex_status -1)) 1126 | 1127 | (defun dictem-local-run-functions (funs database query strategy) 1128 | (cond 1129 | ((functionp funs) 1130 | (let ((ex_st (funcall funs database query strategy))) 1131 | (if (/= ex_status 0) 1132 | (setq ex_status ex_st)))) 1133 | ((and (consp funs) (functionp (car funs))) 1134 | (dictem-local-run-functions (car funs) database query strategy) 1135 | (dictem-local-run-functions (cdr funs) database query strategy)) 1136 | ((null funs) 1137 | nil) 1138 | (t (error "wrong argument type")) 1139 | ) 1140 | ex_status) 1141 | 1142 | (let ((selected-window (frame-selected-window)) 1143 | ; here we remember values of variables local to buffer 1144 | (server dictem-server) 1145 | (port dictem-port) 1146 | (dbs dictem-database-alist) 1147 | (strats dictem-strategy-alist) 1148 | (user-dbs dictem-user-databases-alist) 1149 | (user-only dictem-use-user-databases-only) 1150 | (use-existing-buf dictem-use-existing-buffer) 1151 | ; (option-mime dictem-option-mime) 1152 | (dict-buf nil) 1153 | ) 1154 | (cond 1155 | ((eq dictem-use-existing-buffer 'always) 1156 | (dictem-ensure-buffer)) 1157 | ((eq dictem-use-existing-buffer t) 1158 | (dictem-ensure-buffer)) 1159 | (t 1160 | (dictem)) 1161 | 0) 1162 | (setq dict-buf (buffer-name)) 1163 | ; (set-buffer-file-coding-system coding-system) 1164 | (make-local-variable 'dictem-default-strategy) 1165 | (make-local-variable 'dictem-default-database) 1166 | (make-local-variable 'case-replace) 1167 | (make-local-variable 'case-fold-search) 1168 | 1169 | ; the following lines are to inherit values local to buffer 1170 | (set (make-local-variable 'dictem-server) server) 1171 | (set (make-local-variable 'dictem-port) port) 1172 | (set (make-local-variable 'dictem-database-alist) dbs) 1173 | (set (make-local-variable 'dictem-strategy-alist) strats) 1174 | (set (make-local-variable 'dictem-user-databases-alist) user-dbs) 1175 | (set (make-local-variable 'dictem-use-user-databases-only) user-only) 1176 | (set (make-local-variable 'dictem-use-existing-buffer) use-existing-buf) 1177 | 1178 | ; (set (make-local-variable 'dictem-option-mime) option-mime) 1179 | 1180 | (set (make-local-variable 'dictem-hyperlinks-alist) nil) 1181 | 1182 | ;;;;;;;;;;;;;; 1183 | (setq case-replace nil) 1184 | (setq case-fold-search nil) 1185 | (setq dictem-error-messages nil) 1186 | (dictem-local-run-functions search-fun database query strategy) 1187 | (switch-to-buffer dict-buf) 1188 | (if (and (not (equal ex_status 0)) (= (point-min) (point-max))) 1189 | (insert (dictem-generate-full-error-message ex_status))) 1190 | (goto-char (point-min)) 1191 | (setq buffer-read-only t) 1192 | ex_status 1193 | ))) 1194 | 1195 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1196 | (defun dictem-next-section () 1197 | "Move point to the next definition" 1198 | (interactive) 1199 | (forward-char) 1200 | (if (search-forward-regexp "^From " nil t) 1201 | (beginning-of-line) 1202 | (goto-char (point-max)))) 1203 | 1204 | (defun dictem-previous-section () 1205 | "Move point to the previous definition" 1206 | (interactive) 1207 | (backward-char) 1208 | (if (search-backward-regexp "^From " nil t) 1209 | (beginning-of-line) 1210 | (goto-char (point-min)))) 1211 | 1212 | (defun dictem-hyperlinks-menu () 1213 | "Hyperlinks menu with autocompletion" 1214 | (interactive) 1215 | (let ((link (completing-read "Go to:" dictem-hyperlinks-alist))) 1216 | (if (and link (setq link (assoc link dictem-hyperlinks-alist))) 1217 | (dictem-run-define 1218 | (cadr link) 1219 | dictem-last-database)) 1220 | )) 1221 | 1222 | (defun dictem-next-link () 1223 | "Move point to the next hyperlink" 1224 | (interactive) 1225 | (let ((pt nil) 1226 | (limit (point-max))) 1227 | (if (and (setq pt (next-single-property-change 1228 | (point) 'link nil limit)) 1229 | (/= limit pt)) 1230 | (if (get-char-property pt 'link) 1231 | (goto-char pt) 1232 | (goto-char (next-single-property-change pt 'link nil limit)))) 1233 | )) 1234 | 1235 | (defun dictem-previous-link () 1236 | "Move point to the previous hyperlink" 1237 | (interactive) 1238 | (let ((pt nil) 1239 | (limit (point-min))) 1240 | (if (and (setq pt (previous-single-property-change 1241 | (point) 'link nil limit)) 1242 | (/= limit pt)) 1243 | (if (get-char-property pt 'link) 1244 | (goto-char pt) 1245 | (goto-char (previous-single-property-change pt 'link nil limit)))) 1246 | )) 1247 | 1248 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1249 | (defun dictem-help () 1250 | "Display a dictem help" 1251 | (interactive) 1252 | (describe-function 'dictem-mode)) 1253 | 1254 | (defun dictem-mode () 1255 | "This is a mode for dict client implementing 1256 | the protocol defined in RFC 2229. 1257 | 1258 | The following basic commands are available in the buffer. 1259 | 1260 | \\[dictem-help] display the help information 1261 | 1262 | \\[dictem-kill] kill the dictem buffer 1263 | \\[dictem-kill-all-buffers] kill all dictem buffers 1264 | \\[dictem-quit] bury the dictem buffer 1265 | 1266 | \\[dictem-last] restore content of the previously visited dictem buffer 1267 | 1268 | \\[dictem-run-search] make a new SEARCH, i.e. ask for a database, strategy and query 1269 | and show definitions 1270 | \\[dictem-run-match] make a new MATCH, i.e. ask for database, strategy and query 1271 | and show matches 1272 | \\[dictem-run-define] make a new DEFINE, i.e. ask for a database and query 1273 | and show definitions 1274 | \\[dictem-run-show-server] show information about DICT server 1275 | \\[dictem-run-show-info] ask for a database and show information about it 1276 | \\[dictem-run-show-databases] show databases DICT server provides 1277 | \\[dictem-run-show-strategies] show search strategies DICT server provides 1278 | 1279 | \\[dictem-next-section] move point to the next definition 1280 | \\[dictem-previous-section] move point to the previous definition 1281 | \\[dictem-next-link] move point to the next hyper link 1282 | \\[dictem-previous-link] move point to the previous hyper link 1283 | 1284 | \\[dictem-hyperlinks-menu] display the menu with hyperlinks 1285 | 1286 | \\[scroll-up] scroll dictem buffer up 1287 | \\[scroll-down] scroll dictem buffer down 1288 | \\[dictem-define-on-click] or \\[dictem-define-on-press] visit a link (DEFINE using all dictionaries) 1289 | 1290 | 1291 | Also some advanced commands are available. 1292 | 1293 | \\[dictem-initialize] Initializes dictem, i.e. obtains 1294 | a list of available databases and strategiss from DICT server 1295 | and makes other tasks 1296 | \\[dictem-initialize-strategies-alist] Obtain strategy ALIST from a DICT server and sets dictem-strategy-alist variable 1297 | \\[dictem-initialize-databases-alist] Obtain database ALIST from a DICT server and sets dictem-database-alist variable 1298 | 1299 | 1300 | The following key bindings are currently in effect in the buffer: 1301 | \\{dictem-mode-map} 1302 | " 1303 | 1304 | (interactive) 1305 | 1306 | (kill-all-local-variables) 1307 | (buffer-disable-undo) 1308 | (use-local-map dictem-mode-map) 1309 | (setq major-mode 'dictem-mode) 1310 | (setq mode-name "dictem") 1311 | 1312 | (add-hook 'kill-buffer-hook 'dictem-kill t t) 1313 | (run-hooks 'dictem-mode-hook) 1314 | ) 1315 | 1316 | (defvar dictem-window-configuration 1317 | nil 1318 | "The window configuration to be restored upon closing the buffer") 1319 | 1320 | (defvar dictem-selected-window 1321 | nil 1322 | "The currently selected window") 1323 | 1324 | (defvar dictem-content-history 1325 | nil 1326 | "A list of lists (buffer_content point)") 1327 | 1328 | (defconst dictem-buffer-name 1329 | "*dictem buffer*") 1330 | 1331 | (defconst dictem-url-regexp 1332 | "^\\(dict\\)://\\([^/:]*\\)\\(:\\([0-9]+\\)\\)?/\\(.*\\)$") 1333 | 1334 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1335 | 1336 | (defconst dictem-cmd2function-alist 1337 | '(("show-server" dictem-call-process-SHOW-SERVER) 1338 | ("show-info" dictem-call-process-SHOW-INFO) 1339 | ("show-strat" dictem-call-process-SHOW-STRAT) 1340 | ("show-db" dictem-call-process-SHOW-DB) 1341 | ("match" dictem-call-process-MATCH) 1342 | ("define" dictem-call-process-DEFINE) 1343 | ("search" dictem-call-process-SEARCH) 1344 | )) 1345 | 1346 | (defconst dictem-cmd2userdb-alist 1347 | '(("match" dictem-userdb-MATCH) 1348 | ("define" dictem-userdb-DEFINE) 1349 | ("search" dictem-userdb-SEARCH) 1350 | ("show-info" dictem-userdb-SHOW-INFO) 1351 | )) 1352 | 1353 | (defun dictem-cmd2xxx (cmd alist) 1354 | (let ((fun (assoc cmd alist))) 1355 | (if fun 1356 | (symbol-function (cadr fun)) 1357 | (error "Unknown command \"%s\"" cmd) 1358 | ) 1359 | )) 1360 | 1361 | (defun dictem-cmd2function (cmd) 1362 | (dictem-cmd2xxx cmd dictem-cmd2function-alist)) 1363 | (defun dictem-cmd2userdb (cmd) 1364 | (dictem-cmd2xxx cmd dictem-cmd2userdb-alist)) 1365 | 1366 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1367 | 1368 | (defun dictem-parse-url (url) 1369 | "Parses string like dict://dict.org:2628/foldoc 1370 | and returns a list containing protocol, server, port and path on nil if fails" 1371 | (if (string-match dictem-url-regexp url) 1372 | (list 1373 | (match-string 1 url) ; protocol 1374 | (match-string 2 url) ; host 1375 | (match-string 4 url) ; port 1376 | (match-string 5 url) ; path (database name for dict://) 1377 | ) 1378 | nil)) 1379 | 1380 | (defun dictem () 1381 | "Create a new dictem buffer and install dictem-mode" 1382 | (interactive) 1383 | 1384 | (let ( 1385 | (buffer (generate-new-buffer dictem-buffer-name)) 1386 | (window-configuration (current-window-configuration)) 1387 | (selected-window (frame-selected-window))) 1388 | (switch-to-buffer-other-window buffer) 1389 | (dictem-mode) 1390 | 1391 | (make-local-variable 'dictem-window-configuration) 1392 | (make-local-variable 'dictem-selected-window) 1393 | (make-local-variable 'dictem-content-history) 1394 | (setq dictem-window-configuration window-configuration) 1395 | (setq dictem-selected-window selected-window) 1396 | )) 1397 | 1398 | ;(unless dictem-mode-map 1399 | (setq dictem-mode-map (make-sparse-keymap)) 1400 | (suppress-keymap dictem-mode-map) 1401 | 1402 | ; Kill the buffer 1403 | (define-key dictem-mode-map "k" 'dictem-kill) 1404 | 1405 | ; Kill all dictem buffers 1406 | (define-key dictem-mode-map "x" 'dictem-kill-all-buffers) 1407 | 1408 | ; Bury the buffer 1409 | (define-key dictem-mode-map "q" 'dictem-quit) 1410 | 1411 | ; LAST, works like in Info-mode 1412 | (define-key dictem-mode-map "l" 'dictem-last) 1413 | 1414 | ; Show help message 1415 | (define-key dictem-mode-map "h" 'dictem-help) 1416 | 1417 | ; SEARCH = MATCH + DEFINE 1418 | (define-key dictem-mode-map "s" 'dictem-run-search) 1419 | 1420 | ; MATCH 1421 | (define-key dictem-mode-map "m" 'dictem-run-match) 1422 | 1423 | ; DEFINE 1424 | (define-key dictem-mode-map "d" 'dictem-run-define) 1425 | 1426 | ; SHOW SERVER 1427 | (define-key dictem-mode-map "r" 'dictem-run-show-server) 1428 | 1429 | ; SHOW INFO 1430 | (define-key dictem-mode-map "i" 'dictem-run-show-info) 1431 | 1432 | ; Move point to the next DEFINITION 1433 | (define-key dictem-mode-map "n" 'dictem-next-section) 1434 | 1435 | ; Move point to the previous DEFINITION 1436 | (define-key dictem-mode-map "p" 'dictem-previous-section) 1437 | 1438 | ; Move point to the next HYPER LINK 1439 | (define-key dictem-mode-map "\M-n" 'dictem-next-link) 1440 | 1441 | ; Move point to the previous HYPER LINK 1442 | (define-key dictem-mode-map "\M-p" 'dictem-previous-link) 1443 | 1444 | ; Hyperlinks menu 1445 | (define-key dictem-mode-map "e" 'dictem-hyperlinks-menu) 1446 | 1447 | ; Scroll up dictem buffer 1448 | (define-key dictem-mode-map " " 'scroll-up) 1449 | 1450 | ; Scroll down dictem buffer 1451 | (define-key dictem-mode-map "\177" 'scroll-down) 1452 | 1453 | ; Define on click 1454 | (if (featurep 'xemacs) 1455 | (define-key dictem-mode-map [button2] 1456 | 'dictem-define-on-click) 1457 | (define-key dictem-mode-map [mouse-2] 1458 | 'dictem-define-on-click)) 1459 | 1460 | (define-key dictem-mode-map "\C-m" 1461 | 'dictem-define-on-press) 1462 | 1463 | (defun dictem-mode-p () 1464 | "Return non-nil if current buffer has dictem-mode" 1465 | (eq major-mode 'dictem-mode)) 1466 | 1467 | (defun dictem-ensure-buffer () 1468 | "If current buffer is not a dictem buffer, create a new one." 1469 | (if (dictem-mode-p) 1470 | (progn 1471 | (if dictem-use-content-history 1472 | (setq dictem-content-history 1473 | (cons (list (buffer-substring 1474 | (point-min) (point-max)) 1475 | (point)) dictem-content-history))) 1476 | (setq buffer-read-only nil) 1477 | (erase-buffer)) 1478 | (dictem))) 1479 | 1480 | (defun dictem-quit () 1481 | "Bury the current dictem buffer." 1482 | (interactive) 1483 | (if (featurep 'xemacs) 1484 | (bury-buffer) 1485 | (quit-window))) 1486 | 1487 | (defun dictem-kill () 1488 | "Kill the current dictem buffer." 1489 | (interactive) 1490 | 1491 | (if (eq major-mode 'dictem-mode) 1492 | (progn 1493 | (setq major-mode nil) 1494 | (let ((configuration dictem-window-configuration) 1495 | (selected-window dictem-selected-window)) 1496 | (kill-buffer (current-buffer)) 1497 | (if (window-live-p selected-window) 1498 | (progn 1499 | (select-window selected-window) 1500 | (set-window-configuration configuration))))))) 1501 | 1502 | (defun dictem-last () 1503 | "Go back to the last buffer visited visited." 1504 | (interactive) 1505 | (if (eq major-mode 'dictem-mode) 1506 | (if dictem-content-history 1507 | (progn 1508 | (setq buffer-read-only nil) 1509 | (delete-region (point-min) (point-max)) 1510 | (insert (car (car dictem-content-history))) 1511 | (goto-char (cadr (car dictem-content-history))) 1512 | (setq dictem-content-history (cdr dictem-content-history)) 1513 | ) 1514 | ) 1515 | )) 1516 | 1517 | (defun dictem-kill-all-buffers () 1518 | "Kill all dictem buffers." 1519 | (interactive) 1520 | (dolist (buffer (buffer-list)) 1521 | (let ((buf-name (buffer-name buffer))) 1522 | (if (and (<= (length dictem-buffer-name) (length buf-name)) 1523 | (string= dictem-buffer-name 1524 | (substring buf-name 0 (length dictem-buffer-name)))) 1525 | (kill-buffer buf-name)) 1526 | ))) 1527 | 1528 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1529 | ;;;;; Top-level Functions ;;;;;; 1530 | 1531 | (defun dictem-run-match (query database strat) 1532 | "Asks a user about database name, search strategy and query, 1533 | creates new *dictem* buffer and 1534 | shows matches in it." 1535 | (interactive 1536 | (list 1537 | (dictem-read-query (thing-at-point 'word)) 1538 | (dictem-select-database t t (dictem-get-default-database)) 1539 | (dictem-select-strategy (dictem-get-default-strategy)))) 1540 | (dictem-run 'dictem-base-match database query strat)) 1541 | 1542 | (defun dictem-run-define (query database) 1543 | "Asks a user about database name and query, 1544 | creates new *dictem* buffer and 1545 | shows definitions in it." 1546 | (interactive 1547 | (list 1548 | (dictem-read-query (thing-at-point 'word)) 1549 | (dictem-select-database t t (dictem-get-default-database)))) 1550 | (dictem-run 'dictem-base-define database query nil)) 1551 | 1552 | (defun dictem-run-search (query database strat) 1553 | "Asks a user about database name, search strategy and query, 1554 | creates new *dictem* buffer and 1555 | shows definitions in it." 1556 | (interactive 1557 | (list 1558 | (dictem-read-query (thing-at-point 'word)) 1559 | (dictem-select-database t t (dictem-get-default-database)) 1560 | (dictem-select-strategy (dictem-get-default-strategy)))) 1561 | (dictem-run 'dictem-base-search database query strat)) 1562 | 1563 | (defun dictem-run-show-info (database) 1564 | "Asks a user about database name 1565 | creates new *dictem* buffer and 1566 | shows information about it." 1567 | (interactive (list 1568 | (dictem-select-database 1569 | nil nil 1570 | (dictem-get-default-database)))) 1571 | (dictem-run 'dictem-base-show-info database)) 1572 | 1573 | (defun dictem-run-show-server () 1574 | "Creates new *dictem* buffer and 1575 | shows information about DICT server in it." 1576 | (interactive) 1577 | (dictem-run 'dictem-base-show-server)) 1578 | 1579 | (defun dictem-run-show-databases () 1580 | "Creates new *dictem* buffer and 1581 | shows a list of databases provided by DICT." 1582 | (interactive) 1583 | (dictem-run 'dictem-base-show-databases)) 1584 | 1585 | (defun dictem-run-show-strategies () 1586 | "Creates new *dictem* buffer and 1587 | shows a list of search stratgeies provided by DICT." 1588 | (interactive) 1589 | (dictem-run 'dictem-base-show-strategies)) 1590 | 1591 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1592 | 1593 | (easy-menu-define 1594 | dictem-menu 1595 | dictem-mode-map 1596 | "DictEm Menu" 1597 | `("DictEm" 1598 | ["DictEm..." dictem-help t] 1599 | "--" 1600 | ["Next Section" dictem-next-section t] 1601 | ["Previous Section" dictem-previous-section t] 1602 | "--" 1603 | ["Match" dictem-run-match t] 1604 | ["Definition" dictem-run-define t] 1605 | ["Search" dictem-run-search t] 1606 | "--" 1607 | ["Information about server" dictem-run-show-server t] 1608 | ["Information about database" dictem-run-show-info t] 1609 | ["A list of available databases" dictem-run-show-databases t] 1610 | "--" 1611 | ["Bury Dictem Buffer" dictem-quit t] 1612 | ["Kill Dictem Buffer" dictem-kill t] 1613 | )) 1614 | 1615 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1616 | ;;;;; Optional Features ;;;;; 1617 | (defun dictem-create-link (start end face function &optional data add-props) 1618 | "Create a link in the current buffer starting from `start' going to `end'. 1619 | The `face' is used for displaying, the `data' are stored together with the 1620 | link. Upon clicking the `function' is called with `data' as argument." 1621 | (let ((properties 1622 | (append (list 'face face 1623 | 'mouse-face 'highlight 1624 | 'link-data data 1625 | 'link-function function 1626 | 'dictem-server dictem-server 1627 | 'dictem-port dictem-port) 1628 | add-props))) 1629 | (remove-text-properties start end properties) 1630 | (add-text-properties start end properties))) 1631 | 1632 | ;;;;;;; Postprocessing Functions ;;;;;;; 1633 | 1634 | (defun dictem-postprocess-definition-separator () 1635 | (save-excursion 1636 | (goto-char (point-min)) 1637 | (let ((regexp "^\\(From\\)\\( [^\n]+\\)\\(\\[[^\n]+\\]\\)")) 1638 | 1639 | (while (search-forward-regexp regexp nil t) 1640 | (let ((beg (match-beginning 1)) 1641 | (end (match-end 1)) 1642 | (beg-dbdescr (match-beginning 2)) 1643 | (end-dbdescr (match-end 2)) 1644 | (beg-dbname (match-beginning 3)) 1645 | (end-dbname (match-end 3)) 1646 | ) 1647 | (put-text-property beg end 1648 | 'face 'dictem-database-description-face) 1649 | (put-text-property beg-dbdescr end-dbdescr 1650 | 'face 'dictem-database-description-face) 1651 | (setq dictem-current-dbname 1652 | (dictem-replace-spaces 1653 | (buffer-substring-no-properties 1654 | (+ beg-dbname 1) (- end-dbname 1)))) 1655 | (dictem-create-link 1656 | beg-dbname end-dbname 1657 | 'dictem-reference-dbname-face 1658 | 'dictem-base-show-info 1659 | (list (cons 'dbname dictem-current-dbname)))) 1660 | )))) 1661 | 1662 | (defvar dictem-hyperlink-beginning 1663 | "{" 1664 | "String that begins hyperlink. 1665 | This variable is used by 1666 | the function 'dictem-postprocess-definition-hyperlinks'") 1667 | 1668 | (defvar dictem-hyperlink-end 1669 | "}" 1670 | "String that ends hyperlink. 1671 | This variable is used by 1672 | the function 'dictem-postprocess-definition-hyperlinks'") 1673 | 1674 | (defvar dictem-hyperlink-define-func 1675 | 'dictem-base-define 1676 | "Function called when user clicks on hyperlinks inside the definition. 1677 | This variable is used by 1678 | the function 'dictem-postprocess-definition-hyperlinks'") 1679 | 1680 | (defun dictem-postprocess-collect-hyperlinks () 1681 | (save-excursion 1682 | (goto-char (point-min)) 1683 | (let ((regexp (concat "\\(" dictem-hyperlink-beginning "\\([^{}|]+\\)" 1684 | dictem-hyperlink-end 1685 | "\\|\\(" dictem-hyperlink-beginning 1686 | "\\([^{}|\n]+\\)|\\([^{}|\n]+\\)" dictem-hyperlink-end 1687 | "\\)\\)"))) 1688 | 1689 | (while (search-forward-regexp regexp nil t) 1690 | (cond ((match-beginning 2) 1691 | (let* ((word (dictem-replace-spaces 1692 | (buffer-substring-no-properties 1693 | (match-beginning 2) 1694 | (match-end 2))))) 1695 | (setq dictem-hyperlinks-alist 1696 | (cons (list word word) dictem-hyperlinks-alist)) 1697 | )) 1698 | ((match-beginning 3) 1699 | (let* ((word-beg (match-beginning 4)) 1700 | (word-end (match-end 4)) 1701 | (link-beg (match-beginning 5)) 1702 | (link-end (match-end 5)) 1703 | (word (dictem-replace-spaces 1704 | (buffer-substring-no-properties 1705 | word-beg word-end))) 1706 | (link (dictem-replace-spaces 1707 | (buffer-substring-no-properties 1708 | link-beg link-end))) 1709 | ) 1710 | (setq dictem-hyperlinks-alist 1711 | (cons (list word link) dictem-hyperlinks-alist)) 1712 | ))))) 1713 | )) 1714 | 1715 | (defun dictem-find-brackets (re-beg re-end) 1716 | (let ((beg-beg (make-marker)) 1717 | (beg-end (make-marker)) 1718 | (end-beg (make-marker)) 1719 | (end-end (make-marker))) 1720 | (if (search-forward-regexp re-beg nil t) 1721 | (progn 1722 | (set-marker beg-beg (match-beginning 0)) 1723 | (set-marker beg-end (match-end 0)) 1724 | (if (search-forward-regexp re-end nil t) 1725 | (progn 1726 | (set-marker end-beg (match-beginning 0)) 1727 | (set-marker end-end (match-end 0)) 1728 | (list beg-beg beg-end end-beg end-end)) 1729 | nil)) 1730 | nil))) 1731 | 1732 | (defun dictem-postprocess-definition-hyperlinks-cyrlybr1 () 1733 | (save-excursion 1734 | (goto-char (point-min)) 1735 | (let ((regexp) (pos) (beg1) (beg2) (beg3) (end) (word)) 1736 | 1737 | (while (setq pos (dictem-find-brackets dictem-hyperlink-beginning 1738 | dictem-hyperlink-end)) 1739 | (delete-region (nth 0 pos) (nth 1 pos)) 1740 | (delete-region (nth 2 pos) (nth 3 pos)) 1741 | (setq word (buffer-substring-no-properties (nth 1 pos) (nth 2 pos))) 1742 | (dictem-create-link 1743 | (nth 1 pos) (nth 2 pos) 1744 | 'dictem-reference-definition-face 1745 | dictem-hyperlink-define-func 1746 | (list (cons 'word (dictem-replace-spaces word)) 1747 | (cons 'dbname dictem-current-dbname)) 1748 | '(link t)))))) 1749 | 1750 | (defun dictem-postprocess-definition-hyperlinks-curlybr2 () 1751 | (save-excursion 1752 | (goto-char (point-min)) 1753 | (let ((regexp 1754 | (concat dictem-hyperlink-beginning "\\([^{}|\n]+\\)|\\([^{}|\n]+\\)" 1755 | dictem-hyperlink-end))) 1756 | 1757 | (while (search-forward-regexp regexp nil t) 1758 | (let* ((beg (match-beginning 5)) 1759 | (end (match-end 5)) 1760 | (match-beg (match-beginning 3)) 1761 | (repl-beg (match-beginning 4)) 1762 | (repl-end (match-end 4)) 1763 | (repl (buffer-substring-no-properties repl-beg repl-end)) 1764 | (word (buffer-substring-no-properties beg end))) 1765 | (replace-match repl t t) 1766 | (dictem-create-link 1767 | match-beg (+ match-beg (length repl)) 1768 | 'dictem-reference-definition-face 1769 | dictem-hyperlink-define-func 1770 | (list (cons 'word (dictem-replace-spaces word)) 1771 | (cons 'dbname dictem-current-dbname)) 1772 | '(link t))))))) 1773 | 1774 | (defun dictem-postprocess-definition-hyperlinks () 1775 | (dictem-postprocess-definition-hyperlinks-cyrlybr1) 1776 | (dictem-postprocess-definition-hyperlinks-curlybr2) 1777 | ; (dictem-postprocess-definition-hyperlinks-curlybr2) 1778 | ) 1779 | 1780 | (defun dictem-postprocess-match () 1781 | (save-excursion 1782 | (goto-char (point-min)) 1783 | (let ((last-database dictem-last-database) 1784 | (regexp "\\(\"[^\"\n]+\"\\)\\|\\([^ \"\n]+\\)")) 1785 | 1786 | (while (search-forward-regexp regexp nil t) 1787 | (let* ((beg (match-beginning 0)) 1788 | (end (match-end 0)) 1789 | (first-char (buffer-substring-no-properties beg beg))) 1790 | (cond 1791 | ((save-excursion (goto-char beg) (= 0 (current-column))) 1792 | (setq last-database 1793 | (dictem-replace-spaces 1794 | (buffer-substring-no-properties beg (- end 1)))) 1795 | (dictem-create-link 1796 | beg (- end 1) 1797 | 'dictem-reference-dbname-face 'dictem-base-show-info 1798 | (list (cons 'dbname last-database)))) 1799 | ((match-beginning 1) 1800 | (dictem-create-link 1801 | beg end 1802 | 'dictem-reference-m1-face 'dictem-base-define 1803 | (list (cons 'word 1804 | (dictem-replace-spaces 1805 | (buffer-substring-no-properties 1806 | (+ beg 1) (- end 1)))) 1807 | (cons 'dbname last-database)))) 1808 | (t 1809 | (dictem-create-link 1810 | beg end 1811 | 'dictem-reference-m2-face 'dictem-base-define 1812 | (list (cons 'word 1813 | (dictem-replace-spaces 1814 | (buffer-substring-no-properties 1815 | beg end ))) 1816 | (cons 'dbname last-database)))) 1817 | )))))) 1818 | 1819 | (defun dictem-postprocess-definition-remove-header () 1820 | (save-excursion 1821 | (goto-char (point-min)) 1822 | (end-of-line) 1823 | (let (eol (point)) 1824 | (goto-char (point-min)) 1825 | (if (search-forward-regexp "[0-9] definitions? found" eol t) 1826 | (progn 1827 | (goto-char (point-min)) 1828 | (let ((kill-whole-line t)) 1829 | (kill-line 1)) 1830 | ))))) 1831 | 1832 | (defun dictem-add-text-face-properties (start end face-add-props 1833 | &optional object) 1834 | (let (face-props) 1835 | (while (<= start end) 1836 | (progn 1837 | (setq face-props (get-text-property start 'face object)) 1838 | (if (facep face-props) 1839 | (progn 1840 | (setq face-props nil) 1841 | (add-text-properties 1842 | start (+ 1 start) 1843 | (list 'face nil) 1844 | object))) 1845 | (add-text-properties 1846 | start (+ 1 start) 1847 | (list 'face (append face-props face-add-props)) 1848 | object) 1849 | (setq start (+ start 1)))))) 1850 | 1851 | (defun dictem-add-begendre-face-propertires (re-beg re-end face-properties) 1852 | (let ((bold-beg-beg (make-marker)) 1853 | (bold-beg-end (make-marker)) 1854 | (bold-end-beg (make-marker)) 1855 | (bold-end-end (make-marker))) 1856 | (while (search-forward-regexp re-beg nil t) 1857 | (progn 1858 | (set-marker bold-beg-beg (match-beginning 0)) 1859 | (set-marker bold-beg-end (match-end 0)) 1860 | (if (search-forward-regexp re-end nil t) 1861 | (progn 1862 | (set-marker bold-end-beg (match-beginning 0)) 1863 | (set-marker bold-end-end (match-end 0)) 1864 | (dictem-add-text-face-properties 1865 | bold-beg-end (- bold-end-beg 1) face-properties) 1866 | (delete-region bold-beg-beg bold-beg-end) 1867 | (delete-region bold-end-beg bold-end-end) 1868 | )))))) 1869 | 1870 | (defun dictem-postprocess-stardict-definition () 1871 | (interactive) 1872 | 1873 | (goto-char (point-min)) 1874 | (dictem-add-begendre-face-propertires 1875 | "" "" '(:weight bold)) 1876 | 1877 | (goto-char (point-min)) 1878 | (dictem-add-begendre-face-propertires 1879 | "" "" '(:height 1.2 :foreground "white" :weight bold)) 1880 | 1881 | (goto-char (point-min)) 1882 | (dictem-add-begendre-face-propertires 1883 | "" "" '(:weight bold :foreground "green")) 1884 | 1885 | (goto-char (point-min)) 1886 | (dictem-add-begendre-face-propertires 1887 | "" "" '()) 1888 | 1889 | (goto-char (point-min)) 1890 | (dictem-add-begendre-face-propertires 1891 | "" "" '(:foreground "green")) 1892 | 1893 | (goto-char (point-min)) 1894 | (dictem-add-begendre-face-propertires 1895 | "" "" '(:foreground "brown")) 1896 | 1897 | (goto-char (point-min)) 1898 | (dictem-add-begendre-face-propertires 1899 | "" "" '(:foreground "green")) 1900 | 1901 | (goto-char (point-min)) 1902 | (dictem-add-begendre-face-propertires 1903 | "" "" '(:foreground "BurlyWood")) 1904 | 1905 | (goto-char (point-min)) 1906 | (dictem-add-begendre-face-propertires 1907 | "" "" '(:slant "oblique")) 1908 | 1909 | (goto-char (point-min)) 1910 | (dictem-add-begendre-face-propertires 1911 | "" "" '(:foreground "lightblue")) 1912 | 1913 | ; replaceing with [ 1914 | (goto-char (point-min)) 1915 | (while (search-forward-regexp "" nil t) 1916 | (replace-match "[" t t)) 1917 | 1918 | ; replaceing with ] 1919 | (goto-char (point-min)) 1920 | (while (search-forward-regexp "" nil t) 1921 | (replace-match "]" t t)) 1922 | 1923 | ; replaceing with ( 1924 | (goto-char (point-min)) 1925 | (while (search-forward-regexp "" nil t) 1926 | (replace-match "" t t)) 1927 | 1928 | ; replaceing with ( 1929 | (goto-char (point-min)) 1930 | (while (search-forward-regexp "" nil t) 1931 | (replace-match "" t t)) 1932 | 1933 | (let ((dictem-hyperlink-beginning "") 1934 | (dictem-hyperlink-end "")) 1935 | (dictem-postprocess-definition-hyperlinks-cyrlybr1)) 1936 | 1937 | ) 1938 | 1939 | ;;;;; On-Click Functions ;;;;; 1940 | (defun dictem-define-on-press () 1941 | "Is called upon pressing Enter." 1942 | (interactive) 1943 | 1944 | (let* ( 1945 | (properties (text-properties-at (point))) 1946 | (data (plist-get properties 'link-data)) 1947 | (fun (plist-get properties 'link-function)) 1948 | (dictem-server (plist-get properties 'dictem-server)) 1949 | (dictem-port (plist-get properties 'dictem-port)) 1950 | (word (assq 'word data)) 1951 | (dbname (assq 'dbname data)) 1952 | ) 1953 | (if (or word dbname) 1954 | (dictem-run fun 1955 | (if dbname (cdr dbname) dictem-last-database) 1956 | (if word (cdr word) nil) 1957 | nil)))) 1958 | 1959 | (defun dictem-define-on-click (event) 1960 | "Is called upon clicking the link." 1961 | (interactive "@e") 1962 | 1963 | (mouse-set-point event) 1964 | (dictem-define-on-press)) 1965 | 1966 | ;(defun dictem-define-with-db-on-click (event) 1967 | ; "Is called upon clicking the link." 1968 | ; (interactive "@e") 1969 | ; 1970 | ; (mouse-set-point event) 1971 | ; (let* ( 1972 | ; (properties (text-properties-at (point))) 1973 | ; (word (plist-get properties 'link-data))) 1974 | ; (if word 1975 | ; (dictem-run 'dictem-base-define (dictem-select-database) word nil)))) 1976 | 1977 | ;(define-key dictem-mode-map [C-down-mouse-2] 1978 | ; 'dictem-define-with-db-on-click) 1979 | 1980 | 1981 | ;;; Function for "narrowing" definitions ;;;;; 1982 | 1983 | (defcustom dictem-postprocess-each-definition-hook 1984 | nil 1985 | "Hook run in dictem mode buffers containing SHOW SERVER result." 1986 | :group 'dictem 1987 | :type 'hook 1988 | :options '(dictem-postprocess-definition-separator 1989 | dictem-postprocess-definition-hyperlinks)) 1990 | 1991 | (defun dictem-postprocess-each-definition () 1992 | (save-excursion 1993 | (goto-char (point-min)) 1994 | (let ((regexp-from-dbname "^From [^\n]+\\[\\([^\n]+\\)\\]") 1995 | (beg nil) 1996 | (end (make-marker)) 1997 | (dbname nil)) 1998 | (if (search-forward-regexp regexp-from-dbname nil t) 1999 | (let ((dictem-current-dbname 2000 | (buffer-substring-no-properties 2001 | (match-beginning 1) (match-end 1)))) 2002 | (setq beg (match-beginning 0)) 2003 | (while (search-forward-regexp regexp-from-dbname nil t) 2004 | (set-marker end (match-beginning 0)) 2005 | ; (set-marker marker (match-end 0)) 2006 | (setq dbname 2007 | (buffer-substring-no-properties 2008 | (match-beginning 1) (match-end 1))) 2009 | 2010 | (save-excursion 2011 | (narrow-to-region beg (marker-position end)) 2012 | (run-hooks 'dictem-postprocess-each-definition-hook) 2013 | (widen)) 2014 | 2015 | (setq dictem-current-dbname dbname) 2016 | (goto-char end) 2017 | (forward-char) 2018 | (setq beg (marker-position end)) 2019 | ) 2020 | (save-excursion 2021 | (narrow-to-region beg (point-max)) 2022 | (run-hooks 'dictem-postprocess-each-definition-hook) 2023 | (widen)) 2024 | ))))) 2025 | 2026 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2027 | 2028 | (provide 'dictem) 2029 | --------------------------------------------------------------------------------