Sublime Forum

Copy text with highlighted colors

#5

I would very much like to see this functionality.

See Copy/save with syntax highlighting format (in Tech Support) for related information.

0 Likes

#6

I’m interested in this topic, although I’m not sure how far I might pursue it at this stage. There are a couple of available options currently:

Copy the text to another editor, which has a print - or print/save to HTML - option. Within this other editor, chose a theme which is similar to your chosen ST one;
There is an (online or downloadable) pigmentizer tool. This would need a lot of customizing to match your chosen theme;
There is a Pygmentize plugin for ST, which presumably enables the previous tool from within ST;
There is a copy-as-rtf bundle, but this is for TextMate and might be tricky to port. In particular, it isn’t written in Python (Perl?).

I welcome comments on the following approach:
Parse the attached theme (as XML or JSON) to create a dictionary of scopes and colours;
Read the chosen font, and perhaps other ST settings - such as line-padding;
Parse the document using scope_name, extract_scope, substr to create HTML DIVs, with the scope name used as class-names;
Create and attach, or insert, a stylesheet created from the dictionary obtained in step one.

The main obstacle I foresee is that the scopes extracted from the theme file won’t precisely match the scope obtained from ‘extract_scope’. So it might involve some complicated use of ‘score_selector’. And I would need to handle line breaks and tabs, and use html entities for certain characters.

I welcome suggestions, opinions on this topic. Andy.

0 Likes

#7

Well I’m making some progress with this :wink: ; the attached screenshot is an HTML document generated from a keyboard combination from within ST.

But, as you can see, I’m losing tabs and newlines. I’m using ‘scope_name’ to extend a region which contains the same scope, and then ‘substr’ to grab the regions text. How can I retain the tabs and newlines? :question:

I also need to retrieve the background and foreground colours (from the theme file) and escape HTML entities, but I know how to do this bit :smile:

[code]import sublime, sublime_plugin
from xml.dom import minidom

class PrintHtmlCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.colours = {}
self.the_content = ]
path_packages = sublime.packages_path()
settings = sublime.load_settings(‘Preferences.sublime-settings’)
colour_scheme = settings.get(‘color_scheme’)
font_size = settings.get(‘font_size’) or 10
font_face = settings.get(‘font_face’) or ‘Consolas’
# print locals()
# print path_packages # need to remove ‘Packages’
doc = minidom.parse(path_packages + ‘\User\Andy.tmTheme’) # use os.path.sep
the_dict = doc.getElementsByTagName(‘dict’)[0]
the_array = the_dict.getElementsByTagName(‘array’)[0]
dict_items = the_array.getElementsByTagName(‘dict’)[1:]
for item in dict_items:
scope = ‘’; colour = ‘’
for key_tag in item.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘scope’:
scope = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
colour = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
if scope != ‘’ and colour != ‘’:
self.colours[scope] = colour
curr_view = self.view
size = curr_view.size()
pt = 0; end = 1
while end <= size:
scope_name = curr_view.scope_name(pt)
while curr_view.scope_name(end) == scope_name and end <= size:
end += 1
region = sublime.Region(pt, end)
the_key = curr_view.scope_name(pt).strip()
if self.colours.has_key(the_key):
the_colour = self.colours[the_key]
else:
best_match = -1
for key in self.colours:
if curr_view.score_selector(pt, key) > best_match:
best_match = curr_view.score_selector(pt, key)
the_colour = self.colours[key]
self.colours[the_key] = the_colour
self.the_content.append((curr_view.substr(region), curr_view.scope_name(pt),
the_colour))
pt = end
end = pt + 1
the_html = open(‘test.html’, ‘w’) # defaults to Packages\User currently
the_html.write(’\n\n<style type=“text/css”>\n’)
the_html.write(’\tdiv { display: inline-block; }\n’)
the_html.write(’\n\n\n’)

	for divs in self.the_content:
		the_html.write('<div style=\"color:' + divs[2] + '\">')
		the_html.write(divs[0] + '</div>\n')
	the_html.write('</body>\n</html>')
	the_html.close()[/code]

BTW The above code won’t run for you currently, unless you manually change the theme-filename within the code.

0 Likes

#8

Actually, no worries :wink: (for the minute). substr is capturing the newlines and tabs, but I need to convert them to
and ’ ’ (four spaces) within the HTML.

