Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 55 additions & 52 deletions inksyntax.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,27 @@
A source code syntax highlighter plugin for Inkscape.
'''

import codecs
import os
import platform
import sys
from subprocess import PIPE, Popen
import traceback
from lxml import etree
import warnings

import gi
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk, Gtk, Pango

__version__ = '0.2'

# Update PYTHONPATH for Inkscape plugins
try:
# Ask inkscape for its extension directory
p = Popen(['inkscape', '--extension-directory'], stdout=PIPE)
out = p.communicate()[0]
sys.path.append(out.strip())
except OSError:
# Use some default directories
sys.path.append('/usr/share/inkscape/extensions')
sys.path.append(r'c:/Program Files/Inkscape/share/extensions')
sys.path.append(os.path.dirname(__file__))

import inkex
from simplestyle import *
from StringIO import StringIO
from io import StringIO

# from inkex.utils import debug

def hl_lang (s):
'''Return the main highlight language name.'''
Expand Down Expand Up @@ -92,6 +88,11 @@ def hl_lang (s):
u'xlink': XLINK_NS,
}

def decode(stringToDecode):
'''
Decode the given string and return it.
'''
return codecs.escape_decode(bytes(stringToDecode, "utf-8"))[0].decode("utf-8")

def search_highlighter(liststore, name):
'''
Expand Down Expand Up @@ -138,12 +139,12 @@ def edit_fragment(text='', highlighter='', callback=None):
liststore = Gtk.ListStore(str, object)
if HAVE_PYGMENTS:
langs = pygments_langs.keys()
langs.sort()
langs = sorted(langs)
for name in langs:
liststore.append([name + ' (Pygments)', pygments_langs[name]])
if HAVE_HIGHLIGHT:
langs = highlight_langs.keys()
langs.sort()
langs = sorted(langs)
for name in langs:
liststore.append([name + ' (Highlight)', highlight_langs[name]])
completion.set_model(liststore)
Expand All @@ -168,7 +169,6 @@ def on_lang_edit_changed(ed):
scroll.set_shadow_type(Gtk.ShadowType.IN)
grid.attach_next_to(scroll, label, Gtk.PositionType.BOTTOM, 2, 1)
view = Gtk.TextView()
view.override_font(Pango.FontDescription.from_string('monospace 11'))
view.set_border_width(4)
view.get_buffer().set_text(text)
view.set_vexpand(True)
Expand All @@ -187,7 +187,9 @@ def on_lang_edit_changed(ed):
box = Gtk.Box()
box.set_spacing(8)
grid.attach_next_to(box, line_box, Gtk.PositionType.BOTTOM, 2, 1)
ok_but = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
ok_but = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
ok_but.set_always_show_image(True)
box.pack_end(ok_but, False, False, 0)
cancel_but = Gtk.Button.new_from_stock(Gtk.STOCK_CANCEL)
Expand All @@ -197,7 +199,9 @@ def on_lang_edit_changed(ed):

# Disable Ok by default
ok_but.set_sensitive(False)
lang_edit.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY,
with warnings.catch_warnings():
warnings.simplefilter("ignore")
lang_edit.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY,
Gtk.STOCK_DIALOG_WARNING)

# Callback on OK press
Expand All @@ -210,11 +214,15 @@ def on_ok(*args):
if callback is not None:
buf = view.get_buffer()
beg,end = buf.get_bounds()

with warnings.catch_warnings():
warnings.simplefilter("ignore")
fontName = font_button.get_font_name()
callback(buf.get_text(beg, end, False),
backend=backend,
highlighter=highlighter,
line_numbers=line_box.get_active(),
font=font_button.get_font_name())
font=fontName)
Gtk.main_quit()
ok_but.connect('clicked', on_ok)

Expand All @@ -224,12 +232,10 @@ def on_ok(*args):
Gtk.main()


