From c60deaea19ce823abb3cf724f516edfa044efc39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Br=C3=B6tzmann?= Date: Wed, 8 May 2019 11:53:13 +0200 Subject: [PATCH] [syntax_highlight] Fix deprecation warnings, fix pylint errors This fixes some deprecation warnings related to Gtk.Color and restructures code and formatting according to pylint suggestions --- syntax_highlight/README.md | 28 +- syntax_highlight/chat_syntax_highlighter.py | 154 ++++--- syntax_highlight/config_dialog.ui | 472 ++++++++++---------- syntax_highlight/gtkformatter.py | 45 +- syntax_highlight/plugin_config.py | 62 +-- syntax_highlight/plugin_config_dialog.py | 162 +++---- syntax_highlight/syntax_highlight.py | 70 ++- syntax_highlight/types.py | 27 +- 8 files changed, 511 insertions(+), 509 deletions(-) diff --git a/syntax_highlight/README.md b/syntax_highlight/README.md index 0199de3..29f16cf 100644 --- a/syntax_highlight/README.md +++ b/syntax_highlight/README.md @@ -1,23 +1,22 @@ # Syntax Highlighting Plugin for Gajim -[Gajim](https://gajim.org) Plugin that highlights source code blocks in chatbox. +[Gajim](https://gajim.org) Plugin that highlights source code blocks in the chat window. ## Installation -The recommended way of installing this plugin is to use -Gajim's Plugin Installer. +The recommended way of installing this plugin is to use Gajim's Plugin Installer. For more information and instruction on how to install plugins manually, please -refer to the [Gajim Plugin Wiki seite](https://dev.gajim.org/gajim/gajim-plugins/wikis/home#how-to-install-plugins). +refer to the [Gajim Plugin Wiki site](https://dev.gajim.org/gajim/gajim-plugins/wikis/home#how-to-install-plugins). ## Usage This plugin uses markdown-style syntax to identify which parts of a message -should be formatted as code in the chatbox. +should be formatted as code in the chat window. ``` -Inline source code will be highlighted when placed in between `two single +Inline source code will be highlighted when placed in between `two single back-ticks`. ``` @@ -35,8 +34,8 @@ i.e. there must be a newline here. ``` ```` -In case no languge is specified with the opening tag or the specified language -could not be identified, the default languge configured in the settings is +In case no language is specified with the opening tag or the specified language +could not be identified, the default language configured in the settings is used. You can test it by copying and sending the following text to one of your @@ -53,20 +52,19 @@ using the plugin.) ## Relation to XEP-0393 - 'Message Styling' - https://xmpp.org/extensions/xep-0393.html#pre-block In [XEP-0393](https://xmpp.org/extensions/xep-0393.html), the back-tick based syntax is defined as markup for preformatted -text blocks, respectively inline performatted text. -Formatting of such text blocks with monospaced fonts is recommended by the XEP. +text blocks, respectively inline preformatted text. +Formatting of such text blocks with mono-spaced fonts is recommended by the XEP. By using the same syntax as defined in XEP-0393 XMPP clients with only XEP-0393 support but without syntax highlighting can at least present their users blocks -of pre-formatted text. +of preformatted text. Since text in between the back-tick markers is not further formatted by this -plugin, it can be considered "pre-formatted". +plugin, it can be considered "preformatted". Hence, this plugin is compatible to the formatting options defined by XEP-0393, [section 5.1.2, "Preformatted Text"](https://xmpp.org/extensions/xep-0393.html#pre-block) and [section 5.2.5, "Preformatted Span"](https://xmpp.org/extensions/xep-0393.html#mono). @@ -84,7 +82,7 @@ including default language, style, font settings, background color and formattin of the code markers. In the configuration window, the current settings are displayed in an -interactive preview pannel. This allows you to directly check how code would +interactive preview panel. This allows you to directly check how code would look like in the message window. @@ -117,7 +115,7 @@ in a terminal to display the debug messages. ## Credits Since I had no experience in writing Plugins for Gajim, I used the -[Latex Plugin](https://trac-plugins.gajim.org/wiki/LatexPlugin) +[Latex Plugin](https://dev.gajim.org/gajim/gajim-plugins/wikis/LatexPlugin) written by Yves Fischer and Yann Leboulanger as an example and copied a big portion of initial code. Therefore, credits go to the authors of the Latex Plugin for providing an example. diff --git a/syntax_highlight/chat_syntax_highlighter.py b/syntax_highlight/chat_syntax_highlighter.py index 63c9508..c18cc18 100644 --- a/syntax_highlight/chat_syntax_highlighter.py +++ b/syntax_highlight/chat_syntax_highlighter.py @@ -4,15 +4,14 @@ import pygments from gi.repository import Gtk -from gajim.plugins.helpers import log - - -from .gtkformatter import GTKFormatter -from .types import MatchType, LineBreakOptions, CodeMarkerOptions - +from syntax_highlight.gtkformatter import GTKFormatter +from syntax_highlight.types import MatchType +from syntax_highlight.types import LineBreakOptions +from syntax_highlight.types import CodeMarkerOptions log = logging.getLogger('gajim.p.syntax_highlight') + class ChatSyntaxHighlighter: def hide_code_markup(self, buf, start, end): tag = buf.get_tag_table().lookup('hide_code_markup') @@ -27,8 +26,7 @@ class ChatSyntaxHighlighter: line_break = self.config.get_line_break_action() return (line_break == LineBreakOptions.ALWAYS) \ - or (is_multiline and line_break == LineBreakOptions.MULTILINE) - + or (is_multiline and line_break == LineBreakOptions.MULTILINE) def format_code(self, buf, s_tag, s_code, e_tag, e_code, language): style = self.config.get_style_name() @@ -37,26 +35,26 @@ class ChatSyntaxHighlighter: self.hide_code_markup(buf, e_code, e_tag) else: comment_tag = GTKFormatter.create_tag_for_token( - pygments.token.Comment, - pygments.styles.get_style_by_name(style)) + pygments.token.Comment, + pygments.styles.get_style_by_name(style)) buf.get_tag_table().add(comment_tag) buf.apply_tag(comment_tag, s_tag, s_code) buf.apply_tag(comment_tag, e_tag, e_code) code = s_code.get_text(e_code) - log.debug("full text to encode: %s.", code) + log.debug('full text to encode: %s.', code) - - start_mark = buf.create_mark(None, s_code, False) + start_mark = buf.create_mark(None, s_code, False) lexer = None if language is None: lexer = self.config.get_default_lexer() - log.info("No Language specified. Falling back to default lexer: %s.", - self.config.get_default_lexer_name()) + log.info('No Language specified. ' + 'Falling back to default lexer: %s.', + self.config.get_default_lexer_name()) else: - log.debug("Using lexer for %s.", str(language)) + log.debug('Using lexer for %s.', str(language)) lexer = self.config.get_lexer_with_fallback(language) if lexer is None: @@ -71,13 +69,15 @@ class ChatSyntaxHighlighter: def find_multiline_matches(self, text): start = None matches = [] - #Less strict, allow prefixed whitespaces: for i in re.finditer(r'(?:^|\n)[ |\t]*(```)\S*[ |\t]*(?:\n|$)', text, re.DOTALL): + # Less strict, allow prefixed whitespaces: + # for i in re.finditer(r'(?:^|\n)[ |\t]*(```)\S*[ |\t]*(?:\n|$)', + # text, re.DOTALL): for i in re.finditer(r'(?:^|\n)(```)\S*(?:\n|$)', text, re.DOTALL): if start is None: start = i elif re.match(r'^\n```', i.group(0)) is not None: matches.append( - (start.start(), i.end(), text[start.start():i.end()])) + (start.start(), i.end(), text[start.start():i.end()])) start = None else: # not an end... @@ -91,37 +91,40 @@ class ChatSyntaxHighlighter: defined in XEP-0393. The same applies mirrored to the end marker. """ - return [(i.start(1), i.end(1), i.group(1)) for i in \ - re.finditer(r'(?:^|\s|\*|~|_)(`((?!`).+?)`)(?:\s|\*|~|_|$)', text)] + return [(i.start(1), i.end(1), i.group(1)) for i in + re.finditer(r'(?:^|\s|\*|~|_)(`((?!`).+?)`)(?:\s|\*|~|_|$)', + text)] def merge_match_groups(self, real_text, inline_matches, multiline_matches): it_inline = iter(inline_matches) - it_multi = iter(multiline_matches) - length = len(real_text) + it_multi = iter(multiline_matches) + length = len(real_text) # Just to get cleaner code below... def get_next(iterator): - return next(iterator, (length, length, "")) + return next(iterator, (length, length, '')) # In order to simplify the process, we use the 'length' here. cur_inline = get_next(it_inline) - cur_multi = get_next(it_multi) + cur_multi = get_next(it_multi) pos = 0 - # This will contain tuples with parts of the input and its classification - parts = [] + # This will contain tuples with parts of the input and its + # classification + parts = [] while pos < length: - log.debug("-> in: %s", str(cur_inline)) - log.debug("-> mu: %s", str(cur_multi)) + log.debug('-> in: %s', str(cur_inline)) + log.debug('-> mu: %s', str(cur_multi)) # selected = (start, end, type) - selected = (cur_inline[0], cur_inline[1], MatchType.INLINE) \ - if cur_inline[0] < cur_multi[0] \ - else (cur_multi[0], cur_multi[1], MatchType.MULTILINE) \ - if cur_multi[0] < length \ - else (pos, length, MatchType.TEXT) - log.debug("--> select: %s", str(selected)) + if cur_inline[0] < cur_multi[0]: + selected = (cur_inline[0], cur_inline[1], MatchType.INLINE) + elif cur_multi[0] < length: + selected = (cur_multi[0], cur_multi[1], MatchType.MULTILINE) + else: + selected = (pos, length, MatchType.TEXT) + log.debug('--> select: %s', str(selected)) # Handle plain text string parts (and unforseen errors...) if pos < selected[0]: @@ -129,7 +132,7 @@ class ChatSyntaxHighlighter: parts.append((real_text[pos:end], MatchType.TEXT)) pos = selected[0] elif pos > selected[0]: - log.error("Should not happen, position > found match.") + log.error('Should not happen, position > found match.') # Cut out and append selected text segment parts.append((real_text[selected[0]:selected[1]], selected[2])) @@ -158,67 +161,76 @@ class ChatSyntaxHighlighter: fixed = (marker_len_no_newline + 1, '\n') return fixed - buf = self.textview.tv.get_buffer() - # first, try to find inline or multiline code snippets - inline_matches = self.find_inline_matches(real_text) - multiline_matches = self.find_multiline_matches(real_text) + # First, try to find inline or multiline code snippets + inline_matches = self.find_inline_matches(real_text) + multiline_matches = self.find_multiline_matches(real_text) if not inline_matches and not multiline_matches: - log.debug("Stopping early, since there is no code block in it....") + log.debug('Stopping early, since there is no code block in it...') return - iterator = iter_ if iter_ is not None else buf.get_end_iter() + iterator = iter_ if iter_ is not None else buf.get_end_iter() # Create a start marker with left gravity before inserting text. - start_mark = buf.create_mark("SHP_start", iterator, True) - end_mark = buf.create_mark("SHP_end", iterator, False) + start_mark = buf.create_mark('SHP_start', iterator, True) + end_mark = buf.create_mark('SHP_end', iterator, False) - insert_newline_for_multiline = self.check_line_break(True) - insert_newline_for_inline = self.check_line_break(False) + insert_newline_for_multiline = self.check_line_break(True) + insert_newline_for_inline = self.check_line_break(False) split_text = self.merge_match_groups( - real_text, inline_matches, multiline_matches) + real_text, inline_matches, multiline_matches) buf.begin_user_action() for num, (text_to_insert, match_type) in enumerate(split_text): - language = None - end_of_message = num == (len(split_text) - 1) + language = None + end_of_message = num == (len(split_text) - 1) if match_type == MatchType.TEXT: self.textview.detect_and_print_special_text( - text_to_insert, other_tags, graphics=_graphics, - iter_=iterator, additional_data=_additional) + text_to_insert, other_tags, graphics=_graphics, + iter_=iterator, additional_data=_additional) else: if match_type == MatchType.MULTILINE: language_match = re.search( - '\n*```([^\n]*)\n', text_to_insert, re.DOTALL) + '\n*```([^\n]*)\n', text_to_insert, re.DOTALL) + language = None if language_match is None \ - else language_match.group(1) + else language_match.group(1) + language_len = 0 if language is None else len(language) # We account the language word width for the front marker - front = fix_newline(text_to_insert[0], 3 + language_len, - insert_newline_for_multiline) - back = fix_newline(text_to_insert[-1], 3, - insert_newline_for_multiline and not end_of_message) + front = fix_newline( + text_to_insert[0], + 3 + language_len, + insert_newline_for_multiline) + back = fix_newline( + text_to_insert[-1], + 3, + insert_newline_for_multiline and not end_of_message) else: - front = fix_newline(text_to_insert[0], 1, - insert_newline_for_inline) - back = fix_newline(text_to_insert[-1], 1, - insert_newline_for_inline and not end_of_message) + front = fix_newline( + text_to_insert[0], + 1, + insert_newline_for_inline) + back = fix_newline( + text_to_insert[-1], + 1, + insert_newline_for_inline and not end_of_message) marker_widths = (front[0], back[0]) text_to_insert = ''.join([front[1], text_to_insert, back[1]]) - # insertion invalidates iterator, let's use our start mark... + # Insertion invalidates iterator, let's use our start mark... self.insert_and_format_code(buf, text_to_insert, language, marker_widths, start_mark, end_mark, other_tags) iterator = buf.get_iter_at_mark(end_mark) - # the current end of the buffer's contents is the start for the + # The current end of the buffer's contents is the start for the # next iteration buf.move_mark(start_mark, iterator) @@ -235,7 +247,7 @@ class ChatSyntaxHighlighter: def insert_and_format_code(self, buf, insert_text, language, marker, start_mark, end_mark, other_tags=None): - start_iter = buf.get_iter_at_mark(start_mark) + start_iter = buf.get_iter_at_mark(start_mark) if other_tags: buf.insert_with_tags_by_name(start_iter, insert_text, @@ -243,14 +255,14 @@ class ChatSyntaxHighlighter: else: buf.insert(start_iter, insert_text) - tag_start = buf.get_iter_at_mark(start_mark) - tag_end = buf.get_iter_at_mark(end_mark) - s_code = tag_start.copy() - e_code = tag_end.copy() + tag_start = buf.get_iter_at_mark(start_mark) + tag_end = buf.get_iter_at_mark(end_mark) + s_code = tag_start.copy() + e_code = tag_end.copy() s_code.forward_chars(marker[0]) e_code.backward_chars(marker[1]) - log.debug("full text between tags: %s.", tag_start.get_text(tag_end)) + log.debug('full text between tags: %s.', tag_start.get_text(tag_end)) self.format_code(buf, tag_start, s_code, tag_end, e_code, language) @@ -266,6 +278,6 @@ class ChatSyntaxHighlighter: buf.apply_tag(tag, tag_start, tag_end) def __init__(self, config, textview): - self.last_end_mark = None - self.config = config - self.textview = textview + self.last_end_mark = None + self.config = config + self.textview = textview diff --git a/syntax_highlight/config_dialog.ui b/syntax_highlight/config_dialog.ui index 6cba6a1..64328d3 100644 --- a/syntax_highlight/config_dialog.ui +++ b/syntax_highlight/config_dialog.ui @@ -42,271 +42,271 @@ ; Test your highlighting here <!-- Test your highlighting here --> - + + True False + 18 + vertical - - - - + True False - 18 - vertical + 40 + 6 + 12 - + True False - 40 - 6 - 12 - - - True - False - end - Default language for syntax highlighting - 0 - - - 0 - 0 - - - - - True - False - end - Insert line breaks around code blocks - 0 - - - 0 - 1 - - - - - True - False - - - - - 0 - - - - - 1 - 0 - - - - - True - False - line_break_selection - - - - - 0 - - - - - 1 - 1 - - - - - True - False - - - - - 0 - - - - - 1 - 2 - - - - - True - False - end - Select syntax highlighting style - 0 - - - 0 - 2 - - - - - True - False - end - Select code marker (the backticks) formatting - 0 - - - 0 - 3 - - - - - True - False - code_marker_selection - - - - - 0 - - - - - 1 - 3 - - - - - True - False - end - Select font for code snippets - 0 - - - 0 - 4 - - - - - True - True - True - Sans 12 - de-de - - True - - - - 1 - 4 - - - - - Set background color - True - True - False - end - True - - - - 0 - 5 - - - - - True - True - True - start - Choose the background color for code blocks - True - - - - 1 - 5 - - + end + Default language for syntax highlighting + 0 - False - False - 0 - - - - - True - False - - - False - True - 1 + 0 + 0 True False - center - 6 - 6 - Test here how code blocks will look like in the chat window + end + Insert line breaks around code blocks 0 - - False - True - 2 + 0 + 1 + + + True + False + + + + + 0 + + + + + 1 + 0 + + + + + True + False + line_break_selection + + + + + 0 + + + + + 1 + 1 + + + + + True + False + + + + + 0 + + + + + 1 + 2 + + + + + True + False + end + Select syntax highlighting style + 0 + + + 0 + 2 + + + + + True + False + end + Select code marker (the backticks) formatting + 0 + + + 0 + 3 + + + + + True + False + code_marker_selection + + + + + 0 + + + + + 1 + 3 + + + + + True + False + end + Select font for code snippets + 0 + + + 0 + 4 + + + + + True + True + True + Sans 12 + + True + + + + 1 + 4 + + + + + Set background color + True + True + False + end + True + + + + 0 + 5 + + + + + True + True + True + start + Choose the background color for code blocks + True + + + + 1 + 5 + + + + + False + False + 0 + + + + + True + False + + + False + True + 1 + + + + + True + False + center + 6 + 6 + Test here how code blocks will look like in the chat window + 0 + + + + False + True + 2 + + + + + 200 + True + True + in True True word-char + 6 + 6 + 6 + 6 preview_textbuffer - - True - True - 3 - - - - - True - False - 20 - - - False - True - 4 - - - - + + True + True + 3 + + + + + True + False + 20 + + + False + True + 4 + diff --git a/syntax_highlight/gtkformatter.py b/syntax_highlight/gtkformatter.py index 75d6ce2..d7347f0 100644 --- a/syntax_highlight/gtkformatter.py +++ b/syntax_highlight/gtkformatter.py @@ -1,12 +1,13 @@ import logging -from gi.repository import Gtk as gtk +from gi.repository import Gtk from gi.repository import Pango from pygments.formatter import Formatter -from gajim.plugins.helpers import log + log = logging.getLogger('gajim.p.syntax_highlight') + class GTKFormatter(Formatter): name = 'GTK Formatter' aliases = ['textbuffer', 'gtk'] @@ -14,14 +15,14 @@ class GTKFormatter(Formatter): def __init__(self, **options): super(GTKFormatter, self).__init__(**options) - #Formatter.__init__(self, **options) + # Formatter.__init__(self, **options) self.tags = {} self.mark = options.get('start_mark', None) @staticmethod def create_tag_for_token(ttype, highlighting_style): style = highlighting_style.style_for_token(ttype) - tag = gtk.TextTag.new() + tag = Gtk.TextTag.new() if 'bgcolor' in style and not style['bgcolor'] is None: tag.set_property('background', '#%s' % style['bgcolor']) if 'bold' in style and style['bold']: @@ -44,13 +45,13 @@ class GTKFormatter(Formatter): tag.set_property('underline', 'single') return tag - def get_tag(self, ttype, buf): """ Creates, stores and returs a tag for a given token type. This method ensures that a tag style is created only once. - Furthermore, the tag will be added to the given Gtk.TextBuffer's tag table. + Furthermore, the tag will be added to the given Gtk.TextBuffer's + tag table. """ tag = None if ttype in self.tags: @@ -65,23 +66,23 @@ class GTKFormatter(Formatter): self.mark = mark def format(self, tokensource, outfile): - if not isinstance(outfile, gtk.TextBuffer) or outfile is None: + if not isinstance(outfile, Gtk.TextBuffer) or outfile is None: log.warn("Did not get a buffer to format...") return buf = outfile - end_iter = buf.get_end_iter() + end_iter = buf.get_end_iter() - start_mark = self.mark - start_iter = buf.get_iter_at_mark(start_mark) if not start_mark is None \ - else end_iter + start_mark = self.mark + start_iter = buf.get_iter_at_mark(start_mark) if \ + start_mark is not None else end_iter - last_ttype = None - last_start = start_iter - last_end = buf.get_end_iter() + last_ttype = None + last_start = start_iter + last_end = buf.get_end_iter() last_fixed_start = last_start - reset = True + reset = True for ttype, value in tokensource: search = None @@ -90,24 +91,26 @@ class GTKFormatter(Formatter): buf.apply_tag(tag, last_fixed_start, last_end) - search = last_end.forward_search(value, gtk.TextSearchFlags.TEXT_ONLY, end_iter) + search = last_end.forward_search( + value, Gtk.TextSearchFlags.TEXT_ONLY, end_iter) reset = True else: - # in case last_ttype is None, i.e. first loop walkthrough: + # In case last_ttype is None, i.e. first loop walkthrough: # last_start to end_iter is the full code block. - search = last_start.forward_search(value, gtk.TextSearchFlags.TEXT_ONLY, end_iter) + search = last_start.forward_search( + value, Gtk.TextSearchFlags.TEXT_ONLY, end_iter) # Prepare for next iteration last_ttype = ttype if search is not None: (last_start, last_end) = search - # If we've found the end of a sequence of similar type tokens or if - # we are in the first loop iteration, set the fixed point + # If we've found the end of a sequence of similar type tokens + # or if we are in the first loop iteration, set the fixed point if reset: last_fixed_start = last_start reset = False else: - # Hm... Nothing found, but tags left? Seams there's nothing we + # Hm... Nothing found, but tags left? Seems there's nothing we # can do now. break diff --git a/syntax_highlight/plugin_config.py b/syntax_highlight/plugin_config.py index 5c76692..ebed683 100644 --- a/syntax_highlight/plugin_config.py +++ b/syntax_highlight/plugin_config.py @@ -1,22 +1,30 @@ -from gajim.plugins.helpers import log +import logging from gi.repository import Gdk -from pygments.lexers import get_lexer_by_name, get_all_lexers +from pygments.lexers import get_lexer_by_name +from pygments.lexers import get_all_lexers from pygments.styles import get_all_styles +from pygments.util import ClassNotFound + +from syntax_highlight.types import LineBreakOptions +from syntax_highlight.types import CodeMarkerOptions +from syntax_highlight.types import PLUGIN_INTERNAL_NONE_LEXER_ID + +log = logging.getLogger('gajim.p.syntax_highlight') -from .types import LineBreakOptions, CodeMarkerOptions, \ - PLUGIN_INTERNAL_NONE_LEXER_ID class SyntaxHighlighterConfig: - PLUGIN_INTERNAL_NONE_LEXER=('None (monospace only)', PLUGIN_INTERNAL_NONE_LEXER_ID) + PLUGIN_INTERNAL_NONE_LEXER = ('None (monospace only)', + PLUGIN_INTERNAL_NONE_LEXER_ID) def _create_lexer_list(self): # The list we create here contains the plain text name and the lexer's # id string lexers = [] - # Iteration over get_all_lexers() seems to be broken somehow. Workarround + # Iteration over get_all_lexers() seems to be broken somehow + # Workaround all_lexers = get_all_lexers() for lexer in all_lexers: # We don't want to add lexers that we cant identify by name later @@ -24,7 +32,7 @@ class SyntaxHighlighterConfig: lexers.append((lexer[0], lexer[1][0])) lexers.sort() - # Insert our internal "none" type at top of the list. + # Insert our internal 'none' type at top of the list lexers.insert(0, self.PLUGIN_INTERNAL_NONE_LEXER) return lexers @@ -38,24 +46,24 @@ class SyntaxHighlighterConfig: lexer = None try: lexer = get_lexer_by_name(name) - except: + except ClassNotFound: pass return lexer def get_lexer_with_fallback(self, language): lexer = self.get_lexer_by_name(language) if lexer is None: - log.info("Falling back to default lexer for %s.", - self.get_default_lexer_name()) + log.info('Falling back to default lexer for %s.', + self.get_default_lexer_name()) lexer = self.default_lexer[1] return lexer def set_font(self, font): - if font is not None and font != "": + if font is not None and font != '': self.config['font'] = font def set_style(self, style): - if style is not None and style != "": + if style is not None and style != '': self.config['style'] = style def set_line_break_action(self, option): @@ -68,14 +76,16 @@ class SyntaxHighlighterConfig: lexer = get_lexer_by_name(name) if lexer is None and self.default_lexer is None: - log.error("Failed to get default lexer by name."\ - "Falling back to simply using the first in the list.") + log.error('Failed to get default lexer by name.' + 'Falling back to simply using the first lexer ' + 'in the list.') lexer = self.lexer_list[0] - name = lexer[0] + name = lexer[0] self.default_lexer = (name, lexer) if lexer is None and self.default_lexer is not None: - log.info("Failed to get default lexer by name, keeping previous"\ - "setting (lexer = %s).", self.default_lexer[0]) + log.info('Failed to get default lexer by name, keeping ' + 'previous setting (lexer = %s).', + self.default_lexer[0]) name = self.default_lexer[0] else: self.default_lexer = (name, lexer) @@ -88,7 +98,7 @@ class SyntaxHighlighterConfig: self.config['bgcolor_override'] = state def set_bgcolor(self, color): - if isinstance(color, Gdk.Color): + if isinstance(color, Gdk.RGBA): color = color.to_string() self.config['bgcolor'] = color @@ -110,9 +120,9 @@ class SyntaxHighlighterConfig: return self.lexer_list def get_line_break_action(self): - # return int only + # Return int only if isinstance(self.config['line_break'], int): - # in case of legacy settings, convert. + # In case of legacy settings, convert. action = self.config['line_break'] self.set_line_break_action(action) else: @@ -146,13 +156,13 @@ class SyntaxHighlighterConfig: Initialize all config variables that depend directly on pygments being available. """ - self.lexer_list = self._create_lexer_list() - self.style_list = [s for s in get_all_styles()] + self.lexer_list = self._create_lexer_list() + self.style_list = [s for s in get_all_styles()] self.style_list.sort() self.set_default_lexer(self.config['default_lexer']) def __init__(self, config): - self.lexer_list = [] - self.style_list = [] - self.config = config - self.default_lexer = None + self.lexer_list = [] + self.style_list = [] + self.config = config + self.default_lexer = None diff --git a/syntax_highlight/plugin_config_dialog.py b/syntax_highlight/plugin_config_dialog.py index cc257c2..c33e2b1 100644 --- a/syntax_highlight/plugin_config_dialog.py +++ b/syntax_highlight/plugin_config_dialog.py @@ -1,63 +1,47 @@ import re import pygments -from gi.repository import Gtk, Gdk +from gi.repository import Gtk +from gi.repository import Gdk from gi.repository.Pango import FontDescription - from gajim.plugins.gui import GajimPluginConfigDialog -from gajim.plugins.helpers import log_calls +from gajim.plugins.helpers import get_builder +from syntax_highlight.gtkformatter import GTKFormatter +from syntax_highlight.types import LineBreakOptions +from syntax_highlight.types import CodeMarkerOptions -from .gtkformatter import GTKFormatter -from .types import LineBreakOptions, CodeMarkerOptions class SyntaxHighlighterPluginConfiguration(GajimPluginConfigDialog): - @log_calls('SyntaxHighlighterPluginConfiguration') def init(self): - self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path( - 'config_dialog.ui') - self.xml = Gtk.Builder() - self.xml.set_translation_domain('gajim_plugins') - self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH, - ['mainBox', 'line_break_selection', 'code_marker_selection', - 'preview_textbuffer']) - box = self.xml.get_object('mainBox') - self.get_child().pack_start(box, False, False, 0) - self.result_label = self.xml.get_object('result_label') + path = self.plugin.local_file_path('config_dialog.ui') + self._ui = get_builder(path) + box = self.get_content_area() + box.pack_start(self._ui.main_box, True, True, 0) + + self._ui.set_translation_domain('gajim_plugins') self.liststore = Gtk.ListStore(str) - - self.default_lexer_combobox = self.xml.get_object('default_lexer_combobox') - self.default_lexer_combobox.set_property("model", self.liststore) + self._ui.default_lexer_combobox.set_model(self.liststore) self.style_liststore = Gtk.ListStore(str) - self.style_combobox = self.xml.get_object('style_combobox') - self.style_combobox.set_property("model", self.style_liststore) + self._ui.style_combobox.set_model(self.style_liststore) - self.bg_color_checkbox = self.xml.get_object('bg_color_checkbutton') - self.bg_color_colorbutton = self.xml.get_object('bg_color_colorbutton') + self._ui.preview_textview.get_buffer().connect( + 'insert-text', self._on_preview_text_inserted) - self.line_break_combobox = self.xml.get_object('line_break_combobox') + self._ui.connect_signals(self) - self.code_marker_combobox = self.xml.get_object('code_marker_combobox') - - self.preview_textview = self.xml.get_object('preview_textview') - self.preview_textview.get_buffer().connect("insert-text", self.on_preview_text_inserted) - self.preview_textview.set_size_request(-1, 130) - - self.font_button = self.xml.get_object('font_button') - - self.xml.connect_signals(self) - self.default_lexer_id = 0 - self.style_id = 0 + self.default_lexer_id = 0 + self.style_id = 0 def set_config(self, config): - self.config = config - self.lexers = self.config.get_lexer_list() - self.styles = self.config.get_styles_list() - default_lexer = self.config.get_default_lexer_name() - default_style = self.config.get_style_name() + self.config = config + self.lexers = self.config.get_lexer_list() + self.styles = self.config.get_styles_list() + default_lexer = self.config.get_default_lexer_name() + default_style = self.config.get_style_name() for i, lexer in enumerate(self.lexers): self.liststore.append([lexer[0]]) @@ -68,102 +52,100 @@ class SyntaxHighlighterPluginConfiguration(GajimPluginConfigDialog): self.style_liststore.append([style]) if style == default_style: self.style_id = i - self.update_preview() + self._update_preview() - def lexer_changed(self, _widget): - new = self.default_lexer_combobox.get_active() + def _lexer_changed(self, _widget): + new = self._ui.default_lexer_combobox.get_active() if new != self.default_lexer_id: self.default_lexer_id = new self.config.set_default_lexer(self.lexers[self.default_lexer_id][1]) - self.update_preview() + self._update_preview() - def line_break_changed(self, _widget): - new = LineBreakOptions(self.line_break_combobox.get_active()) + def _line_break_changed(self, _widget): + new = LineBreakOptions(self._ui.line_break_combobox.get_active()) if new != self.config.get_line_break_action(): self.config.set_line_break_action(new) - self.update_preview() + self._update_preview() - def code_marker_changed(self, _widget): - new = CodeMarkerOptions(self.code_marker_combobox.get_active()) + def _code_marker_changed(self, _widget): + new = CodeMarkerOptions(self._ui.code_marker_combobox.get_active()) if new != self.config.get_code_marker_setting(): self.config.set_code_marker_setting(new) - def bg_color_enabled(self, _widget): - new = self.bg_color_checkbox.get_active() + def _bg_color_enabled(self, _widget): + new = self._ui.bg_color_checkbutton.get_active() if new != self.config.is_bgcolor_override_enabled(): bg_override_enabled = new self.config.set_bgcolor_override_enabled(bg_override_enabled) - self.bg_color_colorbutton.set_sensitive(bg_override_enabled) - self.update_preview() + self._ui.bg_color_colorbutton.set_sensitive(bg_override_enabled) + self._update_preview() - def bg_color_changed(self, _widget): - new = self.bg_color_colorbutton.get_color() + def _bg_color_changed(self, _widget): + new = self._ui.bg_color_colorbutton.get_rgba() if new != self.config.get_bgcolor(): self.config.set_bgcolor(new) - self.update_preview() + self._update_preview() - def style_changed(self, _widget): - new = self.style_combobox.get_active() + def _style_changed(self, _widget): + new = self._ui.style_combobox.get_active() if new != self.style_id: self.style_id = new self.config.set_style(self.styles[self.style_id]) - self.update_preview() + self._update_preview() - def font_changed(self, _widget): - new = self.font_button.get_font() + def _font_changed(self, _widget): + new = self._ui.font_button.get_font() if new != self.config.get_font(): self.config.set_font(new) - self.update_preview() + self._update_preview() - def update_preview(self): - self.format_preview_text() + def _update_preview(self): + self._format_preview_text() - def on_preview_text_inserted(self, _buf, _iterator, text, length, *_args): + def _on_preview_text_inserted(self, _buf, _iterator, text, length, *_args): if (length == 1 and re.match(r'\s', text)) or length > 1: - self.format_preview_text() + self._format_preview_text() - def format_preview_text(self): - buf = self.preview_textview.get_buffer() + def _format_preview_text(self): + buf = self._ui.preview_textview.get_buffer() start_iter = buf.get_start_iter() start_mark = buf.create_mark(None, start_iter, True) buf.remove_all_tags(start_iter, buf.get_end_iter()) formatter = GTKFormatter( - style=self.config.get_style_name(), - start_mark=start_mark) + style=self.config.get_style_name(), start_mark=start_mark) - code = start_iter.get_text(buf.get_end_iter()) - lexer = self.config.get_default_lexer() + code = start_iter.get_text(buf.get_end_iter()) + lexer = self.config.get_default_lexer() if not self.config.is_internal_none_lexer(lexer): - tokens = pygments.lex(code, lexer) - + tokens = pygments.lex(code, lexer) pygments.format(tokens, formatter, buf) buf.delete_mark(start_mark) - self.preview_textview.override_font( - FontDescription.from_string(self.config.get_font())) + self._ui.preview_textview.override_font( + FontDescription.from_string(self.config.get_font())) color = Gdk.RGBA() if color.parse(self.config.get_bgcolor()): - self.preview_textview.override_background_color( - Gtk.StateFlags.NORMAL, color) + self._ui.preview_textview.override_background_color( + Gtk.StateFlags.NORMAL, color) def on_run(self): - self.default_lexer_combobox.set_active(self.default_lexer_id) - self.line_break_combobox.set_active(self.config.get_line_break_action()) - self.code_marker_combobox.set_active(self.config.get_code_marker_setting()) - self.style_combobox.set_active(self.style_id) + self._ui.default_lexer_combobox.set_active(self.default_lexer_id) + self._ui.line_break_combobox.set_active( + self.config.get_line_break_action()) + self._ui.code_marker_combobox.set_active( + self.config.get_code_marker_setting()) + self._ui.style_combobox.set_active(self.style_id) - self.font_button.set_font(self.config.get_font()) + self._ui.font_button.set_font(self.config.get_font()) bg_override_enabled = self.config.is_bgcolor_override_enabled() - self.bg_color_checkbox.set_active(bg_override_enabled) - - self.bg_color_colorbutton.set_sensitive(bg_override_enabled) - - parsed, color = Gdk.Color.parse(self.config.get_bgcolor()) - if parsed: - self.bg_color_colorbutton.set_color(color) + self._ui.bg_color_checkbutton.set_active(bg_override_enabled) + self._ui.bg_color_colorbutton.set_sensitive(bg_override_enabled) + color = Gdk.RGBA() + if color.parse(self.config.get_bgcolor()): + self._ui.bg_color_colorbutton.set_rgba(color) diff --git a/syntax_highlight/syntax_highlight.py b/syntax_highlight/syntax_highlight.py index fcbb7be..c041d02 100644 --- a/syntax_highlight/syntax_highlight.py +++ b/syntax_highlight/syntax_highlight.py @@ -1,29 +1,33 @@ import logging import sys +from gajim.plugins import GajimPlugin + +from syntax_highlight.types import LineBreakOptions +from syntax_highlight.types import CodeMarkerOptions +from syntax_highlight.types import PLUGIN_INTERNAL_NONE_LEXER_ID if sys.version_info >= (3, 4): from importlib.util import find_spec as find_module else: from importlib import find_loader as find_module - -from gajim.plugins.helpers import log_calls, log -from gajim.plugins import GajimPlugin - -from .types import MatchType, LineBreakOptions, CodeMarkerOptions, \ - PLUGIN_INTERNAL_NONE_LEXER_ID +PYGMENTS_MISSING = 'You are missing Python-Pygments.' log = logging.getLogger('gajim.p.syntax_highlight') + def try_loading_pygments(): success = find_module('pygments') is not None if success: try: - from .chat_syntax_highlighter import ChatSyntaxHighlighter - from .plugin_config_dialog import SyntaxHighlighterPluginConfiguration - from .plugin_config import SyntaxHighlighterConfig - global SyntaxHighlighterPluginConfiguration, ChatSyntaxHighlighter, \ - SyntaxHighlighterConfig + from syntax_highlight.chat_syntax_highlighter import \ + ChatSyntaxHighlighter + from syntax_highlight.plugin_config_dialog import \ + SyntaxHighlighterPluginConfiguration + from syntax_highlight.plugin_config import SyntaxHighlighterConfig + global SyntaxHighlighterPluginConfiguration + global ChatSyntaxHighlighter + global SyntaxHighlighterConfig success = True log.debug("pygments loaded.") except Exception as exception: @@ -32,27 +36,21 @@ def try_loading_pygments(): return success -PYGMENTS_MISSING = 'You are missing Python-Pygments.' - - class SyntaxHighlighterPlugin(GajimPlugin): - @log_calls('SyntaxHighlighterPlugin') def on_connect_with_chat_control(self, chat_control): account = chat_control.contact.account.name - jid = chat_control.contact.jid + jid = chat_control.contact.jid if account not in self.ccontrol: self.ccontrol[account] = {} self.ccontrol[account][jid] = ChatSyntaxHighlighter( - self.conf, chat_control.conv_textview) + self.conf, chat_control.conv_textview) - @log_calls('SyntaxHighlighterPlugin') def on_disconnect_from_chat_control(self, chat_control): account = chat_control.contact.account.name jid = chat_control.contact.jid del self.ccontrol[account][jid] - @log_calls('SyntaxHighlighterPlugin') def on_print_real_text(self, text_view, real_text, other_tags, graphics, iterator, additional): account = text_view.account @@ -78,36 +76,32 @@ class SyntaxHighlighterPlugin(GajimPlugin): self.available_text = None self.config_dialog = SyntaxHighlighterPluginConfiguration(self) - self.conf = SyntaxHighlighterConfig(self.config) + self.conf = SyntaxHighlighterConfig(self.config) # The following initialization requires pygments to be available. self.conf.init_pygments() - self.config_dialog = SyntaxHighlighterPluginConfiguration(self) + self.config_dialog = SyntaxHighlighterPluginConfiguration(self) self.config_dialog.set_config(self.conf) self.gui_extension_points = { - 'chat_control_base': ( - self.on_connect_with_chat_control, - self.on_disconnect_from_chat_control - ), - 'print_real_text': (self.on_print_real_text, None), - } + 'chat_control_base': ( + self.on_connect_with_chat_control, + self.on_disconnect_from_chat_control), + 'print_real_text': (self.on_print_real_text, None), } return True - @log_calls('SyntaxHighlighterPlugin') def init(self): - self.ccontrol = {} + self.ccontrol = {} self.config_default_values = { - 'default_lexer' : (PLUGIN_INTERNAL_NONE_LEXER_ID, ''), - 'line_break' : (LineBreakOptions.MULTILINE, ''), - 'style' : ('default', ''), - 'font' : ('Monospace 10', ''), - 'bgcolor' : ('#ccc', ''), - 'bgcolor_override' : (True, ''), - 'code_marker' : (CodeMarkerOptions.AS_COMMENT, ''), - 'pygments_path' : (None, ''), - } + 'default_lexer': (PLUGIN_INTERNAL_NONE_LEXER_ID, ''), + 'line_break': (LineBreakOptions.MULTILINE, ''), + 'style': ('default', ''), + 'font': ('Monospace 10', ''), + 'bgcolor': ('#ccc', ''), + 'bgcolor_override': (True, ''), + 'code_marker': (CodeMarkerOptions.AS_COMMENT, ''), + 'pygments_path': (None, ''), } is_initialized = self.try_init() diff --git a/syntax_highlight/types.py b/syntax_highlight/types.py index 8559e1a..bec9fbf 100644 --- a/syntax_highlight/types.py +++ b/syntax_highlight/types.py @@ -1,21 +1,24 @@ -from enum import Enum, IntEnum, unique +from enum import Enum +from enum import IntEnum +from enum import unique + +PLUGIN_INTERNAL_NONE_LEXER_ID = '_syntax_highlight_internal_none_type' -PLUGIN_INTERNAL_NONE_LEXER_ID='_syntax_highlight_internal_none_type' class MatchType(Enum): - INLINE = 0 - MULTILINE = 1 - TEXT = 2 + INLINE = 0 + MULTILINE = 1 + TEXT = 2 + @unique class LineBreakOptions(IntEnum): - NEVER = 0 - ALWAYS = 1 - MULTILINE = 2 + NEVER = 0 + ALWAYS = 1 + MULTILINE = 2 + @unique class CodeMarkerOptions(IntEnum): - AS_COMMENT = 0 - HIDE = 1 - - + AS_COMMENT = 0 + HIDE = 1