0 Likes

#9

Making progress :wink: - see screenshot. (Although you may not like my colours!)

0 Likes

#10

Below is a working version if anyone would like to give it a try :wink: . There are two screenshots below to compare the ST and HTML version.

Windows only at the moment!
Assign it a key-binding and it will create an HTML file version of the current view/file;
The HTML will be saved in the same folder as ‘yourfilename_parsed.html’;
It works with tabs or four spaces at the moment. I should be able to modify it to read, and adjust to, your preference for this setting;
I haven’t tried it with any HUGE files yet - it would probably need re-drafting to write each line as it parses the text and, sensibly, to work in a different thread.

[code]import sublime, sublime_plugin
from xml.dom import minidom
import re
from os import path

class PrintHtmlCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.colours = {}
self.the_content = ]
path_packages = sublime.packages_path()
settings = sublime.load_settings(‘Preferences.sublime-settings’)
colour_scheme = settings.get(‘color_scheme’)
colour_scheme = colour_scheme.replace(’/’, ‘\\’)
colour_scheme = colour_scheme.replace(‘Packages’, ‘’)
font_size = settings.get(‘font_size’) or 10
font_face = settings.get(‘font_face’) or ‘Consolas’
doc = minidom.parse(path_packages + colour_scheme)
the_dict = doc.getElementsByTagName(‘dict’)[0]
the_array = the_dict.getElementsByTagName(‘array’)[0]
colour_settings = the_array.getElementsByTagName(‘dict’)[0]
bground = ‘’; fground = ‘’
for key_tag in colour_settings.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘background’:
bground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
fground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
dict_items = the_array.getElementsByTagName(‘dict’)[1:]
for item in dict_items:
scope = ‘’; colour = ‘’
for key_tag in item.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘scope’:
scope = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
colour = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
if scope != ‘’ and colour != ‘’:
self.colours[scope] = colour
curr_view = self.view
size = curr_view.size()
pt = 0; end = 1
while end <= size:
scope_name = curr_view.scope_name(pt)
while curr_view.scope_name(end) == scope_name and end <= size:
end += 1
region = sublime.Region(pt, end)
the_key = curr_view.scope_name(pt).strip()
if self.colours.has_key(the_key):
the_colour = self.colours[the_key]
else:
if re.match(‘source.[a-zA-Z_]*$’, the_key) is not None:
self.colours[the_key] = fground
the_colour = fground
else:
best_match = -1
for key in self.colours:
if curr_view.score_selector(pt, key) > best_match:
best_match = curr_view.score_selector(pt, key)
the_colour = self.colours[key]
self.colours[the_key] = the_colour
tidied_text = curr_view.substr(region)
tidied_text = tidied_text.replace(’&’, ‘&’)
tidied_text = tidied_text.replace(’<’, ‘<’)
tidied_text = tidied_text.replace(’>’, ‘>’)
tidied_text = tidied_text.replace(’\t’, ’ ’ * 4)
tidied_text = tidied_text.replace(’ ‘, ’ ’ * 4)
tidied_text = tidied_text.replace(’\n’, ‘
’)

		self.the_content.append((tidied_text, curr_view.scope_name(pt), the_colour))
		pt = end
		end = pt + 1
	curr_file = curr_view.file_name()
	head, tail = path.split(curr_file)
	fname, ext = path.splitext(tail)
	print head, tail, fname
	the_html = open(head + '\\' + fname + '_parsed.html', 'w')			# defaults to Packages\User currently
	the_html.write('<html>\n<head>\n<style type=\"text/css\">\n')
	the_html.write('\tspan { display: inline; border: 0; margin: 0; padding: 0; }\n')
	the_html.write('\tbody { ')
	if fground != '': the_html.write('color: ' + fground + ';')
	if bground != '': the_html.write(' background-color: ' + bground + ';')
	the_html.write(' font: ' + `font_size` + 'pt \"' + font_face + '\", Consolas, \"Times New Roman\";')
	the_html.write('\n}\n')
	the_html.write('</style>\n</head>\n<body>\n')

	for spans in self.the_content:
		the_html.write('<span style=\"color:' + spans[2] + '\">')
		the_html.write(spans[0] + '</span>')
	the_html.write('</body>\n</html>')
	the_html.close()[/code]

