Sublime Forum

Copy text with highlighted colors

#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

#25

The attached is a nice touch :wink:


0 Likes

#26

@facelessuser: "maybe just generate temporary html " - is it possible to feed an HTML string to a browser, without first saving the file? I suppose so - I’ve never tried to do this before :wink:. But I could certainly modify the code to create a temporary/bogus file name for the HTML.

Myself, and a number of other posters, have struggled to obtain the right command that previews in a browser. I did consider this, but I assume a lot of users already have their own method of doing this reliably (for them). I wouldn’t want to rely on the installation of a different package to do this; although, perhaps you’re suggesting I could examine the code for the Markdown package?

I suppose I could read another setting, that identifies the users’ command to run once the HTML is generated :question: Mmm

Having a setting for an alternative, printable, theme is certainly a good idea :wink:. This shouldn’t be tricky. I suppose there could also be a setting to specify: false == don’t apply background, or ‘#NNNNNN’. Andy.

0 Likes

#27

[quote=“agibsonsw”]@facelessuser: "maybe just generate temporary html " - is it possible to feed an HTML string to a browser, without first saving the file? I suppose so - I’ve never tried to do this before :wink:. But I could certainly modify the code to create a temporary/bogus file name for the HTML.

Myself, and a number of other posters, have struggled to obtain the right command that previews in a browser. I did consider this, but I assume a lot of users already have their own method of doing this reliably (for them). I wouldn’t want to rely on the installation of a different package to do this; although, perhaps you’re suggesting I could examine the code for the Markdown package?
[/quote]

No sense in re-inventing the wheel. I was more like you guessed, just examine some code to understand what others do to have it work reliably. I just think, auto-opening the file in a browser would make the workflow very nice. Also, the current method is going to create HTMLs all over, so creating temp HTMLs in one place will keep junk files to a minimum.

[quote=“agibsonsw”]
Having a setting for an alternative, printable, theme is certainly a good idea :wink:. This shouldn’t be tricky. I suppose there could also be a setting to specify: false == don’t apply background, or ‘#NNNNNN’. Andy.[/quote]

I don’t think ignoring the background will be too useful (tough to say); usually the colors of text and such only work well with the background selected. But alternative color themes…that would be nice :smile: .

0 Likes

#28

Below is the version that optionally allows you to print line numbers, using a different key-binding. I haven’t updated my repo yet.

{ "keys": "ctrl+alt+m"], "command": "print_html", "args": { "numbers": false } }, { "keys": "ctrl+alt+n"], "command": "print_html", "args": { "numbers": true } },

[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, numbers): # numbers == True: output line numbers
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 = ‘’; gfground = ‘’
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()
elif key_tag.firstChild.data.strip() == ‘gutterForeground’:
gfground = 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('<!DOCTYPE html>\n')
	the_html.write('<html>\n<head>\n<title>' + fname + ext + '</title>\n')
	the_html.write('<style type=\"text/css\">\n')
	the_html.write('\tspan { display: inline; border: 0; margin: 0; padding: 0; }\n')
	if numbers and gfground != '':
		the_html.write('\tli { color: ' + gfground  + '; }\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')
	if numbers: the_html.write('<ol>\n<li>')
	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)
		if numbers:
			new_li = '</span></li>\n<li><span style=\"color:' + the_colour + '\">'
			tidied_text = tidied_text.replace('\n', new_li)
		else:
			tidied_text = tidied_text.replace('\n', '<br>')
		# 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)
		the_html.write('<span style=\"color:' + the_colour + '\">')
		the_html.write(tidied_text + '</span>')
		pt = end
		end = pt + 1
	if numbers: the_html.write('</li>\n</ol>')
	the_html.write('\n</body>\n</html>')
	the_html.close()[/code]

Let me know if it misbehaves on different systems/browsers; in particular, I may need to tweak the css so that un-wanted gaps between each line are removed.

0 Likes

