-
Notifications
You must be signed in to change notification settings - Fork 11
/
main.py
154 lines (125 loc) · 5.35 KB
/
main.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
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
import subprocess
import Clipster
import CopyQ
import GPaste
import Clipman
from lib import logger, pidOf, tryInt, ensureStatus, findExec, getThemeIcon, setClipboard, showMessage
from ulauncher.api.client.Extension import Extension
from ulauncher.api.client.EventListener import EventListener
from ulauncher.api.shared.event import KeywordQueryEvent, PreferencesEvent, PreferencesUpdateEvent, ItemEnterEvent
from ulauncher.api.shared.item.ExtensionSmallResultItem import ExtensionSmallResultItem
from ulauncher.api.shared.item.ExtensionResultItem import ExtensionResultItem
from ulauncher.api.shared.action.DoNothingAction import DoNothingAction
from ulauncher.api.shared.action.ExtensionCustomAction import ExtensionCustomAction
from ulauncher.api.shared.action.RenderResultListAction import RenderResultListAction
clipboardManagers = [CopyQ, GPaste, Clipster, Clipman]
sorter = lambda m: int("{}{}".format(int(m.isEnabled()), int(m.isRunning())))
def showStatus(status):
return RenderResultListAction([ExtensionResultItem(
name = status,
on_enter = DoNothingAction(),
highlightable = False
)])
def formatEntry(icon, query, entry):
entryArr = entry.strip().split('\n')
context = []
pos = 0
if query:
line = next(l for l in entryArr if query in l.lower())
pos = entryArr.index(line)
if pos > 0:
line = entryArr[pos - 1].strip()
if line:
context.append('...' + line)
context.append(entryArr[pos])
if len(entryArr) > pos + 1:
line = entryArr[pos + 1].strip()
if line:
context.append(line + '...')
return ExtensionSmallResultItem(
icon = icon,
name = '\n'.join(context),
on_enter = ExtensionCustomAction(entry)
)
def getManager(name):
if name == 'Auto':
contenders = [m for m in clipboardManagers if m.canStart()];
return sorted(contenders, key=sorter)[-1]
for m in clipboardManagers:
if m.name == name:
return m
def setManager(name, extension):
global manager
logger.info('Loading ulauncher-clipboard manager: %s', name)
manager = getManager(name)
if not ensureStatus(manager):
showMessage(
'ulauncher-clipboard error',
"Could not load {}. Make sure it's installed and enabled.".format(manager.name),
getThemeIcon('dialog-error', 32)
)
class PreferencesLoadListener(EventListener):
def on_event(self, event, extension):
extension.preferences.update(event.preferences)
setManager(event.preferences['manager'], extension)
class PreferencesChangeListener(EventListener):
def on_event(self, event, extension):
if event.id == 'manager':
setManager(event.new_value, extension)
class KeywordQueryEventListener(EventListener):
def on_event(self, event, extension):
maxLines = tryInt(extension.preferences['max_lines'], 20)
icon = getThemeIcon('edit-paste', 32)
query = (event.get_argument() or '').lower()
if not ensureStatus(manager):
return showStatus('Could not start {}. Please make sure you have it on your system and that it is not disabled.'.format(manager.name))
try:
history = manager.getHistory()
except Exception as e:
logger.error('Failed getting clipboard history')
logger.error(e)
return showStatus('Could not load clipboard history')
# Filter entries if there's a query
if query == '':
matches = history[:maxLines]
else:
matches = []
for entry in history:
if len(matches) == maxLines:
break
if query in entry.lower():
matches.append(entry)
if len(matches) > 0:
lines = 0
results = []
for entry in matches:
result = formatEntry(icon, query, entry)
# Limit to max lines and compensate for the margin
lines += max(1, (result.get_name().count('\n') + 1) * 0.85)
if maxLines >= lines:
results.append(result)
return RenderResultListAction(results)
return showStatus('No matches in clipboard history' if len(query) > 0 else 'Clipboard history is empty')
class ItemEnterEventListener(EventListener):
def on_event(self, event, extension):
text = event.get_data()
copyHook = extension.preferences['copy_hook']
# Prefer to use the clipboard managers own implementation
if getattr(manager, 'add', None):
logger.info("Adding to clipboard using clipboard manager's method")
manager.add(text)
else:
logger.info("Adding to clipboard using fallback method")
setClipboard(text)
if copyHook:
logger.info('Running copy hook: ' + copyHook)
subprocess.Popen(['sh', '-c', copyHook])
class Clipboard(Extension):
def __init__(self):
super(Clipboard, self).__init__()
self.subscribe(KeywordQueryEvent, KeywordQueryEventListener())
self.subscribe(PreferencesEvent, PreferencesLoadListener())
self.subscribe(PreferencesUpdateEvent, PreferencesChangeListener())
self.subscribe(ItemEnterEvent, ItemEnterEventListener())
if __name__ == '__main__':
Clipboard().run()