I should put it on GitHub at some point, but it’s still at an early stage.

Things for me to consider:

  1. Parsing the theme file once and persisting a dictionary of colour values.
  2. If I, instead, code to create a separate stylesheet, and use (a version of) the scopes as class-names, then it would be possible for you to tweak the stylesheet. (A biggish job :wink: )
  3. Perhaps giving an opportunity to change the name and location of the generated file. (Don’t think this is necessary at this stage.)
  4. Adapt for Apple, linux - probably need a little guidance with this;
  5. More error handling.



0 Likes

#11

To make this work for other oses I just need to change the few lines indicated. Could someone with Apple or Linux offer guidance :wink: . I know I can use ‘os.path.sep’ but it’s the escaping part that I need to be careful with. Andy.

[code] path_packages = sublime.packages_path()
settings = sublime.load_settings(‘Preferences.sublime-settings’)
colour_scheme = settings.get(‘color_scheme’)
colour_scheme = colour_scheme.replace(’/’, ‘\\’) # this one
colour_scheme = colour_scheme.replace(‘Packages’, ‘’)
font_size = settings.get(‘font_size’) or 10
font_face = settings.get(‘font_face’) or ‘Consolas’
tab_size = settings.get(‘tab_size’) or 4
doc = minidom.parse(path_packages + colour_scheme) # this one?

	curr_file = curr_view.file_name()
	head, tail = path.split(curr_file)
	fname, ext = path.splitext(tail)
	print head, tail, fname
	the_html = open(head + '\\' + fname + '_parsed.html', 'w')		# this one[/code]
0 Likes

#12

There’s a slight update here: it reads your chosen **tab_size **and uses this value to space out the resultant html.

[code]import sublime, sublime_plugin
from xml.dom import minidom
import re
from os import path

class PrintHtmlCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.colours = {}
self.the_content = ]
path_packages = sublime.packages_path()
settings = sublime.load_settings(‘Preferences.sublime-settings’)
colour_scheme = settings.get(‘color_scheme’)
colour_scheme = colour_scheme.replace(’/’, ‘\\’)
colour_scheme = colour_scheme.replace(‘Packages’, ‘’)
font_size = settings.get(‘font_size’) or 10
font_face = settings.get(‘font_face’) or ‘Consolas’
tab_size = settings.get(‘tab_size’) or 4
doc = minidom.parse(path_packages + colour_scheme)
the_dict = doc.getElementsByTagName(‘dict’)[0]
the_array = the_dict.getElementsByTagName(‘array’)[0]
colour_settings = the_array.getElementsByTagName(‘dict’)[0]
bground = ‘’; fground = ‘’
for key_tag in colour_settings.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘background’:
bground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
fground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
dict_items = the_array.getElementsByTagName(‘dict’)[1:]
for item in dict_items:
scope = ‘’; colour = ‘’
for key_tag in item.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘scope’:
scope = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
colour = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
if scope != ‘’ and colour != ‘’:
self.colours[scope] = colour
curr_view = self.view
size = curr_view.size()
pt = 0; end = 1
while end <= size:
scope_name = curr_view.scope_name(pt)
while curr_view.scope_name(end) == scope_name and end <= size:
end += 1
region = sublime.Region(pt, end)
the_key = curr_view.scope_name(pt).strip()
if self.colours.has_key(the_key):
the_colour = self.colours[the_key]
else:
if re.match(‘source.[a-zA-Z_]*$’, the_key) is not None:
self.colours[the_key] = fground
the_colour = fground
else:
best_match = -1
for key in self.colours:
if curr_view.score_selector(pt, key) > best_match:
best_match = curr_view.score_selector(pt, key)
the_colour = self.colours[key]
self.colours[the_key] = the_colour
tidied_text = curr_view.substr(region)
tidied_text = tidied_text.replace(’&’, ‘&’)
tidied_text = tidied_text.replace(’<’, ‘<’)
tidied_text = tidied_text.replace(’>’, ‘>’)
tidied_text = tidied_text.replace(’\t’, ’ ’ * tab_size)
tidied_text = tidied_text.replace(’ ’ * tab_size, ’ ’ * tab_size)
tidied_text = tidied_text.replace(’\n’, ‘
’)

		self.the_content.append((tidied_text, curr_view.scope_name(pt), the_colour))
		pt = end
		end = pt + 1
	curr_file = curr_view.file_name()
	head, tail = path.split(curr_file)
	fname, ext = path.splitext(tail)
	print head, tail, fname
	the_html = open(head + '\\' + fname + '_parsed.html', 'w')			# defaults to Packages\User currently
	the_html.write('<html>\n<head>\n<style type=\"text/css\">\n')
	the_html.write('\tspan { display: inline; border: 0; margin: 0; padding: 0; }\n')
	the_html.write('\tbody { ')
	if fground != '': the_html.write('color: ' + fground + ';')
	if bground != '': the_html.write(' background-color: ' + bground + ';')
	the_html.write(' font: ' + `font_size` + 'pt \"' + font_face + '\", Consolas, \"Times New Roman\";')
	the_html.write('\n}\n')
	the_html.write('</style>\n</head>\n<body>\n')

	for spans in self.the_content:
		the_html.write('<span style=\"color:' + spans[2] + '\">')
		the_html.write(spans[0] + '</span>')
	the_html.write('</body>\n</html>')
	the_html.close()[/code]
