aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--.gitmodules4
-rw-r--r--.htaccess6
-rw-r--r--GNUmakefile14
-rw-r--r--INSTALL79
-rw-r--r--README63
-rw-r--r--__init__.py0
m---------dico0
-rw-r--r--dicoclient/__init__.py19
-rw-r--r--dicoclient/dicoclient.py415
-rw-r--r--dicoclient/dicoshell.py321
-rw-r--r--dicoclient/setup.py39
-rw-r--r--dicoweb.wsgi27
-rw-r--r--docker-compose.override.yml27
-rw-r--r--docker/Dockerfile9
-rw-r--r--docker/gcide.css (renamed from static/gcide.css)0
-rw-r--r--docker/settings_docker.py255
-rw-r--r--docker/templates/404.html (renamed from templates/404.html)0
-rw-r--r--docker/templates/500.html (renamed from templates/500.html)0
-rw-r--r--docker/templates/about.html (renamed from templates/about.html)0
-rw-r--r--docker/templates/base.html (renamed from templates/base.html)31
-rw-r--r--docker/templates/download.html (renamed from templates/download.html)6
-rw-r--r--docker/templates/index.html (renamed from templates/index.html)30
-rw-r--r--docker/templates/info.html38
-rw-r--r--docker/templates/license.html (renamed from templates/license.html)0
-rw-r--r--docker/templates/opensearch.xml (renamed from templates/opensearch.xml)6
-rw-r--r--docker/urls.py (renamed from templatetags/dictlookup.py)23
-rw-r--r--docker/views.py346
-rw-r--r--docker/withsetting.py (renamed from templatetags/withsetting.py)2
-rw-r--r--dummy_translations.py40
-rw-r--r--gcide.wsgi25
-rw-r--r--index.html15
-rw-r--r--manage.py23
-rw-r--r--settings-sample.py125
-rw-r--r--static/18px-Bulbgraph.pngbin1210 -> 0 bytes
-rw-r--r--static/dicoweb.css134
-rw-r--r--static/dicoweb.js80
-rw-r--r--static/gnu-head-sm.jpgbin5286 -> 0 bytes
-rw-r--r--templatetags/__init__.py0
-rw-r--r--templatetags/macros.py160
-rw-r--r--urls.py28
-rw-r--r--views.py253
42 files changed, 803 insertions, 1846 deletions
diff --git a/.gitignore b/.gitignore
index d8249a5..07fc363 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-.emacs.desktop
-settings.py
+.emacs*
+.env
*~
-tmp/
+\#*
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..9529e2c
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "dico"]
+ path = dico
+ url = git://git.gnu.org.ua/dico.git
+ branch = docker
diff --git a/.htaccess b/.htaccess
deleted file mode 100644
index 2df5844..0000000
--- a/.htaccess
+++ /dev/null
@@ -1,6 +0,0 @@
-Options All -Indexes
-<Files ~ "^\.emacs">
- Order allow,deny
- Deny from all
- Satisfy All
-</Files>
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..267803f
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,14 @@
+command=docker compose -p gcideweb -f dico/docker/docker-compose.yml -f docker-compose.override.yml --env-file .env --profile=lighttpd
+define goal =
+$(1):
+ $$(command) $(1)$(if $(filter-out up, $(1)),, -d)
+endef
+
+$(foreach verb,build config up down restart ps, $(eval $(call goal, $(verb))))
+
+bootstrap:
+ git submodule init
+ git submodule update
+ cd dico && ./bootstrap --force --skip-po
+
+
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index ee9a98b..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,79 +0,0 @@
-GNU Dico - Dicoweb INSTALL
-Copyright (C) 2008-2010, 2012 Wojciech Polak
-
-* Dicoweb requirements
-======================
-
-- Django 1.0+ -- a Python Web framework (http://www.djangoproject.com/)
-- Wit -- a wiki translator distributed within GNU Dico.
- (http://puszcza.gnu.org.ua/projects/wit/)
-
-* Installation instructions
-===========================
-
-Rename 'settings-sample.py' to 'settings.py' and edit your
-local Dicoweb site configuration.
-
-
-** The development/test server
-------------------------------
-
-Change the current working directory into the `dicoweb' directory
-and run the command `python manage.py runserver'. You will see
-the following output:
-
- Validating models...
- 0 errors found.
-
- Django version 1.0, using settings 'dicoweb.settings'
- Development server is running at http://127.0.0.1:8000/
- Quit the server with CONTROL-C.
-
-** Production server with mod_wsgi
-----------------------------------
-
-Apache configuration:
-
- LoadModule wsgi_module modules/mod_wsgi.so
- WSGIScriptAlias / /usr/local/django/dicoweb/dicoweb.wsgi
- Alias /static "/usr/local/django/dicoweb/static"
-
-More detailed information is available at:
-http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
-
-** Production server with mod_python
-------------------------------------
-
-Apache configuration:
-
- LoadModule python_module modules/mod_python.so
- <Location "/">
- SetHandler python-program
- PythonHandler django.core.handlers.modpython
- PythonPath "sys.path + ['/usr/local/django', '/usr/local/django/dicoweb']"
- SetEnv DJANGO_SETTINGS_MODULE dicoweb.settings
- PythonInterpreter dicoweb
- PythonDebug Off
- </Location>
-
- <Location "/static">
- SetHandler None
- </Location>
- <Location "/favicon.ico">
- SetHandler None
- </Location>
-
- <Directory "/usr/local/django/dicoweb/">
- AllowOverride All
- Options None
- Order allow,deny
- Allow from all
- </Directory>
-
-
-
-Local Variables:
-mode: outline
-paragraph-separate: "[ ]*$"
-version-control: never
-End:
diff --git a/README b/README
new file mode 100644
index 0000000..107f55b
--- /dev/null
+++ b/README
@@ -0,0 +1,63 @@
+* Overview
+
+This file describes docker-based setup for the gcide web site.
+
+* Installation
+
+1. make bootstrap
+
+This will prepare GNU dico sources for building.
+
+2. make build
+
+This will build the docker images.
+
+3. Edit the .env file. It should contain the following variables:
+
+ DICOWEB_NAME
+ Domain name of the server.
+ DICOWEB_PORT
+ Port the dicoweb container is listening on.
+ DICOWEB_ADMIN
+ Email address of the administrator.
+ DICT_SERVER
+ IP address or hostname of the dict server to use. The server must
+ offer the gcide database.
+ PIES_SYSLOG_SERVER
+ IP address and port number of the syslog server.
+
+4. Configure your syslog server to receive and route log messages from
+ gcideweb.
+
+5. docker compose up -d
+
+* Maintenance
+
+Most commands are performed by invoking `make' with the corresponding
+command verb:
+
+** make config
+
+ Inspect the resulting docker-compose.yml.
+
+** make build
+
+ Build all images.
+
+** make up
+
+ Start up the services.
+
+** make down
+
+ Pull the services down.
+
+** make ps
+
+ List running services.
+
+Local Variables:
+mode: outline
+paragraph-separate: "[ ]*$"
+version-control: never
+End:
diff --git a/__init__.py b/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/__init__.py
+++ /dev/null
diff --git a/dico b/dico
new file mode 160000
+Subproject b6bce074e9bc85002b55d98397d4d3a6a7b540c
diff --git a/dicoclient/__init__.py b/dicoclient/__init__.py
deleted file mode 100644
index a300cea..0000000
--- a/dicoclient/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file is part of GNU Dico.
-# Copyright (C) 2008-2009, 2012 Wojciech Polak
-#
-# GNU Dico is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Dico is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>.
-
-__all__ = ["dicoclient"]
-
-from dicoclient import *
diff --git a/dicoclient/dicoclient.py b/dicoclient/dicoclient.py
deleted file mode 100644
index 76336c2..0000000
--- a/dicoclient/dicoclient.py
+++ /dev/null
@@ -1,415 +0,0 @@
-# This file is part of GNU Dico.
-# Copyright (C) 2008-2010, 2012 Wojciech Polak
-#
-# GNU Dico is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Dico is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>.
-
-import re
-import socket
-import base64
-import quopri
-import hashlib
-
-__version__ = '1.0'
-
-class DicoClient:
- """GNU Dico client module written in Python
- (a part of GNU Dico software)"""
-
- host = None;
- levenshtein_distance = 0
- mime = False
-
- verbose = 0
- timeout = 10
- transcript = False
- __connected = False
-
- def __init__ (self, host=None):
- if host != None:
- self.host = host;
-
- def __del__ (self):
- if self.__connected:
- self.socket.close ()
-
- def open (self, host=None, port=2628, cred=None):
- """Open the connection to the DICT server."""
- if host != None:
- self.host = host
- if self.verbose:
- self.__debug ('Connecting to %s:%d' % (self.host, port))
- socket.setdefaulttimeout (int (self.timeout))
- self.socket = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
- self.socket.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self.socket.connect ((self.host, port))
- self.__connected = True
- self.fd = self.socket.makefile ();
-
- self.server_banner = self.__read ()[0]
- capas, msgid = re.search ('<(.*)> (<.*>)$',
- self.server_banner).groups ()
- self.server_capas = capas.split ('.')
- self.server_msgid = msgid
-
- self.__send_client ()
- self.__read ()
- if cred and 'user' in cred and 'password' in cred:
- self.auth(cred['user'], cred['password'])
-
- def auth (self, user, passwd):
- if self.__connected and 'auth' in self.server_capas:
- if self.verbose:
- self.__debug ('Authenticating on %s' % (self.host))
- m = hashlib.md5()
- m.update(self.server_msgid)
- m.update(passwd)
- self.__send ('AUTH %s %s' % (user, m.hexdigest()))
- res = self.__read ()
- code, msg = res[0].split (' ', 1)
- if int (code) == 230:
- return True
- return False
-
- def close (self):
- """Close the connection."""
- if self.__connected:
- self.__send_quit ()
- self.__read ()
- self.socket.close ()
- self.__connected = False
-
- def option (self, name, *args):
- """Send the OPTION command."""
- if self.__connected:
- self.__send ('OPTION %s%s' %
- (name, reduce (lambda x, y: str (x) +' '+ str (y),
- args, '')))
- res = self.__read ()
- code, msg = res[0].split (' ', 1)
- if int (code) == 250:
- if name.lower () == 'mime':
- self.mime = True
- return True
- return False
-
- def __get_mime (self, lines):
- cnt = 0
- mimeinfo = {}
- firstline = lines[0].lower ()
- if firstline.find ('content-type:') != -1 or \
- firstline.find ('content-transfer-encoding:') != -1:
- cnt += 1
- for line in lines:
- if line == '':
- break
- t = line.split (':', 1)
- mimeinfo[t[0].lower ()] = t[1].strip ()
- cnt += 1
- for i in range (0, cnt):
- lines.pop (0)
- else:
- lines.pop (0)
- if 'content-transfer-encoding' in mimeinfo:
- if mimeinfo['content-transfer-encoding'].lower () == 'base64':
- buf = base64.decodestring ('\n'.join (lines))
- lines[:] = (buf.split ('\r\n'))
- if lines[-1] == '': del lines[-1]
- del mimeinfo['content-transfer-encoding']
- elif mimeinfo['content-transfer-encoding'].lower () == 'quoted-printable':
- buf = quopri.decodestring ('\n'.join (lines))
- lines[:] = buf.split ('\r\n')
- if lines[-1] == '': del lines[-1]
- del mimeinfo['content-transfer-encoding']
- return mimeinfo
-
- def __get_rs (self, line):
- code, text = line.split (' ', 1)
- code = int (code)
- return code, text
-
- def __read (self):
- if not self.__connected:
- raise DicoNotConnectedError ('Not connected')
- buf = []
- line = self.__readline ()
- if len (line) == 0:
- raise DicoNotConnectedError ('Not connected')
- buf.append (line)
- code, text = self.__get_rs (line)
-
- if code >= 100 and code < 200:
- if code == 150:
- while True:
- rs = self.__readline ()
- code, text = self.__get_rs (rs)
- if code != 151:
- buf.append (rs)
- break
- buf.append ([rs, self.__readblock ()])
- else:
- buf.append (self.__readblock ())
- buf.append (self.__readline ())
- return buf
-
- def __readline (self):
- line = self.fd.readline ().rstrip ()
- if self.transcript:
- self.__debug ('S:%s' % line)
- return line
-
- def __readblock (self):
- buf = []
- while True:
- line = self.__readline ()
- if line == '.':
- break
- buf.append (line)
- return buf
-
-
- def __send (self, command):
- if not self.__connected:
- raise DicoNotConnectedError ('Not connected')
- self.socket.send (command.encode ('utf_8') + "\r\n")
- if self.transcript:
- self.__debug ('C:%s' % command)
-
- def __send_client (self):
- if self.verbose:
- self.__debug ('Sending client information')
- self.__send ('CLIENT "%s %s"' % ("GNU Dico (Python Edition)",
- __version__))
-
- def __send_quit (self):
- if self.verbose:
- self.__debug ('Quitting')
- self.__send ('QUIT');
-
- def __send_show (self, what, arg=None):
- if arg != None:
- self.__send ('SHOW %s "%s"' % (what, arg))
- else:
- self.__send ('SHOW %s' % what)
- return self.__read ()
-
- def __send_define (self, database, word):
- if self.verbose:
- self.__debug ('Sending query for word "%s" in database "%s"' %
- (word, database))
- self.__send ('DEFINE "%s" "%s"' % (database, word))
- return self.__read ()
-
- def __send_match (self, database, strategy, word):
- if self.verbose:
- self.__debug ('Sending query to match word "%s" in database "%s", using "%s"'
- % (word, database, strategy))
- self.__send ('MATCH "%s" "%s" "%s"' % (database, strategy, word))
- return self.__read ()
-
- def __send_xlev (self, distance):
- self.__send ('XLEV %u' % distance)
- return self.__read ()
-
- def show_databases (self):
- """List all accessible databases."""
- if self.verbose:
- self.__debug ('Getting list of databases')
- res = self.__send_show ('DATABASES')
- if self.mime:
- mimeinfo = self.__get_mime (res[1])
- dbs_res = res[1:-1][0]
- dbs = []
- for d in dbs_res:
- short_name, full_name = d.split (' ', 1)
- dbs.append ([short_name, self.__unquote (full_name)])
- dct = {
- 'count': len (dbs),
- 'databases': dbs,
- }
- return dct
-
- def show_strategies (self):
- """List available matching strategies."""
- if self.verbose:
- self.__debug ('Getting list of strategies')
- res = self.__send_show ('STRATEGIES')
- if self.mime:
- mimeinfo = self.__get_mime (res[1])
- sts_res = res[1:-1][0]
- sts = []
- for s in sts_res:
- short_name, full_name = s.split (' ', 1)
- sts.append ([short_name, self.__unquote (full_name)])
- dct = {
- 'count': len (sts),
- 'strategies': sts,
- }
- return dct
-
- def show_info (self, database):
- """Provide information about the database."""
- res = self.__send_show ("INFO", database)
- code, msg = res[0].split (' ', 1)
- if int (code) < 500:
- if self.mime:
- mimeinfo = self.__get_mime (res[1])
- dsc = res[1]
- return {'desc': '\n'.join (dsc), 'type': 'info' }
- else:
- return {'error': code, 'msg': msg}
-
- def show_lang_db (self):
- """Show databases with their language preferences."""
- res = self.__send_show ('LANG DB')
- code, msg = res[0].split (' ', 1)
- if int (code) < 500:
- if self.mime:
- mimeinfo = self.__get_mime (res[1])
- dsc = res[1]
- lang_src = {}
- lang_dst = {}
- for i in dsc:
- pair = i.split (' ', 1)[1]
- src, dst = pair.split (':', 1)
- for j in src:
- lang_src[src.strip()] = True
- for j in dst:
- lang_dst[dst.strip()] = True
- return {
- 'desc': '\n'.join (dsc),
- 'type': 'lang',
- 'lang_src': lang_src.keys (),
- 'lang_dst': lang_dst.keys (),
- }
- else:
- return {'error': code, 'msg': msg}
-
- def show_lang_pref (self):
- """Show server language preferences."""
- res = self.__send_show ('LANG PREF')
- code, msg = res[0].split (' ', 1)
- if int (code) < 500:
- return {'msg': msg}
- else:
- return {'error': code, 'msg': msg}
-
- def show_server (self):
- """Provide site-specific information."""
- res = self.__send_show ('SERVER')
- code, msg = res[0].split (' ', 1)
- if int (code) < 500:
- dsc = res[1]
- return {'desc': '\n'.join (dsc), 'type': 'server'}
- else:
- return {'error': code, 'msg': msg}
-
- def define (self, database, word):
- """Look up word in database."""
- database = database.replace ('"', "\\\"")
- word = word.replace ('"', "\\\"")
- res = self.__send_define (database, word)
- code, msg = res[-1].split (' ', 1)
- if int (code) < 500:
- defs_res = res[1:-1]
- defs = []
- rx = re.compile ('^\d+ ("[^"]+"|\w+) ([a-zA-Z0-9_\-]+) ("[^"]*"|\w+)')
- for i in defs_res:
- term, db, db_fullname = rx.search (i[0]).groups ()
- df = {
- 'term': self.__unquote (term),
- 'db': db,
- 'db_fullname': self.__unquote (db_fullname),
- }
- if self.mime:
- mimeinfo = self.__get_mime (i[1])
- df.update (mimeinfo)
- df['desc'] = '\n'.join (i[1])
- defs.append (df)
- dct = {
- 'count': len (defs),
- 'definitions': defs,
- 'type': 'define'
- }
- return dct
- else:
- return {'error': code, 'msg': msg}
-
- def match (self, database, strategy, word):
- """Match word in database using strategy."""
- if not self.__connected:
- raise DicoNotConnectedError ('Not connected')
-
- if self.levenshtein_distance and 'xlev' in self.server_capas:
- res = self.__send_xlev (self.levenshtein_distance)
- code, msg = res[-1].split (' ', 1)
- if int (code) != 250 and self.verbose:
- self.__debug ('Server rejected XLEV command')
- self.__debug ('Server reply: %s' % msg)
-
- database = database.replace ('"', "\\\"")
- strategy = strategy.replace ('"', "\\\"")
- word = word.replace ('"', "\\\"")
-
- res = self.__send_match (database, strategy, word)
- code, msg = res[-1].split (' ', 1)
- if int (code) < 500:
- if self.mime:
- mimeinfo = self.__get_mime (res[1])
- mts_refs = res[1:-1][0]
- mts = {}
- for i in mts_refs:
- db, term = i.split (' ', 1)
- if mts.has_key (db):
- mts[db].append (self.__unquote (term))
- else:
- mts[db] = [self.__unquote (term)]
- dct = {
- 'matches': mts,
- }
- return dct
- else:
- return {'error': code, 'msg': msg}
-
- def xlev (self, distance):
- """Set Levenshtein distance."""
- self.levenshtein_distance = distance
- res = self.__send_xlev (distance)
- code, msg = res[0].split (' ', 1)
- if int (code) == 250:
- return True
- return False
-
- def __unquote (self, s):
- s = s.replace ("\\\\'", "'")
- if s[0] == '"' and s[-1] == '"':
- s = s[1:-1]
- try:
- s = self.__decode (s)
- except UnicodeEncodeError:
- pass
- return s
-
- def __decode (self, encoded):
- for octc in (c for c in re.findall (r'\\(\d{3})', encoded)):
- encoded = encoded.replace (r'\%s' % octc, chr (int (octc, 8)))
- return unicode (encoded, 'utf_8')
-
- def __debug (self, msg):
- print 'dico: Debug: %s' % msg
-
-class DicoNotConnectedError (Exception):
- def __init__ (self, value):
- self.parameter = value
- def __str__(self):
- return repr (self.parameter)
diff --git a/dicoclient/dicoshell.py b/dicoclient/dicoshell.py
deleted file mode 100644
index 1c0e64d..0000000
--- a/dicoclient/dicoshell.py
+++ /dev/null
@@ -1,321 +0,0 @@
-# This file is part of GNU Dico.
-# Copyright (C) 2008-2010, 2012 Wojciech Polak
-#
-# GNU Dico is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Dico is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>.
-
-import re
-import os
-import sys
-import atexit
-import getopt
-import readline
-import curses.ascii
-import socket
-import dicoclient
-
-class Shell:
- """Simple GNU Dico-Python Shell."""
-
- prompt = 'dico> '
- prefix = '.'
-
- default_host = 'gnu.org.ua'
- database = '!'
- strategy = '.'
- last_matches = []
- last_databases = []
- last_strategies = []
- transcript = False
-
- def __init__ (self, opts, args):
- for o, a in opts:
- if o in ('-h', '--host'):
- self.default_host = a
-
- self.dc = dicoclient.DicoClient (self.default_host)
-
- def run (self):
- histfile = os.path.expanduser ('~/.dico_history')
- try:
- readline.read_history_file (histfile)
- except IOError:
- pass
- atexit.register (readline.write_history_file, histfile)
-
- print '\nType ? for help summary\n'
- while True:
- try:
- input = raw_input (self.prompt).strip ()
- input = unicode (input, 'utf_8')
- except (EOFError, KeyboardInterrupt):
- print
- sys.exit ()
-
- try:
- self.parse (input)
- except socket.timeout:
- self.__error ('socket timed out')
- except dicoclient.DicoNotConnectedError:
- try:
- self.dc.open ()
- dict = self.dc.show_databases ()
- self.last_databases = dict['databases']
- dict = self.dc.show_strategies ()
- self.last_strategies = dict['strategies']
- self.parse (input)
- except socket.error, (errno, strerror):
- self.__error (strerror)
-
- def parse (self, input):
- if len (input) < 1:
- return
- if input[0] == self.prefix:
- self.parse_command (input[1:])
- elif input == '?':
- self.print_help ()
- elif re.match (r'^[0-9]+$', input):
- try:
- match = self.last_matches[int (input)]
- dict = self.dc.define (match[0], match[1])
- if 'count' in dict:
- for d in dict['definitions']:
- print 'From %s, %s:' % (d['db'], d['db_fullname'].
- encode ('utf_8'))
- print d['desc']
- elif 'error' in dict:
- print dict['msg']
- except IndexError:
- self.__error ('No previous match')
- elif input[0] == '/':
- if len (input) > 1:
- dict = self.dc.match (self.database, self.strategy, input[1:])
- if 'matches' in dict:
- self.last_matches = []
- lmi = 0
- for db in dict['matches']:
- print 'From %s, %s:' % (db, self.__lookup_db (db).
- encode ('utf_8'))
- for term in dict['matches'][db]:
- print '%4d) "%s"' % (lmi, term.encode ('utf_8'))
- self.last_matches.append ([db, term])
- lmi = lmi + 1
- elif 'error' in dict:
- print dict['msg']
- else:
- if len (self.last_matches) > 0:
- m = {}
- lmi = 0
- for i, db in enumerate (self.last_matches):
- if not db[0] in m: m[db[0]] = []
- m[db[0]].append (self.last_matches[i][1])
- for db in m:
- print 'From %s, %s:' % (db, self.__lookup_db (db))
- for term in m[db]:
- print '%4d) "%s"' % (lmi, term)
- lmi = lmi + 1
- else:
- self.__error ('No previous match')
- elif input[0] == '!':
- if re.match (r'^![0-9]+$', input):
- number = int (input[1:])
- readline.insert_text (readline.get_history_i