-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathSublimePrint.py
237 lines (194 loc) · 7.97 KB
/
SublimePrint.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import sublime
import sublime_plugin
import os
import subprocess
def load_settings():
return sublime.load_settings("SublimePrint.sublime-settings")
def save_settings():
sublime.save_settings("SublimePrint.sublime-settings")
def open_pipe(cmd, cwd=None, stdin=None):
return subprocess.Popen(cmd, cwd=cwd, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
class SublimePrint(sublime_plugin.WindowCommand):
'''
Base class for the print commands. Handles creating the printer list and
setting options to the printer command.
'''
BIN_PATHS = [
"/usr/bin",
"/usr/local/bin"
]
def is_enabled(self):
'''
Print commands normally requires an active view.
'''
return self.window.active_view() != None
def find_command(self, cmd):
'''
If the given command exists in one of the BIN_PATHS folders, return
the full path, else exit.
'''
if os.path.isabs(cmd) and not os.path.isfile(cmd):
cmd_path = None
else:
try:
cmd_path = list(filter(os.path.isfile, [os.path.join(p, cmd) for p in self.BIN_PATHS]))[0]
except:
cmd_path = None
if cmd_path is None:
sublime.error_message("Command '" + cmd + "' not found! Please review the documentation.")
return cmd_path
def get_printer(self):
'''
Create the list of available printers if necessary and return the
used printer (the default printer if the list is recreated).
'''
# Create printer list in user settings if not defined
settings = load_settings()
used_printer = settings.get("used_printer", None)
cache_printer_names = settings.get("cache_printer_names", True)
if used_printer is None or not cache_printer_names:
lpstat_cmd = self.find_command("lpstat")
if lpstat_cmd is None: return None
# Get default printer
p = open_pipe([lpstat_cmd, "-d"])
if p.wait() == 0:
try:
used_printer = p.stdout.read().split(":")[1].strip()
settings.set("used_printer", used_printer)
except:
# No default printer set
pass
# Get all printers
p = open_pipe([lpstat_cmd, "-a"])
if p.wait() == 0:
printer_cnt = 0
for line in p.stdout:
printer_cnt += 1
printer_name = "printer_{0}".format(printer_cnt)
settings.set(printer_name, line.split()[0])
# Save the updated printer information
save_settings()
return used_printer
def printer_command(self, title=None, print_line_numbers=True):
'''
Return the array of command line options to pass to the subprocess.
'''
settings = load_settings()
print_cmd = self.find_command(settings.get("command"))
if print_cmd is None: return None
options = settings.get("options")
title_option = settings.get("title_option")
if title_option and title:
options[title_option] = title
if not (print_line_numbers and settings.get("print_line_numbers")):
options.pop("line-numbers")
options_list = ["--{0}={1}".format(k, v) for k, v in options.items() if v != ""]
options_list += ["--{0}".format(k) for k, v in options.items() if v == ""]
# printer = self.get_printer()
# if printer is not None:
# options_list.append("--printer={0}".format(printer))
return [print_cmd] + options_list
def send_file_to_printer(self, cmd, file_path):
file_dir, file_name = os.path.split(file_path)
cmd.append(file_name)
p = open_pipe(cmd, cwd=file_dir)
ret = p.wait()
if ret:
raise EnvironmentError((cmd, ret, p.stdout.read()))
def send_text_to_printer(self, cmd, text):
p = open_pipe(cmd, stdin=subprocess.PIPE)
p.communicate(text)
ret = p.wait()
if ret:
raise EnvironmentError((cmd, ret, p.stdout.read()))
def get_all_printers(self):
printer_idx = 1
printers = []
settings = load_settings()
while settings.has("printer_{0}".format(printer_idx)):
printers.append(settings.get("printer_{0}".format(printer_idx)))
printer_idx += 1
return printers
def print_file_callback(self, name_index):
if name_index == -1: return
printer_names = self.get_all_printers()
printer = printer_names[name_index]
file_path = self.window.active_view().file_name()
if self.window.active_view().is_dirty():
sublime.message_dialog("File has unsaved changes.")
return
elif not file_path:
sublime.message_dialog("No file to print.")
return
cmd = self.printer_command()
if cmd is not None:
cmd.append("--printer={0}".format(printer))
self.send_file_to_printer(cmd, file_path)
def print_selection_callback(self, name_index):
if name_index == -1: return
settings = load_settings()
printer_names = self.get_all_printers()
printer = printer_names[name_index]
view = self.window.active_view()
if view.file_name():
title = os.path.basename(view.file_name())
else:
title = "* Untitled *"
text_parts = []
for selection in view.sel():
t = ""
for line in view.lines(selection):
if settings.get("print_line_numbers"):
t += "{0:>6}: ".format(str(view.rowcol(line.begin())[0] + 1))
t += view.substr(line) + "\n"
text_parts.append(t)
text = "----------\n".join(text_parts)
cmd = self.printer_command(title, False)
if cmd is not None:
cmd.append("--printer={0}".format(printer))
self.send_text_to_printer(cmd, text)
def print_clipboard_callback(self, name_index):
if name_index == -1: return
printer_names = self.get_all_printers()
printer = printer_names[name_index]
cmd = self.printer_command("* Clipboard *", False)
if cmd is not None:
cmd.append("--printer={0}".format(printer))
self.send_text_to_printer(cmd, sublime.get_clipboard())
class PrintFileCommand(SublimePrint):
'''
Print the current file. This command assumes the file has been saved to
disk. It will abort if not.
'''
def run(self):
settings = load_settings()
printer_names = self.get_all_printers()
if settings.get("prompt_printer") == True:
self.window.show_quick_panel(printer_names, self.print_file_callback)
else:
self.print_file_callback(printer_names.index(self.get_printer()))
class PrintSelectionCommand(SublimePrint):
'''
This command prints the current selection. If there are multiple
selections, they will all be printed with a separator line between them.
'''
def run(self):
settings = load_settings()
printer_names = self.get_all_printers()
if settings.get("prompt_printer") == True:
self.window.show_quick_panel(printer_names, self.print_selection_callback)
else:
self.print_selection_callback(printer_names.index(self.get_printer()))
class PrintClipboardCommand(SublimePrint):
'''
This command prints the content of the clipboard.
'''
def run(self):
settings = load_settings()
printer_names = self.get_all_printers()
if settings.get("prompt_printer") == True:
self.window.show_quick_panel(printer_names, self.print_clipboard_callback)
else:
self.print_clipboard_callback(printer_names.index(self.get_printer()))
def is_enabled(self):
return sublime.get_clipboard() != ""