0 Likes

#13

This third (final… for the moment!) version should, I believe, work in other oses - but I’m unable to test it.

It’s more memory-efficient, as it writes each line to the file as it progresses, rather than building a potentially huge list (before writing to the file).

It saves the original file extension as part of the new name. So ‘this.js’ becomes ‘this_js_parsed.html’. I believe this to be useful, as it’s common to have different file types having the same filename.

[code]import sublime, sublime_plugin
from xml.dom import minidom
import re
from os import path

class PrintHtmlCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.colours = {}
path_packages = sublime.packages_path()
settings = sublime.load_settings(‘Preferences.sublime-settings’)
colour_scheme = settings.get(‘color_scheme’)
colour_scheme = colour_scheme.replace(’/’, ‘\\’)
colour_scheme = colour_scheme.replace(‘Packages’, ‘’)
font_size = settings.get(‘font_size’) or 10
font_face = settings.get(‘font_face’) or ‘Consolas’
tab_size = settings.get(‘tab_size’) or 4
# padd_bottom = settings.get(‘line_padding_bottom’) or 0
doc = minidom.parse(path_packages + colour_scheme)
the_dict = doc.getElementsByTagName(‘dict’)[0]
the_array = the_dict.getElementsByTagName(‘array’)[0]
colour_settings = the_array.getElementsByTagName(‘dict’)[0]
bground = ‘’; fground = ‘’
for key_tag in colour_settings.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘background’:
bground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
fground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
dict_items = the_array.getElementsByTagName(‘dict’)[1:]
for item in dict_items:
scope = ‘’; colour = ‘’
for key_tag in item.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘scope’:
scope = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
colour = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
if scope != ‘’ and colour != ‘’:
self.colours[scope] = colour

	curr_view = self.view
	curr_file = curr_view.file_name()
	head, tail = path.split(curr_file)
	fname, ext = path.splitext(tail)
	ext = ext.replace('.', '_')
	the_html = open(head + path.sep + fname + ext + '_parsed.html', 'w')
	the_html.write('<html>\n<head>\n<style type=\"text/css\">\n')
	the_html.write('\tspan { display: inline; border: 0; margin: 0; padding: 0; }\n')
	the_html.write('\tbody { ')
	if fground != '': the_html.write('color: ' + fground + ';')
	if bground != '': the_html.write(' background-color: ' + bground + ';')
	the_html.write(' font: ' + `font_size` + 'pt \"' + font_face + '\", Consolas, Monospace;')
	the_html.write('\n}\n')
	the_html.write('</style>\n</head>\n<body>\n')

	size = curr_view.size()
	pt = 0; end = 1
	while end <= size:
		scope_name = curr_view.scope_name(pt)
		while curr_view.scope_name(end) == scope_name and end <= size:
			end += 1
		region = sublime.Region(pt, end)
		the_key = scope_name.strip()
		if self.colours.has_key(the_key):
			the_colour = self.colours[the_key]
		else:
			if re.match('source\.[a-zA-Z_]*$', the_key) is not None:
				self.colours[the_key] = fground
				the_colour = fground
			else:
				best_match = -1
				for key in self.colours:
					if curr_view.score_selector(pt, key) > best_match:
						best_match = curr_view.score_selector(pt, key)
						the_colour = self.colours[key]
				self.colours[the_key] = the_colour
		tidied_text = curr_view.substr(region)
		tidied_text = tidied_text.replace('&', '&amp;')
		tidied_text = tidied_text.replace('<', '&lt;')
		tidied_text = tidied_text.replace('>', '&gt;')
		tidied_text = tidied_text.replace('\t', '&nbsp;' * tab_size)
		tidied_text = tidied_text.replace(' ' * tab_size, '&nbsp;' * tab_size)
		tidied_text = tidied_text.replace('\n', '<br>')

		the_html.write('<span style=\"color:' + the_colour + '\">')
		the_html.write(tidied_text + '</span>')
		pt = end
		end = pt + 1
	the_html.write('</body>\n</html>')
	the_html.close()[/code]

