<commit_before>import errno
import json
import os
import random
import sublime
import sublime_plugin
import sys
import urllib
from threading import Thread

global xkcd_open
xkcd_open = []

if sys.version_info < (3, 3):
    raise RuntimeError('Xkcd works with Sublime Text 3 only')


def plugin_loaded():
    """Called directly from sublime on plugin load."""
    try:
        os.makedirs(sublime.cache_path() + os.path.sep + 'Xkcd')
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise IOError('Error encountered during file creation.')


def plugin_unloaded():
    """Called directly from sublime on plugin unload."""
    clean_cache()


def clean_cache():
    """Delete cache"""
    for fl in os.listdir(sublime.cache_path() + os.path.sep + 'Xkcd'):
        try:
            os.remove(sublime.cache_path() + os.path.sep + 'Xkcd' + os.path.sep + fl)
        except OSError as e:
            raise IOError('Could not remove previous files.')


def xJson(id=None):
    """Get JSON object from XKCD API."""
    if id is None:
        url = 'http://xkcd.com/info.0.json'
    else:
        url = 'http://xkcd.com/' + str(id) + '/info.0.json'

    try:
        request = urllib.request.Request(url, headers={"User-Agent":
                                                       "Sublime Xkcd"})
        opener = urllib.request.build_opener()
        f = opener.open(request)
        result = json.loads(f.read().decode("utf-8"))

        return result

    except urllib.error.HTTPError as e:
        err = '%s: HTTP error %s contacting API' % (__name__, str(e.code))
    except urllib.error.URLError as e:
        err = '%s: URL error %s contacting API' % (__name__, str(e.reason))


class EventDump(sublime_plugin.EventListener):

    """Event listener for automatic closing of meta-pane on image close."""

    global xkcd_open

    def on_activated(self, view):
        """View activated."""
        if xkcd_open:
            try:
                xkcd_open.pop()
            except Exception as e:
                print(str(e))
            if view.file_name() != None:
                view.window().run_command(
                    "hide_panel", {"panel": "output.xkcd_meta"})


    def on_close(self, view):
        """View closed."""
        clean_cache()


class XkcdGetComicCommand(sublime_plugin.WindowCommand):

    """Grab comic."""

    def run(self, kind):
        """Main function, runs on activation."""
        # Grab comic via async background process
        if kind == 'latest':
            thread = Thread(target=self.getComic)
        elif kind == 'random':
            thread = Thread(target=self.getRandomComic)
        elif kind == 'list':
            thread = Thread(target=self.getList)
        thread.start()

    def getComic(self, id=None):
        """Background loop."""
        result = xJson(id)

        self.title = result['title']
        self.img = result['img']
        self.alt = result['alt']
        self.num = result['num']

        try:
            local_img = sublime.cache_path() + os.path.sep + 'Xkcd' + \
                os.path.sep + self.img.split('/')[-1]
            urllib.request.urlretrieve(self.img, local_img)

        except urllib.error.HTTPError as e:
            err = '%s: HTTP error %s contacting API' % (__name__, str(e.code))
        except urllib.error.URLError as e:
            err = '%s: URL error %s contacting API' % (__name__, str(e.reason))

        self.output = '[' + str(self.num) + '] ' + \
            self.title + '\n\n' + self.alt

        # sublime.error_message(err)

        panel = self.window.create_output_panel('xkcd_meta')
        panel.run_command('erase_view')
        self.window.run_command(
            "show_panel", {"panel": "output.xkcd_meta"})
        self.window.get_output_panel('xkcd_meta').run_command(
            'append', {'characters': self.output})
        panel.settings().set("word_wrap", True)
        # print(int(self.window.active_view().viewport_extent()[0]-self.window.active_view().layout_extent()[0]))

        self.window.open_file(local_img, sublime.TRANSIENT)

        global xkcd_open
        xkcd_open.append(self.num)

        # HANDLE NAVIGATION (first/previous/next/last) HERE...

    def getRandomComic(self):
        """Background loop."""
        latest = xJson()
        self.getComic(random.randrange(latest['num']))

    def getList(self):
        """Background loop."""
        url = 'http://xkcd.com/archive/'
        xml_str = str(urllib.request.urlopen(url).read()).split(
            '(Hover mouse over title to view publication date)<br /><br />',
            1)[-1].split(
            '</div>\\n<div id="bottom" class="box">', 1)[0].strip()
        clean_xml_str = xml_str.split('<br/>')<commit_msg>Clarify error messages, show via sublime popup instead of in console.<commit_after>import errno
import json
import os
import random
import sublime
import sublime_plugin
import sys
import urllib
from threading import Thread

global xkcd_open
xkcd_open = []

if sys.version_info < (3, 3):
    raise RuntimeError('Xkcd works with Sublime Text 3 only')