#29

@facelessuser

Yes, I’ve tried this myself and the results weren’t good. I even tried inverting all the colour-numbers :open_mouth: but most of the text ended up blue-ish :laughing:

You mean to store the HTML in their default temp folder? I think that this, and other approaches, might wait for more user feedback. In the meantime, I should modify the code so that, if the view isn’t saved, a temporary name is created. I’ll probably just use ‘temp_parsed.html’ for the moment.

0 Likes

#30

Actual numbers opposed to always starting from 1 :smile: :

row = curr_view.rowcol(pt)[0] + 1 .... // Apply start number to first list item if numbers: the_html.write('<ol>\n<li value="%d">' % row)

0 Likes

#31

[quote=“agibsonsw”]@facelessuser

Yes, I’ve tried this myself and the results weren’t good. I even tried inverting all the colour-numbers :open_mouth: but most of the text ended up blue-ish :laughing:

You mean to store the HTML in their default temp folder? I think that this, and other approaches, might wait for more user feedback. In the meantime, I should modify the code so that, if the view isn’t saved, a temporary name is created. I’ll probably just use ‘temp_parsed.html’ for the moment.[/quote]

Hmm. Maybe I will look into then. The clutter created by writing the HTMLs in the same folder as the actual file I find less than desirable. If you aren’t anxious to do such a thing, I will probably play around with it and issue a pull request if I come up with something good.

0 Likes

#32

@facelessuser :sunglasses:

If they haven’t saved the view, how do I retrieve their current project or default path reliably/cross-os? For the moment I want to store a temp HTML there.

0 Likes

#33

I already have it working. You just need the the Desktop module from Paul Boddie boddie.org.uk/python/downloa … 0.4.tar.gz. Really, it is just the folder called desktop in the tar ball you need. It is the same package that “SideBarEnhancements” uses and “Markdown Preview”. It is super easy :smile:.

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

class PrintHtmlCommand(sublime_plugin.TextCommand):
def run(self, edit, numbers): # numbers == True: output line numbers
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 = ‘’; gfground = ‘’
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()
elif key_tag.firstChild.data.strip() == ‘gutterForeground’:
gfground = 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]
  the_html = tempfile.NamedTemporaryFile(delete=False, suffix='.html')
  if curr_sel.empty() or abs(curr_sel.end() - curr_sel.begin()) < 4:
     size = curr_view.size()
     pt = 0; end = 1
  else:
     size = curr_sel.end()
     pt = curr_sel.begin()
     end = pt + 1
  row = curr_view.rowcol(pt)[0] + 1
  the_html.write('<!DOCTYPE html>\n')
  the_html.write('<html>\n<head>\n<title>' + fname + ext + '</title>\n')
  the_html.write('<style type=\"text/css\">\n')
  the_html.write('\tspan { display: inline; border: 0; margin: 0; padding: 0; }\n')
  if numbers and gfground != '':
     the_html.write('\tli { color: ' + gfground  + '; }\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')
  if numbers: the_html.write('<ol>\n<li value="%d">' % row)
  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)
     if numbers:
        new_li = '</span></li>\n<li><span style=\"color:' + the_colour + '\">'
        tidied_text = tidied_text.replace('\n', new_li)
     else:
        tidied_text = tidied_text.replace('\n', '<br>')
     # 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)
     the_html.write('<span style=\"color:' + the_colour + '\">')
     the_html.write(tidied_text + '</span>')
     pt = end
     end = pt + 1
  if numbers: the_html.write('</li>\n</ol>')
  the_html.write('\n</body>\n</html>')
  the_html.close()
  desktop.open(the_html.name)

[/code]

0 Likes

#34

Mmm I’m reluctant to use any non-standard libraries, creating a dependency. Perhaps this could be plan C? Or just an alternative version.

I think I’ve been unnecessarily mucking around with paths; it will save in their current/default folder anyway. Andy.

0 Likes