I was considering applying your chosen ‘line_padding_top/bottom’, but this requires quite a bit of css manipulation.

What’s the default font for Apple and Linux, etc.? I’ve left it currently as: ‘“Your font”, Consolas, Monospace’.

I’m also considering a version which would retain/generate the line-numbers, but I’ve had no feedback yet. Andy.

0 Likes

#14

I tried it out on Mac, and it worked great (after I fixed some things). It grabbed my theme colors just fine.

Don’t do this:

colour_scheme = colour_scheme.replace('/', '\\\\')

That is only valid for windows, use something like:

colour_scheme = os.path.normpath(colour_scheme)

It is neat that it can convert the whole file, but I would prefer under the selection. This also worked quite well once I changed the code to this. Granted it probably needs a check if there are no sels, but I was just testing.

size = curr_view.sel()[0].end() pt = curr_view.sel()[0].begin(); end = pt

Very impressive, and well done. Get this on Package Control :smile:. I suspect this could work on Linux, but I imagine it will require some tweaking to make sure you are importing the libraries you need.

0 Likes

#15

Hi @facelessuser and thank you.

colour_scheme = colour_scheme.replace('/', '\\\\')

I figured this would be ignored for non-Windows, but I should check ‘normpath’ as you suggest.

I figured it would be easy to amend to work with the selection - similar to your code. I could first check whether the selection is empty(). I could also check the column number and, perhaps, precede the HTML with the same number of spaces. I was thinking I could append a number to the new file name; this way, we could highlight different areas and quickly save them as separate files. Might this be useful? I might leave this decision till a bit later.

I studied three different xml modules :open_mouth: before settling on ‘minidom’ - in particular because it shouldn’t require a separate install. But I don’t know about Linux: perhaps someone with Linux might contribute :wink:

I might look at creating a separate thread (for my own education :smile: ). But I expect it should work well even with large files. (It does copy the whole theme file initially, but this is typically between 4-800 lines.)

I shall get it on my GitHub and look at Package Control after that. Regards, Andy.

0 Likes

#16

If you select more than four characters then this version will create an HTML file based on the selection, named ‘_part.html’. Otherwise, it is based on the whole file and named ‘_parsed.html’.

It should work for other oses but I need some feedback from Linux, Mac users. Andy.

[code]import sublime, sublime_plugin
from xml.dom import minidom
import re
from os import path

class PrintHtmlCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.colours = {}
path_packages = sublime.packages_path()
settings = sublime.load_settings(‘Preferences.sublime-settings’)
colour_scheme = settings.get(‘color_scheme’)
# colour_scheme = colour_scheme.replace(’/’, ‘\\’)
colour_scheme = path.normpath(colour_scheme)
colour_scheme = colour_scheme.replace(‘Packages’, ‘’)
font_size = settings.get(‘font_size’) or 10
font_face = settings.get(‘font_face’) or ‘Consolas’
tab_size = settings.get(‘tab_size’) or 4
# padd_bottom = settings.get(‘line_padding_bottom’) or 0
doc = minidom.parse(path_packages + colour_scheme)
the_dict = doc.getElementsByTagName(‘dict’)[0]
the_array = the_dict.getElementsByTagName(‘array’)[0]
colour_settings = the_array.getElementsByTagName(‘dict’)[0]
bground = ‘’; fground = ‘’
for key_tag in colour_settings.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘background’:
bground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
fground = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
dict_items = the_array.getElementsByTagName(‘dict’)[1:]
for item in dict_items:
scope = ‘’; colour = ‘’
for key_tag in item.getElementsByTagName(‘key’):
try:
if key_tag.firstChild.data.strip() == ‘scope’:
scope = key_tag.nextSibling.nextSibling.firstChild.data.strip()
elif key_tag.firstChild.data.strip() == ‘foreground’:
colour = key_tag.nextSibling.nextSibling.firstChild.data.strip()
except:
pass
if scope != ‘’ and colour != ‘’:
self.colours[scope] = colour

	curr_view = self.view
	curr_file = curr_view.file_name()
	head, tail = path.split(curr_file)
	fname, ext = path.splitext(tail)
	ext = ext.replace('.', '_')
	
	curr_sel = curr_view.sel()[0]
	if curr_sel.empty() or abs(curr_sel.end() - curr_sel.begin()) < 4:
		the_html = open(head + path.sep + fname + ext + '_parsed.html', 'w')
		size = curr_view.size()
		pt = 0; end = 1
	else:
		the_html = open(head + path.sep + fname + ext + '_part.html', 'w')
		size = curr_sel.end()
		pt = curr_sel.begin()
		end = pt + 1
	the_html.write('<html>\n<head>\n<style type=\"text/css\">\n')
	the_html.write('\tspan { display: inline; border: 0; margin: 0; padding: 0; }\n')
	the_html.write('\tbody { ')
	if fground != '': the_html.write('color: ' + fground + ';')
	if bground != '': the_html.write(' background-color: ' + bground + ';')
	the_html.write(' font: ' + `font_size` + 'pt \"' + font_face + '\", Consolas, Monospace;')
	the_html.write('\n}\n')
	the_html.write('</style>\n</head>\n<body>\n')
	
	while end <= size:
		scope_name = curr_view.scope_name(pt)
		while curr_view.scope_name(end) == scope_name and end <= size:
			end += 1
		region = sublime.Region(pt, end)
		the_key = scope_name.strip()
		if self.colours.has_key(the_key):
			the_colour = self.colours[the_key]
		else:
			if re.match('source\.[a-zA-Z_]*$', the_key) is not None:
				self.colours[the_key] = fground
				the_colour = fground
			else:
				best_match = -1
				for key in self.colours:
					if curr_view.score_selector(pt, key) > best_match:
						best_match = curr_view.score_selector(pt, key)
						the_colour = self.colours[key]
				self.colours[the_key] = the_colour
		tidied_text = curr_view.substr(region)
		tidied_text = tidied_text.replace('&', '&amp;')
		tidied_text = tidied_text.replace('<', '&lt;')
		tidied_text = tidied_text.replace('>', '&gt;')
		tidied_text = tidied_text.replace('\t', '&nbsp;' * tab_size)
		tidied_text = tidied_text.replace(' ' * tab_size, '&nbsp;' * tab_size)
		tidied_text = tidied_text.replace('\n', '<br>')

		the_html.write('<span style=\"color:' + the_colour + '\">')
		the_html.write(tidied_text + '</span>')
		pt = end
		end = pt + 1
	the_html.write('</body>\n</html>')
	the_html.close()[/code]
0 Likes

#17

Well it’s on GitHub now :smile:

You can trying pulling, pushing or forking, but I’ve haven’t read into this subject yet so it might take me a while to respond :laughing:

I know how to (just about) update my file and add new files to my repo. And, if I receive a request, I can probably ‘click through’ to respond to it.

How to add to Package Control… Presumably, this creates a link to my repo and is able to monitor updates to it. Andy.

0 Likes

#18

[quote=“agibsonsw”]Hi @facelessuser and thank you.

colour_scheme = colour_scheme.replace('/', '\\\\')

I figured this would be ignored for non-Windows, but I should check ‘normpath’ as you suggest.

I figured it would be easy to amend to work with the selection - similar to your code. I could first check whether the selection is empty(). I could also check the column number and, perhaps, precede the HTML with the same number of spaces. I was thinking I could append a number to the new file name; this way, we could highlight different areas and quickly save them as separate files. Might this be useful? I might leave this decision till a bit later.

I studied three different xml modules :open_mouth: before settling on ‘minidom’ - in particular because it shouldn’t require a separate install. But I don’t know about Linux: perhaps someone with Linux might contribute :wink:

