-
Notifications
You must be signed in to change notification settings - Fork 0
/
plugins.py
119 lines (81 loc) · 3.68 KB
/
plugins.py
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
import vim
from .autocommands import autocommands_map
from .util import AutoInstance, template
observers = []
vim_observe_autocommand = template('observe_autocommand')
vim_call_observors = template('get_call_observors')
def call_observers(event_name):
for observer in observers:
observer.emit(event_name)
vim.command(vim_call_observors)
for command in autocommands_map:
# Automating Cmd-Events is bad news. These must instead
# be bound manually by the plugin.
if autocommands_map[command][-3:] == 'Cmd':
continue
au_command = vim_observe_autocommand.format(autocommands_map[command])
vim.command(au_command)
class PluginObserver(object):
""" Provides a centralized observer for propagating Vim autocommands.
Directly listens to Vim events and propagates them as required through
any event listeners that register themselves with this object and provide
the proper hooking methods.
"""
def __init__(self):
""" Initializes a dict of events and their related listeners list.
Initializes self.listeners as a dict where keys are method names that
are intended to respond to events. Each value is set to an empty list
which contains all objects which are triggered by this event.
"""
self.emitters = {}
self.listeners = {}
for event in autocommands_map:
self.listeners[event] = []
observers.append(self)
def create_emitter(self, event_name):
""" Returns an emitter that will trigger event_name on listeners. """
handler_name_found = None
for handler_name in autocommands_map:
if autocommands_map[handler_name] == event_name:
handler_name_found = handler_name
break
if not handler_name_found:
raise NotImplementedError(
'No event handler exists for: {0}'.format(event_name)
)
# Create the inner function. This functionally allows us to completely
# fire events without doing any lookups in order to be as fast as
# possible and prevent our process from blocking Vim.
def emitter(context, data=None):
if handler_name in context.listeners:
for listener in context.listeners[handler_name]:
handler = getattr(listener, handler_name)
handler(data)
return emitter
def emit(self, event_name):
""" Creates a new emitter if this is a new event. Fires the event. """
if event_name not in self.emitters:
self.emitters[event_name] = self.create_emitter(event_name)
emitter = self.emitters[event_name]
# TODO: We need to look into emitting data along with the event.
emitter(self)
def register(self, listener):
""" Registers any event handlers within the given object
"""
for event in autocommands_map:
if getattr(listener, event, False):
if not listener in self.listeners[event]:
self.listeners[event].append(listener)
# Instantiate a default observer for plugins that don't provide it explicitly
default_observer = PluginObserver()
class Plugin(object):
""" Provides Pythonic event handling as an abstraction of Vim's events. """
__metaclass__ = AutoInstance
auto_register = True
def __init__(self, observer=None):
""" Sets up our plugin observer and registers to it if necessary. """
if observer is None:
self.observer = default_observer
# Automatically register this object with the observer if necessary.
if self.auto_register is True:
self.observer.register(self)