aboutsummaryrefslogtreecommitdiffstats
path: root/dlu.py
blob: 6d1eb6f7e5f9808f5765ed6a4bd024b407981277 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python3

import sys, os

global dictionary_name, sought_word, display_envs, x_reads, reads, wordmod, standard_page_remap, load_dictionary, open_dictionary

## Parse command line.
if len(sys.argv) == 2 and sys.argv[1] == '-l':
    f_list = True
elif len(sys.argv) != 3:
    print('Usage: dlu [DICTIONARY WORD | -l]', file = sys.stderr)
    sys.exit(1)
else:
    dictionary_name = sys.argv[1]
    sought_word = sys.argv[2]
    f_list = False

# Default functions, can be overriden by configurations on call to load_dictionary.
if not f_list:
    display_envs = ['MDS_DISPLAY', 'MIR_DISPLAY', 'WAYLAND_DISPLAY', 'DISPLAY']
    x_reads = [
        (lambda f, p : ['atril', f, '-i', p]),
        (lambda f, p : ['evince', f, '-i', p]),
        (lambda f, p : ['xpdf', f, p]),
    ]
    reads = dict((disp, list(x_reads)) for disp in display_envs)
    reads[None] = [lambda f, p : ['jfbview', '-p', p, '--', f]]
    wordmod = lambda x : x.lower()
    def standard_page_remap(offset, multiple = 1, multiple_offset = 0):
        return lambda p : (0 if p < multiple_offset else p - multiple_offset) // multiple + offset
    def open_dictionary(filename, page):
        disps = [disp for disp in display_envs if disp in os.environ] + [None]
        for command_lambda in reads[disps[0]]:
            command = command_lambda(filename, str(page));
            os.execvp(command[0], command)
        sys.stderr.print("%s: could find any viewer to use." % sys.argv[0])
        sys.stderr.print("%s:   file to open: %s" % (sys.argv[0], filename))
        sys.stderr.print("%s:   page to open: %i" % (sys.argv[0], page))
        sys.exit(1)

## Load configurations, which holds data needed to perform the lookup.
g, l = globals(), dict(locals())
for key in l:
    g[key] = l[key]
# Possible auto-selected configuration scripts,
# earlier ones have precedence, we can only select one.
for file in ('$XDG_CONFIG_HOME/%/%rc', '$HOME/.config/%/%rc', '$HOME/.%rc', '$~/.config/%/%rc', '$~/.%rc', '/etc/%rc'):
    # Expand short-hands
    file = file.replace('/', os.sep).replace('%', 'dlu')
    # Expand environment variables
    for arg in ('XDG_CONFIG_HOME', 'HOME'):
        # Environment variables are prefixed with $
        if '$' + arg in file:
            if arg in os.environ:
                # To be sure that do so no treat a $ as a variable prefix
                # incorrectly we replace any $ in the value of the variable
                # with NUL which is not a value pathname character.
                file = file.replace('$' + arg, os.environ[arg].replace('$', '\0'))
            else:
                file = None
                break
    # Proceed if there where no errors.
    if file is not None:
        # With use $~ (instead of ~) for the user's proper home
        # directroy. HOME should be defined, but it could be missing.
        # It could also be set to another directory.
        if file.startswith('$~'):
            import pwd
            # Get the home (also known as initial) directory
            # of the real user, and the rest of the path.
            file = pwd.getpwuid(os.getuid()).pw_dir + file[2:]
        # Now that we are done we can change back any NUL to $:s.
        file = file.replace('\0', '$')
        # If the file we exists,
        if os.path.exists(file):
            # select it,
            config_file = file
            # and stop trying files with lower precedence.
            break
if config_file is not None:
    code = None
    # Read configuration script file.
    with open(config_file, 'rb') as script:
        code = script.read()
    # Decode configurion script file and add a line break
    # at the end to ensure that the last line is empty.
    # If it is not, we will get errors.
    code = code.decode('utf-8', 'strict') + '\n'
    # Compile the configuration script,
    code = compile(code, config_file, 'exec')
    # and run it, with it have the same
    # globals as this module, so that it can
    # not only use want we have defined, but
    # also redefine it for us.
    exec(code, g)
else:
    print('No configuration file found')
    sys.exit(1)

## List available dictionaries.
if f_list:
    for d in list_dictionaries():
        print(d)
    sys.exit(0)

## Perform lookup.
load_dictionary(dictionary_name)

sought_word = wordmod(sought_word)
filename, lasts, page_remap = get()
lasts = [(i, word) for i, word in enumerate(lasts)]

for i, word in lasts:
    word = wordmod(word)
    if sought_word <= word:
        page = i
        break
else:
    page = lasts[-1][0]

page = page_remap(page)
open_dictionary(filename, page)