I might look at creating a separate thread (for my own education :smile: ). But I expect it should work well even with large files. (It does copy the whole theme file initially, but this is typically between 4-800 lines.)

I shall get it on my GitHub and look at Package Control after that. Regards, Andy.[/quote]

The main linux issue is mainly if there is not a full install of Python 2.6. For instance, in Ubuntu, when you try and import an XML module, it usually fails because it cannot find an expat module. This is because Ubuntu comes with a minimal Python2.6 by default. Usually installing a full Python 2.6 is sufficient to get Linux working.

Sublime Text 2 by default trys adding a number of Python 2.6 Linux paths to the Python system path to ensure default modules can be accessed.
From ST2 console output (I think ST2 is Ubuntu specific though)

Py_GetPath(): :./lib/python26.zip:./lib/python2.6/:./lib/python2.6/plat-linux2:./lib/python2.6/lib-tk:./lib/python2.6/lib-old:./lib/python2.6/lib-dynload

To be extra safe, you could just add maybe a configurable path to try and add to the Python system path if it doesn’t exist. I think that would make it configurable for weird installs on different distros, but hopefully ST2’s attempt would be sufficient if the user has a full install of 2.6. Just something you might need to be aware of when Linux users start getting errors.

0 Likes

#19

[quote=“agibsonsw”]Well it’s on GitHub now :smile:

You can trying pulling, pushing or forking, but I’ve haven’t read into this subject yet so it might take me a while to respond :laughing:

I know how to (just about) update my file and add new files to my repo. And, if I receive a request, I can probably ‘click through’ to respond to it.

How to add to Package Control… Presumably, this creates a link to my repo and is able to monitor updates to it. Andy.[/quote]

Adding to Package Control is easy, you just have to fork @wbond’s default repository channel. You then just edit the respository JSON file and add your github link. You can actually edit it straight from github, so it is very easy.

Thanks for this package, it is pretty nifty and useful.

0 Likes

#20

@facelessuser. Thanks again.

Mmm, yes… I shall look into this :smile:

I shall await feedback from Mr or Mrs Linux. I’m in two minds about this though: if their set-up needs to be tweaked to enable “standard” libraries then surely they need to be aware of this, and configure their system accordingly?!

BTW The following is kinda neat, but there’s no advantage to be gained from the current - more straight-forward - approach:

for x, y in zip(('&', '<', '>', '\t', ' ' * tab_size, '\n'), ('&amp;', '&lt;', '&gt;', '&nbsp;' * tab_size, '&nbsp;' * tab_size, '<br>')): tidied_text = tidied_text.replace(x, y)
I might tinker with a version to add line numbers (li items) :wink: . But I’ll leave the current version as is for the moment.

Andy.

0 Likes

#21

Just thought I would let you know. I had this same issue with my Plist to Json convert plugin.

Python is full of neat little tricks like that. Line numbers would be great, it would be cool if you could use the theme color for line numbers if it is available as well.

<key>gutterForeground</key>
0 Likes

#22

@facelessuser: Good to be aware of a potential issue :wink:

An alternative version with line numbers shouldn’t be too tricky - reading gutterForeground is straight-forward as well. I would wrap everything in ol/li items. Instead of just inserting
I would close, and open, a new ‘li’. But I would also need to close the current ‘span’ and re-open it with the same colour. Not a problem really :smile:

I’ll probably need to tweak (reset) the css-behaviour for block-li items as well. (Just thinking out loud… )

Andy.

0 Likes

#23

Nice when things work out within 20 minutes :smiley: . Have to test a bit though. Andy.


0 Likes

#24

Here are some suggestions that I think would be great.

Currently if the view does not exist on disk, the generation of the HTML will fail because you rely on the file name path from the view. I would suggest instead of doing that, maybe just generate temporary html and auto-open it in a web browser (there is a Markdown plugin that does something similar on Package Control). That way you can save the HTML if you want, or just copy and paste from the web page into en email or whatever.

Another suggestion is, I might code with a black background etc, but if I want to copy and paste colorized code to an email, I might want to use a different white background theme. So maybe add a setting:

// false to use the current color theme in use or a string to use the desired alternate color theme(relative to Packages)
"use_alternate_print_color_theme": "User/MyColorTheme.tmTheme"

Anyways, I hope that makes sense.

0 Likes