aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/data/plugins/mode.py
blob: 54d865a7dac3ac59e6ae53a2653115c66557301b (plain)
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import sys
import re

__export__ = ['set_mode', 'get_mode', 'set_mode_config', 'get_mode_config']

UZBLS = {}

DEFAULTS = {
  'mode': '',
  'modes': {
    'insert': {
      'forward_keys': True,
      'keycmd_events': False,
      'modcmd_updates': False,
      'mode_indicator': 'I'},
    'command': {
      'forward_keys': False,
      'keycmd_events': True,
      'modcmd_updates': True,
      'mode_indicator': 'C'}}}

FINDSPACES = re.compile("\s+")
VALID_KEY = re.compile("^[\w_]+$").match


def add_instance(uzbl, *args):
    UZBLS[uzbl] = dict(DEFAULTS)


def del_instance(uzbl, *args):
    if uzbl in UZBLS:
        del UZBLS[uzbl]


def get_mode_dict(uzbl):
    '''Return the mode dict for an instance.'''

    if uzbl not in UZBLS:
        add_instance(uzbl)

    return UZBLS[uzbl]


def get_mode_config(uzbl, mode):
    '''Return the mode config for a given mode.'''

    modes = get_mode_dict(uzbl)['modes']
    if mode not in modes:
        modes[mode] = {}

    return modes[mode]


def get_mode(uzbl):
    return get_mode_dict(uzbl)['mode']


def mode_changed(uzbl, mode):
    '''The mode has just been changed, now set the per-mode config.'''

    if get_mode(uzbl) != mode:
        return

    config = uzbl.get_config()
    mode_config = get_mode_config(uzbl, mode)
    for (key, value) in mode_config.items():
        uzbl.set(key, value, config=config)

    if 'mode_indicator' not in mode_config:
        config['mode_indicator'] = mode

    uzbl.clear_keycmd()
    uzbl.clear_modcmd()


def set_mode(uzbl, mode=None):
    '''Set the mode and raise the MODE_CHANGED event if the mode has changed.
    Fallback on the default mode if no mode argument was given and the default
    mode is not null.'''

    config = uzbl.get_config()
    mode_dict = get_mode_dict(uzbl)
    if mode is None:
        mode_dict['mode'] = ''
        if 'default_mode' in config:
            mode = config['default_mode']

        else:
            mode = 'command'

    if not VALID_KEY(mode):
        raise KeyError("invalid mode name: %r" % mode)

    if 'mode' not in config or config['mode'] != mode:
        config['mode'] = mode

    elif mode_dict['mode'] != mode:
        mode_dict['mode'] = mode
        uzbl.event("MODE_CHANGED", mode)


def config_changed(uzbl, key, value):
    '''Check for mode related config changes.'''

    value = None if not value else value
    if key == 'default_mode':
        if not get_mode(uzbl):
            set_mode(uzbl, value)

    elif key == 'mode':
        set_mode(uzbl, value)


def set_mode_config(uzbl, mode, key, value):
    '''Set mode specific configs. If the mode being modified is the current
    mode then apply the changes on the go.'''

    assert VALID_KEY(mode) and VALID_KEY(key)

    mode_config = get_mode_config(uzbl, mode)
    mode_config[key] = value

    if get_mode(uzbl) == mode:
        uzbl.set(key, value)


def mode_config(uzbl, args):
    '''Parse mode config events.'''

    split = map(unicode.strip, FINDSPACES.split(args.lstrip(), 1))
    if len(split) != 2:
        raise SyntaxError('invalid mode config syntax: %r' % args)

    mode, set = split
    split = map(unicode.strip, set.split('=', 1))
    if len(split) != 2:
        raise SyntaxError('invalid set syntax: %r' % args)

    key, value = split
    set_mode_config(uzbl, mode, key, value)


def toggle_modes(uzbl, modes):
    '''Toggle or cycle between or through a list of modes.'''

    assert len(modes.strip())

    modelist = filter(None, map(unicode.strip, modes.split(' ')))
    mode = get_mode(uzbl)

    index = 0
    if mode in modelist:
        index = (modelist.index(mode)+1) % len(modelist)

    set_mode(uzbl, modelist[index])


def init(uzbl):
    # Event handling hooks.
    uzbl.connect_dict({
        'CONFIG_CHANGED':   config_changed,
        'INSTANCE_EXIT':    del_instance,
        'INSTANCE_START':   add_instance,
        'MODE_CHANGED':     mode_changed,
        'MODE_CONFIG':      mode_config,
        'TOGGLE_MODES':     toggle_modes,
    })

    # Function exports to the uzbl object, `function(uzbl, *args, ..)`
    # becomes `uzbl.function(*args, ..)`.
    uzbl.export_dict({
        'get_mode': get_mode,
        'get_mode_config': get_mode_config,
        'set_mode': set_mode,
        'set_mode_config': set_mode_config,
    })