class InkSyntaxEffect(inkex.Effect):
def __init__(self):
inkex.Effect.__init__(self)
self.OptionParser.add_option('-s', '--src-lang', action='store',
type='string', dest='src_lang',
default='txt', help='Source language')
class InkSyntaxEffect(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument('-s', '--src-lang', type=str, default='txt', help='Source language')

def effect(self):
src_lang = self.options.src_lang

Expand All @@ -243,9 +249,9 @@ def inserter(self, text, backend, highlighter,
line_numbers=False, font=None):
# Get SVG highlighted output as character string
if backend == 'highlight':
# For highlight 2.x
# For highlight 2.x
#cmd = ["highlight", "--syntax", stx, "--svg"]
# For highlight 3.x
# For highlight 3.x
cmd = ["highlight", "--syntax",
hl_lang (highlighter), # Fix for hl 3.9
"-O", "svg"]
Expand All @@ -254,19 +260,20 @@ def inserter(self, text, backend, highlighter,
p = Popen(cmd, stdin=PIPE, stdout=PIPE)
out = p.communicate(text)[0]
else:
out = pygments.highlight(text, highlighter(), SvgFormatter())
out = pygments.highlight(text, highlighter(), SvgFormatter(linenos=line_numbers))

# Parse the SVG tree and get the group element
try:
tree = inkex.etree.parse(StringIO(out))
except inkex.etree.XMLSyntaxError:
tree = etree.parse(StringIO(out))
except etree.XMLSyntaxError:
# Hack for highlight 2.12
out2 = out.replace('</span>', '</tspan>')
tree = inkex.etree.parse(StringIO(out2))
group = tree.getroot().find('{%s}g' % SVG_NS)
tree = etree.parse(StringIO(out2))
group = tree.getroot().find(f"{{{SVG_NS}}}g")


# Remove the background rectangle
if group[0].tag == '{%s}rect' % SVG_NS:
if group[0].tag == f"{{{SVG_NS}}}rect":
del group[0]

# Apply a CSS style
Expand All @@ -276,32 +283,29 @@ def inserter(self, text, backend, highlighter,
self.apply_style_pygments(group)

# Set the attributes for modification
group.attrib['{%s}text' % INKSYNTAX_NS] = text.encode('string-escape')
group.attrib[f"{{{INKSYNTAX_NS}}}text"] = text

# Add the SVG group to the document
svg = self.document.getroot()
self.current_layer.append(group)
self.svg.get_current_layer().append(group)

# Try to apply properties
if font is not None:
fd = Pango.FontDescription.from_string(font)
group.set('style', formatStyle({'font-size': '%fpt' % (fd.get_size()/Pango.SCALE),
'font-family': fd.get_family()}))
# Try to apply properties
if font is not None:
fd = Pango.FontDescription.from_string(font)
group.set('style', str(inkex.Style({'font-size': f"{(fd.get_size()/Pango.SCALE)}pt", 'font-family': fd.get_family()})))

def get_old(self):
# Search amongst all selected <g> nodes
for node in [self.selected[i] for i in self.options.ids
if self.selected[i].tag == '{%s}g' % SVG_NS]:
for node in [self.svg.selected[i] for i in self.options.ids
if self.svg.selected[i].tag == f"{{{SVG_NS}}}g"]:
# Return first <g> with a inksyntax:text attribute
if '{%s}text' % INKSYNTAX_NS in node.attrib:
return (node,
node.attrib.get('{%s}text' %
INKSYNTAX_NS).decode('string-escape'))
decode(node.attrib.get(f"{{{INKSYNTAX_NS}}}text")))
# Pre 0.2 NS compatibility
if '{%s}text' % INKSYNTAX_OLD_NS in node.attrib:
return (node,
node.attrib.get('{%s}text' %
INKSYNTAX_OLD_NS).decode('string-escape'))
decode(node.attrib.get(f"{{{INKSYNTAX_OLD_NS}}}text")))
return None, ''

def apply_style_highlight(self, group):
Expand All @@ -322,14 +326,14 @@ def apply_style_highlight(self, group):
'str': {'fill': '#ff0000'},
'sym': {'fill': '#000000'},
}
for txt in [x for x in group if x.tag == '{%s}text' % SVG_NS]:
for txt in [x for x in group if x.tag == f"{{{SVG_NS}}}tex"]:
# Modify the line spacing
line_spacing_factor = 0.65
txt.set('y', str(line_spacing_factor * float(txt.get('y'))))
# Preserve white spaces
txt.attrib['{%s}space' % XML_NS] = 'preserve'
txt.attrib[f"{{{XML_NS}}}space"] = 'preserve'
# Set the highlight color
for tspan in [x for x in txt if x.tag == '{%s}tspan' % SVG_NS]:
for tspan in [x for x in txt if x.tag == f"{{{SVG_NS}}}tspan"]:
cls = tspan.get('class')
if cls in style:
tspan.set('style', formatStyle(style[cls]))
Expand All @@ -338,7 +342,7 @@ def apply_style_pygments(self, group):
pass

if __name__ == '__main__':
# Standalone
# Standalone
if len(sys.argv) == 1:
def cb(text, **kwds):
print(text, kwds)
Expand All @@ -352,5 +356,4 @@ def cb(text, **kwds):
''', callback=cb)
# Called as a plugin
else:
effect = InkSyntaxEffect()
effect.affect()
InkSyntaxEffect().run()