def plugin_loaded():
    """Called directly from sublime on plugin load."""
    try:
        os.makedirs(sublime.cache_path() + os.path.sep + 'Xkcd')
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise IOError('Error encountered during file creation.')


def plugin_unloaded():
    """Called directly from sublime on plugin unload."""
    clean_cache()


def clean_cache():
    """Delete cache"""
    for fl in os.listdir(sublime.cache_path() + os.path.sep + 'Xkcd'):
        try:
            os.remove(sublime.cache_path() + os.path.sep + 'Xkcd' + os.path.sep + fl)
        except OSError as e:
            raise IOError('Could not remove previous files.')


def xJson(id=None):
    """Get JSON object from XKCD API."""
    if id is None:
        url = 'http://xkcd.com/info.0.json'
    else:
        url = 'http://xkcd.com/' + str(id) + '/info.0.json'

    try:
        request = urllib.request.Request(url, headers={"User-Agent":
                                                       "Sublime Xkcd"})
        opener = urllib.request.build_opener()
        f = opener.open(request)
        result = json.loads(f.read().decode("utf-8"))

        return result

    except urllib.error.HTTPError as e:
        sublime.error_message('Xkcd: %s: HTTP error %s contacting API' % (__name__, str(e.code)))
    except urllib.error.URLError as e:
        sublime.error_message('Xkcd: %s: URL error %s contacting API' % (__name__, str(e.reason)))


class EventDump(sublime_plugin.EventListener):

    """Event listener for automatic closing of meta-pane on image close."""

    global xkcd_open

    def on_activated(self, view):
        """View activated."""
        if xkcd_open:
            try:
                xkcd_open.pop()
            except Exception as e:
                print(str(e))
            if view.file_name() != None:
                view.window().run_command(
                    "hide_panel", {"panel": "output.xkcd_meta"})


    def on_close(self, view):
        """View closed."""
        clean_cache()


class XkcdGetComicCommand(sublime_plugin.WindowCommand):

    """Grab comic."""

    def run(self, kind):
        """Main function, runs on activation."""
        # Grab comic via async background process
        if kind == 'latest':
            thread = Thread(target=self.getComic)
        elif kind == 'random':
            thread = Thread(target=self.getRandomComic)
        elif kind == 'list':
            thread = Thread(target=self.getList)
        thread.start()

    def getComic(self, id=None):
        """Background loop."""
        result = xJson(id)

        if result is not None:
            self.title = result['title']
            self.img = result['img']
            self.alt = result['alt']
            self.num = result['num']

            try:
                local_img = sublime.cache_path() + os.path.sep + 'Xkcd' + \
                    os.path.sep + self.img.split('/')[-1]
                urllib.request.urlretrieve(self.img, local_img)

            except urllib.error.HTTPError as e:
                sublime.error_message('Xkcd: %s: HTTP error %s retrieving image' % (__name__, str(e.code)))
            except urllib.error.URLError as e:
                sublime.error_message('Xkcd: %s: URL error %s retrieving image' % (__name__, str(e.reason)))

            self.output = '[' + str(self.num) + '] ' + \
                self.title + '\n\n' + self.alt

            panel = self.window.create_output_panel('xkcd_meta')
            panel.run_command('erase_view')
            self.window.run_command(
                "show_panel", {"panel": "output.xkcd_meta"})
            self.window.get_output_panel('xkcd_meta').run_command(
                'append', {'characters': self.output})
            panel.settings().set("word_wrap", True)
            # print(int(self.window.active_view().viewport_extent()[0]-self.window.active_view().layout_extent()[0]))

            self.window.open_file(local_img, sublime.TRANSIENT)

            global xkcd_open
            xkcd_open.append(self.num)

            # HANDLE NAVIGATION (first/previous/next/last) HERE...
        else:
            sublime.error_message('Xkcd: Error reading API response')

    def getRandomComic(self):
        """Background loop."""
        latest = xJson()
        self.getComic(random.randrange(latest['num']))

    def getList(self):
        """Background loop."""
        url = 'http://xkcd.com/archive/'
        try:
            xml_str = str(urllib.request.urlopen(url).read()).split(
                '(Hover mouse over title to view publication date)<br /><br />',
                1)[-1].split(
                '</div>\\n<div id="bottom" class="box">', 1)[0].strip()
        except urllib.error.URLError as e:
            print ('Xkcd: %s: URL error %s reading list' % (__name__, str(e.reason)))
        clean_xml_str = xml_str.split('<br/>')
{'fraction_non_alphanumeric': 0.13814144243272983, 'fraction_numerical': 0.002600780234070221, 'mean_word_length': 2.193229000319387, 'pattern_counts': {'":': 6, '<': 15, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1228001', 'n_tokens_mistral': 3187, 'n_tokens_neox': 3064, 'n_words': 716}