<commit_before># -*- coding: utf-8 -*-

import re

from module.network.HTTPRequest import BadHeader
from module.network.RequestFactory import getURL as get_url
from module.plugins.internal.Crypter import Crypter
from module.plugins.internal.misc import parse_name, replace_patterns

class SimpleCrypter(Crypter):
    __name__    = "SimpleCrypter"
    __type__    = "crypter"
    __version__ = "0.83"
    __status__  = "testing"

    __pattern__ = r'^unmatchable$'
    __config__  = [("activated"         , "bool"          , "Activated"                                        , True     ),
                   ("use_premium"       , "bool"          , "Use premium account if available"                 , True     ),
                   ("folder_per_package", "Default;Yes;No", "Create folder for each package"                   , "Default"),
                   ("max_wait"          , "int"           , "Reconnect if waiting time is greater than minutes", 10       )]

    __description__ = """Simple decrypter plugin"""
    __license__     = "GPLv3"
    __authors__     = [("Walter Purcaro", "vuolter@gmail.com")]

    """
    Following patterns should be defined by each crypter:

      LINK_PATTERN: Download link or regex to catch links in group(1)
        example: LINK_PATTERN = r'
<a href="(.+?)"'

      NAME_PATTERN: (optional) folder name or page title
        example: NAME_PATTERN = r'<title>Files of: (?P<N>[^<]+) folder</title>'

      OFFLINE_PATTERN: (optional) Checks if the page is unreachable
        example: OFFLINE_PATTERN = r'File (deleted|not found)'

      TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable
        example: TEMP_OFFLINE_PATTERN = r'Server maintainance'

    You can override the get_links method if you need a more sophisticated way to extract the links.

    If the links are splitted on multiple pages you can define the PAGES_PATTERN regex:

      PAGES_PATTERN: (optional) group(1) should be the number of overall pages containing the links
        example: PAGES_PATTERN = r'Pages: (\d+)'

    and its load_page method:

      def load_page(self, page_n):
          return the html of the page number page_n
    """

    NAME_REPLACEMENTS    = []
    URL_REPLACEMENTS     = []

    COOKIES              = True   #: or False or list of tuples [(domain, name, value)]
    DIRECT_LINK          = True   #: Set to True to looking for direct link (as defined in handle_direct method), set to None to do it if self.account is True else False
    LOGIN_ACCOUNT        = False  #: Set to True to require account login
    LOGIN_PREMIUM        = False  #: Set to True to require premium account login
    TEXT_ENCODING        = True   #: Set to encoding name if encoding value in http header is not correct

    LINK_PATTERN         = None
    LINK_FREE_PATTERN    = None
    LINK_PREMIUM_PATTERN = None
    PAGES_PATTERN        = None

    NAME_PATTERN         = None
    OFFLINE_PATTERN      = r'[^\w](404\s|[Ii]nvalid|[Oo]ffline|[Dd]elet|[Rr]emov|([Nn]o(t|thing)?|sn\'t) (found|(longer )?(available|exist)))'
    TEMP_OFFLINE_PATTERN = r'[^\w](503\s|[Mm]aint(e|ai)nance|[Tt]emp([.-]|orarily)|[Mm]irror)'

    WAIT_PATTERN         = None
    PREMIUM_ONLY_PATTERN = None
    IP_BLOCKED_PATTERN   = None
    SIZE_LIMIT_PATTERN   = None
    ERROR_PATTERN        = None

    @classmethod
    def api_info(cls, url):
        return {}

    @classmethod
    def get_info(cls, url="", html=""):
        info = super(SimpleCrypter, cls).get_info(url)

        info.update(cls.api_info(url))

        if not html and info['status'] != 2:
            if not url:
                info['error']  = "missing url"
                info['status'] = 1

            elif info['status'] == 3:
                try:
                    html = get_url(url, cookies=cls.COOKIES, decode=cls.TEXT_ENCODING)

                except BadHeader, e:
                    info['error'] = "%d: %s" % (e.code, e.content)

                except Exception:
                    pass

        if html:
            if cls.OFFLINE_PATTERN and re.search(cls.OFFLINE_PATTERN, html) is not None:
                info['status'] = 1

            elif cls.TEMP_OFFLINE_PATTERN and re.search(cls.TEMP_OFFLINE_PATTERN, html) is not None:
                info['status'] = 6

            elif cls.NAME_PATTERN:
                m = re.search(cls.NAME_PATTERN, html)
                if m is not None:
                    info['status'] = 2
                    info['pattern'].update(m.groupdict())

        if 'N' in info['pattern']:
            name = replace_patterns(info['pattern']['N'], cls.NAME_REPLACEMENTS)
            info['name'] = parse_name(name)

        return info

    #@TODO: Remove in 0.4.10
    def setup_base(self):
        account_name = self.classname.rsplit("Folder", 1)[0]

        if self.account:
            self.req     = self.pyload.requestFactory.getRequest(account_name, self.account.user)
            self.premium = self.account.info['data']['premium']  #@NOTE: Don't call get_info here to reduce overhead
        else:
            self.req     = self.pyload.requestFactory.getRequest(account_name)
            self.premium = False

        super(SimpleCrypter, self).setup_base()

    #@TODO: Remove in 0.4.10
    def load_account(self):
        class_name = self.classname
        self.__class__.__name__ = class_name.rsplit("Folder", 1)[0]
        super(SimpleCrypter, self).load_account()
        self.__class__.__name__ = class_name

    def handle_direct(self, pyfile):
        maxredirs = int(self.pyload.api.getConfigValue("UserAgentSwitcher", "maxredirs", "plugin")) or 5  #@TODO: Remove `int` in 0.4.10
        redirect  = pyfile.url

        for i in xrange(maxredirs):
            self.log_debug("Redirect #%d to: %s" % (i, redirect))

            html = self.load(redirect)
            location = self.last_header.get('location')

            if location:
                redirect = location
            else:
                self.data = html
                self.links.extend(self.get_links())
                return
        else:
            self.log_warning(_("Too many redirects"))

    def preload(self):
        if self.data:
            return

        self.data = self.load(self.pyfile.url,
                              cookies=self.COOKIES,
                              ref=False,
                              decode=self.TEXT_ENCODING)

    def prepare(self):
        self.direct_dl = False

        if self.LOGIN_PREMIUM and not self.premium:
            self.fail(_("Required premium account not found"))

        if self.LOGIN_ACCOUNT and not self.account:
            self.fail(_("Required account not found"))

        self.req.setOption("timeout", 120)

        if self.LINK_PATTERN:
            if self.LINK_FREE_PATTERN is None:
                self.LINK_FREE_PATTERN = self.LINK_PATTERN

            if self.LINK_PREMIUM_PATTERN is None:
                self.LINK_PREMIUM_PATTERN = self.LINK_PATTERN

        if self.DIRECT_LINK is None:
            self.direct_dl = bool(self.account)
        else:
            self.direct_dl = self.DIRECT_LINK

        self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS)

    def decrypt(self, pyfile):
        self.prepare()

        if self.direct_dl:
            self.log_info(_("Looking for direct link..."))
            self.handle_direct(pyfile)

            if self.links or self.packages:
                self.log_info(_("Direct link detected"))
            else:
                self.log_info(_("Direct link not found"))

        if not self.links and not self.packages:
            self.preload()
            self.check_errors()

            self.links.extend(self.get_links())

            if self.PAGES_PATTERN:
                self.handle_pages(pyfile)

    def handle_free(self, pyfile):
        if not self.LINK_FREE_PATTERN:
            self.log_warning(_("Free decrypting not implemented"))

        links = re.findall(self.LINK_FREE_PATTERN, self.data)
        if not links:
            self.error(_("Free decrypted link not found"))
        else:
            self.links.extend(links)

    def handle_premium(self, pyfile):
        if not self.LINK_PREMIUM_PATTERN:
            self.log_warning(_("Premium decrypting not implemented"))
            self.restart(premium=False)

        links = re.findall(self.LINK_PREMIUM_PATTERN, self.data)
        if not links:
            self.error(_("Premium decrypted link found"))
        else:
            self.links.extend(links)

    def get_links(self):
        """
        Returns the links extracted from self.data
        You should override this only if it's impossible to extract links using only the LINK_PATTERN.
        """
        if self.premium:
            self.log_info(_("Decrypting as premium link..."))
            self.handle_premium(self.pyfile)

        elif not self.LOGIN_ACCOUNT:
            self.log_info(_("Decrypting as free link..."))
            self.handle_free(self.pyfile)

        return self.links

    def load_page(self, number):
        raise NotImplementedError

    def handle_pages(self, pyfile):
        try:
            pages = int(re.search(self.PAGES_PATTERN, self.data).group(1))

        except Exception:
            pages = 1

        for p in xrange(2, pages + 1):
            self.data = self.load_page(p)
            self.links.extend(self.get_links())

    def check_errors(self):
        self.log_info(_("Checking for link errors..."))

        if not self.data:
            self.log_warning(_("No data to check"))
            return

        if self.IP_BLOCKED_PATTERN and re.search(self.IP_BLOCKED_PATTERN, self.data):
            self.fail(_("Connection from your current IP address is not allowed"))

        elif not self.premium:
            if self.PREMIUM_ONLY_PATTERN and re.search(self.PREMIUM_ONLY_PATTERN, self.data):
                self.fail(_("Link can be decrypted by premium users only"))

            elif self.SIZE_LIMIT_PATTERN and re.search(self.SIZE_LIMIT_PATTERN, self.data):
                self.fail(_("Link list too large for free decrypt"))

        if self.ERROR_PATTERN:
            m = re.search(self.ERROR_PATTERN, self.data)
            if m is not None:
                try:
                    errmsg = m.group(1)

                except (AttributeError, IndexError):
                    errmsg = m.group(0)

                finally:
                    errmsg = re.sub(r'<.*?>', " ", errmsg.strip())

                self.info['error'] = errmsg
                self.log_warning(errmsg)

                if re.search(self.TEMP_OFFLINE_PATTERN, errmsg):
                    self.temp_offline()

                elif re.search(self.OFFLINE_PATTERN, errmsg):
                    self.offline()

                elif re.search(r'limit|wait|slot', errmsg, re.I):
                    wait_time = parse_time(errmsg)
                    self.wait(wait_time, reconnect=wait_time > self.config.get("max_wait", 10) * 60)
                    self.restart(_("Download limit exceeded"))

                elif re.search(r'country|ip|region|nation', errmsg, re.I):
                    self.fail(_("Connection from your current IP address is not allowed"))

                elif re.search(r'captcha|code', errmsg, re.I):
                    self.retry_captcha()

                elif re.search(r'countdown|expired', errmsg, re.I):
                    self.retry(10, 60, _("Link expired"))

                elif re.search(r'503|maint(e|ai)nance|temp|mirror', errmsg, re.I):
                    self.temp_offline()

                elif re.search(r'up to|size', errmsg, re.I):
                    self.fail(_("Link list too large for free decrypt"))

                elif re.search(r'404|sorry|offline|delet|remov|(no(t|thing)?|sn\'t) (found|(longer )?(available|exist))',
                               errmsg, re.I):
                    self.offline()

                elif re.search(r'filename', errmsg, re.I):
                    self.fail(_("Invalid url"))

                elif re.search(r'premium', errmsg, re.I):
                    self.fail(_("Link can be decrypted by premium users only"))

                else:
                    self.wait(60, reconnect=True)
                    self.restart(errmsg)

        elif self.WAIT_PATTERN:
            m = re.search(self.WAIT_PATTERN, self.data)
            if m is not None:
                try:
                    waitmsg = m.group(1).strip()

                except (AttributeError, IndexError):
                    waitmsg = m.group(0).strip()

                wait_time = parse_time(waitmsg)
                self.wait(wait_time, reconnect=wait_time > self.config.get("max_wait", 10) * 60)

        self.log_info(_("No errors found"))
        self.info.pop('error', None)
<commit_msg>[SimpleCrypter] Fix handle_direct<commit_after># -*- coding: utf-8 -*-

import re

from module.network.HTTPRequest import BadHeader
from module.network.RequestFactory import getURL as get_url
from module.plugins.internal.Crypter import Crypter
from module.plugins.internal.misc import parse_name, replace_patterns

class SimpleCrypter(Crypter):
    __name__    = "SimpleCrypter"
    __type__    = "crypter"
    __version__ = "0.83"
    __status__  = "testing"

    __pattern__ = r'^unmatchable$'
    __config__  = [("activated"         , "bool"          , "Activated"                                        , True     ),
                   ("use_premium"       , "bool"          , "Use premium account if available"                 , True     ),
                   ("folder_per_package", "Default;Yes;No", "Create folder for each package"                   , "Default"),
                   ("max_wait"          , "int"           , "Reconnect if waiting time is greater than minutes", 10       )]

    __description__ = """Simple decrypter plugin"""
    __license__     = "GPLv3"
    __authors__     = [("Walter Purcaro", "vuolter@gmail.com")]

    """
    Following patterns should be defined by each crypter:

      LINK_PATTERN: Download link or regex to catch links in group(1)
        example: LINK_PATTERN = r'
<a href="(.+?)"'

      NAME_PATTERN: (optional) folder name or page title
        example: NAME_PATTERN = r'<title>Files of: (?P<N>.+?) folder</title>'

      OFFLINE_PATTERN: (optional) Checks if the page is unreachable
        example: OFFLINE_PATTERN = r'File (deleted|not found)'

      TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable
        example: TEMP_OFFLINE_PATTERN = r'Server maintainance'

    You can override the get_links method if you need a more sophisticated way to extract the links.

    If the links are splitted on multiple pages you can define the PAGES_PATTERN regex:

      PAGES_PATTERN: (optional) group(1) should be the number of overall pages containing the links
        example: PAGES_PATTERN = r'Pages: (\d+)'

    and its load_page method:

      def load_page(self, page_n):
          return the html of the page number page_n
    """

    NAME_REPLACEMENTS    = []
    URL_REPLACEMENTS     = []

    COOKIES              = True   #: or False or list of tuples [(domain, name, value)]
    DIRECT_LINK          = True   #: Set to True to looking for direct link (as defined in handle_direct method), set to None to do it if self.account is True else False
    LOGIN_ACCOUNT        = False  #: Set to True to require account login
    LOGIN_PREMIUM        = False  #: Set to True to require premium account login
    TEXT_ENCODING        = True   #: Set to encoding name if encoding value in http header is not correct

    LINK_PATTERN         = None
    LINK_FREE_PATTERN    = None
    LINK_PREMIUM_PATTERN = None
    PAGES_PATTERN        = None

    NAME_PATTERN         = None
    OFFLINE_PATTERN      = r'[^\w](404\s|[Ii]nvalid|[Oo]ffline|[Dd]elet|[Rr]emov|([Nn]o(t|thing)?|sn\'t) (found|(longer )?(available|exist)))'
    TEMP_OFFLINE_PATTERN = r'[^\w](503\s|[Mm]aint(e|ai)nance|[Tt]emp([.-]|orarily)|[Mm]irror)'

    WAIT_PATTERN         = None
    PREMIUM_ONLY_PATTERN = None
    IP_BLOCKED_PATTERN   = None
    SIZE_LIMIT_PATTERN   = None
    ERROR_PATTERN        = None

    @classmethod
    def api_info(cls, url):
        return {}

    @classmethod
    def get_info(cls, url="", html=""):
        info = super(SimpleCrypter, cls).get_info(url)

        info.update(cls.api_info(url))

        if not html and info['status'] != 2:
            if not url:
                info['error']  = "missing url"
                info['status'] = 1

            elif info['status'] == 3:
                try:
                    html = get_url(url, cookies=cls.COOKIES, decode=cls.TEXT_ENCODING)

                except BadHeader, e:
                    info['error'] = "%d: %s" % (e.code, e.content)

                except Exception:
                    pass

        if html:
            if cls.OFFLINE_PATTERN and re.search(cls.OFFLINE_PATTERN, html) is not None:
                info['status'] = 1

            elif cls.TEMP_OFFLINE_PATTERN and re.search(cls.TEMP_OFFLINE_PATTERN, html) is not None:
                info['status'] = 6

            elif cls.NAME_PATTERN:
                m = re.search(cls.NAME_PATTERN, html)
                if m is not None:
                    info['status'] = 2
                    info['pattern'].update(m.groupdict())

        if 'N' in info['pattern']:
            name = replace_patterns(info['pattern']['N'], cls.NAME_REPLACEMENTS)
            info['name'] = parse_name(name)

        return info

    #@TODO: Remove in 0.4.10
    def setup_base(self):
        account_name = self.classname.rsplit("Folder", 1)[0]

        if self.account:
            self.req     = self.pyload.requestFactory.getRequest(account_name, self.account.user)
            self.premium = self.account.info['data']['premium']  #@NOTE: Don't call get_info here to reduce overhead
        else:
            self.req     = self.pyload.requestFactory.getRequest(account_name)
            self.premium = False

        super(SimpleCrypter, self).setup_base()

    #@TODO: Remove in 0.4.10
    def load_account(self):
        class_name = self.classname
        self.__class__.__name__ = class_name.rsplit("Folder", 1)[0]
        super(SimpleCrypter, self).load_account()
        self.__class__.__name__ = class_name

    def handle_direct(self, pyfile):
        self._preload()

        link = self.last_header.get('url')
        if re.match(self.__pattern__, link) is None:
            self.links.append(link)

    def _preload(self):
        if self.data:
            return

        self.data = self.load(self.pyfile.url,
                              cookies=self.COOKIES,
                              ref=False,
                              decode=self.TEXT_ENCODING)

    def _prepare(self):
        self.direct_dl = False

        if self.LOGIN_PREMIUM and not self.premium:
            self.fail(_("Required premium account not found"))

        if self.LOGIN_ACCOUNT and not self.account:
            self.fail(_("Required account not found"))

        self.req.setOption("timeout", 120)

        if self.LINK_PATTERN:
            if self.LINK_FREE_PATTERN is None:
                self.LINK_FREE_PATTERN = self.LINK_PATTERN

            if self.LINK_PREMIUM_PATTERN is None:
                self.LINK_PREMIUM_PATTERN = self.LINK_PATTERN

        if self.DIRECT_LINK is None:
            self.direct_dl = bool(self.premium)
        else:
            self.direct_dl = self.DIRECT_LINK

        self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS)

    def decrypt(self, pyfile):
        self._prepare()

        if self.direct_dl:
            self.log_info(_("Looking for direct link..."))
            self.handle_direct(pyfile)

            if self.links or self.packages:
                self.log_info(_("Direct link detected"))
            else:
                self.log_info(_("Direct link not found"))

        if not self.links and not self.packages:
            self._preload()
            self.check_errors()

            self.links.extend(self.get_links())

            if self.PAGES_PATTERN:
                self.handle_pages(pyfile)

    def handle_free(self, pyfile):
        if not self.LINK_FREE_PATTERN:
            self.log_warning(_("Free decrypting not implemented"))

        links = re.findall(self.LINK_FREE_PATTERN, self.data)
        if not links:
            self.error(_("Free decrypted link not found"))
        else:
            self.links.extend(links)

    def handle_premium(self, pyfile):
        if not self.LINK_PREMIUM_PATTERN:
            self.log_warning(_("Premium decrypting not implemented"))
            self.restart(premium=False)

        links = re.findall(self.LINK_PREMIUM_PATTERN, self.data)
        if not links:
            self.error(_("Premium decrypted link found"))
        else:
            self.links.extend(links)

    def get_links(self):
        """
        Returns the links extracted from self.data
        You should override this only if it's impossible to extract links using only the LINK_PATTERN.
        """
        if self.premium:
            self.log_info(_("Decrypting as premium link..."))
            self.handle_premium(self.pyfile)

        elif not self.LOGIN_ACCOUNT:
            self.log_info(_("Decrypting as free link..."))
            self.handle_free(self.pyfile)

        return self.links

    def load_page(self, number):
        raise NotImplementedError

    def handle_pages(self, pyfile):
        try:
            pages = int(re.search(self.PAGES_PATTERN, self.data).group(1))

        except Exception:
            pages = 1

        for p in xrange(2, pages + 1):
            self.data = self.load_page(p)
            self.links.extend(self.get_links())

    def check_errors(self):
        self.log_info(_("Checking for link errors..."))

        if not self.data:
            self.log_warning(_("No data to check"))
            return

        if self.IP_BLOCKED_PATTERN and re.search(self.IP_BLOCKED_PATTERN, self.data):
            self.fail(_("Connection from your current IP address is not allowed"))

        elif not self.premium:
            if self.PREMIUM_ONLY_PATTERN and re.search(self.PREMIUM_ONLY_PATTERN, self.data):
                self.fail(_("Link can be decrypted by premium users only"))

            elif self.SIZE_LIMIT_PATTERN and re.search(self.SIZE_LIMIT_PATTERN, self.data):
                self.fail(_("Link list too large for free decrypt"))

        if self.ERROR_PATTERN:
            m = re.search(self.ERROR_PATTERN, self.data)
            if m is not None:
                try:
                    errmsg = m.group(1)

                except (AttributeError, IndexError):
                    errmsg = m.group(0)

                finally:
                    errmsg = re.sub(r'<.*?>', " ", errmsg.strip())

                self.info['error'] = errmsg
                self.log_warning(errmsg)

                if re.search(self.TEMP_OFFLINE_PATTERN, errmsg):
                    self.temp_offline()

                elif re.search(self.OFFLINE_PATTERN, errmsg):
                    self.offline()

                elif re.search(r'limit|wait|slot', errmsg, re.I):
                    wait_time = parse_time(errmsg)
                    self.wait(wait_time, reconnect=wait_time > self.config.get('max_wait', 10) * 60)
                    self.restart(_("Download limit exceeded"))

                elif re.search(r'country|ip|region|nation', errmsg, re.I):
                    self.fail(_("Connection from your current IP address is not allowed"))

                elif re.search(r'captcha|code', errmsg, re.I):
                    self.retry_captcha()

                elif re.search(r'countdown|expired', errmsg, re.I):
                    self.retry(10, 60, _("Link expired"))

                elif re.search(r'503|maint(e|ai)nance|temp|mirror', errmsg, re.I):
                    self.temp_offline()

                elif re.search(r'up to|size', errmsg, re.I):
                    self.fail(_("Link list too large for free decrypt"))

                elif re.search(r'404|sorry|offline|delet|remov|(no(t|thing)?|sn\'t) (found|(longer )?(available|exist))',
                               errmsg, re.I):
                    self.offline()

                elif re.search(r'filename', errmsg, re.I):
                    self.fail(_("Invalid url"))

                elif re.search(r'premium', errmsg, re.I):
                    self.fail(_("Link can be decrypted by premium users only"))

                else:
                    self.wait(60, reconnect=True)
                    self.restart(errmsg)

        elif self.WAIT_PATTERN:
            m = re.search(self.WAIT_PATTERN, self.data)
            if m is not None:
                try:
                    waitmsg = m.group(1).strip()

                except (AttributeError, IndexError):
                    waitmsg = m.group(0).strip()

                wait_time = parse_time(waitmsg)
                self.wait(wait_time, reconnect=wait_time > self.config.get('max_wait', 10) * 60)

        self.log_info(_("No errors found"))
        self.info.pop('error', None)
<|endoftext|>


<commit_before>import sublime
import sublime_plugin
import os
import subprocess
import re
import tempfile

def syntax_settings(lang, key, default=None):
    settings = sublime.load_settings("SendTextPlus.sublime-settings")
    ret = None
    plat = sublime.platform()
    if lang:
        lang_settings = settings.get(lang)
        os_settings = lang_settings.get(plat)
        if os_settings:
            ret = os_settings.get(key)
        if not ret:
            ret = lang_settings.get(key)
    if not ret:
        ret = settings.get("default").get(plat).get(key)
    if not ret:
        ret = default
    return ret

def clean(cmd):
    cmd = cmd.expandtabs(4)
    cmd = cmd.rstrip('\n')
    if len(re.findall("\n", cmd)) == 0:
        cmd = cmd.lstrip()
    return cmd

def escape_dq(cmd):
    cmd = cmd.replace('\\', '\\\\')
    cmd = cmd.replace('"', '\\"')
    return cmd

def sendtext(prog, cmd):
    plat = sublime.platform()
    settings = sublime.load_settings("SendTextPlus.sublime-settings")
    print(prog)

    if prog == 'Terminal.app':
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        args = ['osascript']
        args.extend(['-e', 'tell app "Terminal" to do script "' + cmd + '" in front window\n'])
        subprocess.Popen(args)

    elif prog == "iTerm.app":
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        # when cmd ends in a space, iterm does not execute. Thus append a line break.
        if (cmd[-1:] == ' '):
            cmd += '\n'
        args = ['osascript']
        args.extend(['-e', 'tell app "iTerm" to tell the first terminal to tell current session to write text "' + cmd +'"'])
        subprocess.Popen(args)

    elif prog == "tmux":
        progpath = settings.get("tmux", "tmux")
        subprocess.call([progpath, 'set-buffer', cmd])
        subprocess.call([progpath, 'paste-buffer', '-d'])

    elif prog == "screen":
        progpath = settings.get("screen", "screen")
        if len(cmd)<2000:
            subprocess.call([progpath, '-X', 'stuff', cmd])
        else:
            with tempfile.NamedTemporaryFile() as tmp:
                with open(tmp.name, 'w') as f:
                    f.write(cmd)
                    subprocess.call([progpath, '-X', 'stuff', ". %s\n" % (f.name)])

    if plat == 'windows':
        raise Exception("not yet supported")

class SendTextPlusCommand(sublime_plugin.TextCommand):
    def get_syntax(self):
        view = self.view
        pt = view.sel()[0].begin() if len(view.sel())>0 else 0
        if view.score_selector(pt, "source.r"):
            return "r"
        elif view.score_selector(pt, "source.python"):
            return "python"
        elif view.score_selector(pt, "source.julia"):
            return "julia"

    def r_expand_block(self, sel):
        # expand selection to {...} when being triggered
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r".*\{\s*$", thiscmd):
            esel = view.find(r"""^(?:.*(\{(?:(["\'])(?:[^\\]|\\.)*?\2|#.*$|[^\{\}]|(?1))*\})[^\{\}\n]*)+"""
                    , view.line(sel).begin())
            if view.line(sel).begin() == esel.begin():
                sel = esel
        return sel

    def python_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r"^[ \t]*\S", thiscmd):
            indentation = re.match(r"^([ \t]*)", thiscmd).group(1)
            row = view.rowcol(sel.begin())[0]
            prevline = view.line(sel.begin())
            lastrow = view.rowcol(view.size())[0]
            while row < lastrow:
                row = row +1
                line = view.line(view.text_point(row, 0))
                m = re.match(r"^([ \t]*)([^\n\s]+)", view.substr(line))
                if m and len(m.group(1)) <= len(indentation) and \
                        not re.match(r"else|elif|except|finally", m.group(2)):
                    sel = sublime.Region(sel.begin(), prevline.end())
                    break
                elif re.match(r"^[ \t]*\S", view.substr(line)):
                    prevline = line

            if row == lastrow:
                sel = sublime.Region(sel.begin(), prevline.end())

        return sel

    def julia_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if (re.match(r"^\s*(?:function|if|for|while)", thiscmd) and \
                not re.match(r".*end\s*$", thiscmd)) or \
            (re.match(r".*begin\s*$", thiscmd)):
            indentation = re.match("^(\s*)", thiscmd).group(1)
            end = view.find("^"+indentation+"end", sel.begin())
            sel = sublime.Region(sel.begin(), view.line(end.end()).end())

        return sel

    def run(self, edit):
        view = self.view
        syntax = self.get_syntax()
        cmd = ''
        for sel in [s for s in view.sel()]:
            if sel.empty():
                if syntax_settings(syntax, "block", False):
                    if syntax == "r":
                        esel = self.r_expand_block(sel)
                    elif syntax == "python":
                        esel = self.python_expand_block(sel)
                    elif syntax == "julia":
                        esel = self.julia_expand_block(sel)

                    thiscmd = view.substr(view.line(esel))
                    line = view.rowcol(esel.end())[0]
                else:
                    thiscmd = view.substr(view.line(sel))
                    line = view.rowcol(sel.end())[0]

                if syntax_settings(syntax, "auto_advance", False):
                    view.sel().subtract(sel)
                    pt = view.text_point(line+1,0)
                    view.sel().add(sublime.Region(pt,pt))
            else:
                thiscmd = view.substr(sel)
            cmd += thiscmd +'\n'

        # ipython wrapper
        if syntax == "python" and syntax_settings(syntax, "ipython", False):
            cmd = clean(cmd)
            oldcb = sublime.get_clipboard()
            if len(re.findall("\n", cmd)) > 0:
                sublime.set_clipboard(cmd)
                cmd = "%paste"

        prog = syntax_settings(syntax, "prog")
        sendtext(prog, cmd)

        # reset clipbooard
        if syntax == "python" and syntax_settings(syntax, "ipython", False):
            sublime.set_timeout_async(lambda: sublime.set_clipboard(oldcb), 500)

        if syntax_settings(syntax, "auto_advance", False):
            view.show(view.sel())
<commit_msg>remove debug print<commit_after>import sublime
import sublime_plugin
import os
import subprocess
import re
import tempfile

def syntax_settings(lang, key, default=None):
    settings = sublime.load_settings("SendTextPlus.sublime-settings")
    ret = None
    plat = sublime.platform()
    if lang:
        lang_settings = settings.get(lang)
        os_settings = lang_settings.get(plat)
        if os_settings:
            ret = os_settings.get(key)
        if not ret:
            ret = lang_settings.get(key)
    if not ret:
        ret = settings.get("default").get(plat).get(key)
    if not ret:
        ret = default
    return ret

def clean(cmd):
    cmd = cmd.expandtabs(4)
    cmd = cmd.rstrip('\n')
    if len(re.findall("\n", cmd)) == 0:
        cmd = cmd.lstrip()
    return cmd

def escape_dq(cmd):
    cmd = cmd.replace('\\', '\\\\')
    cmd = cmd.replace('"', '\\"')
    return cmd

def sendtext(prog, cmd):
    plat = sublime.platform()
    settings = sublime.load_settings("SendTextPlus.sublime-settings")

    if prog == 'Terminal.app':
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        args = ['osascript']
        args.extend(['-e', 'tell app "Terminal" to do script "' + cmd + '" in front window\n'])
        subprocess.Popen(args)

    elif prog == "iTerm.app":
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        # when cmd ends in a space, iterm does not execute. Thus append a line break.
        if (cmd[-1:] == ' '):
            cmd += '\n'
        args = ['osascript']
        args.extend(['-e', 'tell app "iTerm" to tell the first terminal to tell current session to write text "' + cmd +'"'])
        subprocess.Popen(args)

    elif prog == "tmux":
        progpath = settings.get("tmux", "tmux")
        subprocess.call([progpath, 'set-buffer', cmd])
        subprocess.call([progpath, 'paste-buffer', '-d'])

    elif prog == "screen":
        progpath = settings.get("screen", "screen")
        if len(cmd)<2000:
            subprocess.call([progpath, '-X', 'stuff', cmd])
        else:
            with tempfile.NamedTemporaryFile() as tmp:
                with open(tmp.name, 'w') as f:
                    f.write(cmd)
                    subprocess.call([progpath, '-X', 'stuff', ". %s\n" % (f.name)])

    if plat == 'windows':
        raise Exception("not yet supported")

class SendTextPlusCommand(sublime_plugin.TextCommand):
    def get_syntax(self):
        view = self.view
        pt = view.sel()[0].begin() if len(view.sel())>0 else 0
        if view.score_selector(pt, "source.r"):
            return "r"
        elif view.score_selector(pt, "source.python"):
            return "python"
        elif view.score_selector(pt, "source.julia"):
            return "julia"

    def r_expand_block(self, sel):
        # expand selection to {...} when being triggered
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r".*\{\s*$", thiscmd):
            esel = view.find(r"""^(?:.*(\{(?:(["\'])(?:[^\\]|\\.)*?\2|#.*$|[^\{\}]|(?1))*\})[^\{\}\n]*)+"""
                    , view.line(sel).begin())
            if view.line(sel).begin() == esel.begin():
                sel = esel
        return sel

    def python_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r"^[ \t]*\S", thiscmd):
            indentation = re.match(r"^([ \t]*)", thiscmd).group(1)
            row = view.rowcol(sel.begin())[0]
            prevline = view.line(sel.begin())
            lastrow = view.rowcol(view.size())[0]
            while row < lastrow:
                row = row +1
                line = view.line(view.text_point(row, 0))
                m = re.match(r"^([ \t]*)([^\n\s]+)", view.substr(line))
                if m and len(m.group(1)) <= len(indentation) and \
                        not re.match(r"else|elif|except|finally", m.group(2)):
                    sel = sublime.Region(sel.begin(), prevline.end())
                    break
                elif re.match(r"^[ \t]*\S", view.substr(line)):
                    prevline = line

            if row == lastrow:
                sel = sublime.Region(sel.begin(), prevline.end())

        return sel

    def julia_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if (re.match(r"^\s*(?:function|if|for|while)", thiscmd) and \
                not re.match(r".*end\s*$", thiscmd)) or \
            (re.match(r".*begin\s*$", thiscmd)):
            indentation = re.match("^(\s*)", thiscmd).group(1)
            end = view.find("^"+indentation+"end", sel.begin())
            sel = sublime.Region(sel.begin(), view.line(end.end()).end())

        return sel

    def run(self, edit):
        view = self.view
        syntax = self.get_syntax()
        cmd = ''
        for sel in [s for s in view.sel()]:
            if sel.empty():
                if syntax_settings(syntax, "block", False):
                    if syntax == "r":
                        esel = self.r_expand_block(sel)
                    elif syntax == "python":
                        esel = self.python_expand_block(sel)
                    elif syntax == "julia":
                        esel = self.julia_expand_block(sel)

                    thiscmd = view.substr(view.line(esel))
                    line = view.rowcol(esel.end())[0]
                else:
                    thiscmd = view.substr(view.line(sel))
                    line = view.rowcol(sel.end())[0]

                if syntax_settings(syntax, "auto_advance", False):
                    view.sel().subtract(sel)
                    pt = view.text_point(line+1,0)
                    view.sel().add(sublime.Region(pt,pt))
            else:
                thiscmd = view.substr(sel)
            cmd += thiscmd +'\n'

        # ipython wrapper
        if syntax == "python" and syntax_settings(syntax, "ipython", False):
            cmd = clean(cmd)
            oldcb = sublime.get_clipboard()
            if len(re.findall("\n", cmd)) > 0:
                sublime.set_clipboard(cmd)
                cmd = "%paste"

        prog = syntax_settings(syntax, "prog")
        sendtext(prog, cmd)

        # reset clipbooard
        if syntax == "python" and syntax_settings(syntax, "ipython", False):
            sublime.set_timeout_async(lambda: sublime.set_clipboard(oldcb), 500)

        if syntax_settings(syntax, "auto_advance", False):
            view.show(view.sel())
<|endoftext|>


<commit_before>import code
from code import softspace
import sys
import wx
import new

def sanitise_text(text):
    """When we process text before saving or executing, we sanitise it
    by changing all CR/LF pairs into LF, and then nuking all remaining CRs.
    This consistency also ensures that the files we save have the correct
    line-endings depending on the operating system we are running on.

    It also turns out that things break when after an indentation
    level at the very end of the code, there is no empty line.  For
    example (thanks to Emiel v. IJsseldijk for reproducing!):
    def hello():
      print "hello" # and this is the last line of the text
    Will not completely define method hello.

    To remedy this, we add an empty line at the very end if there's
    not one already.

    """

    text = text.replace('\r\n', '\n')
    text = text.replace('\r', '')

    lines = text.split('\n')

    if lines and len(lines[-1]) != 0:
        return text + '\n'
    else:
        return text

def runcode(self, code):
    """Execute a code object.

    Our extra-special verson of the runcode method.  We use this when we
    want py_shell_mixin._run_source() to generate real exceptions, and
    not just output to stdout, for example when CodeRunner is executed
    as part of a network.  This runcode() is explicitly called by our local
    runsource() method.
    """
    try:
        exec code in self.locals
    except SystemExit:
        raise
    except:
        raise
        #self.showtraceback()
    else:
        if softspace(sys.stdout, 0):
            print

def runsource(self, source, filename="<input>", symbol="single",
              runcode=runcode):
    """Compile and run some source in the interpreter.

    Our extra-special verson of the runsource method.  We use this when we
    want py_shell_mixin._run_source() to generate real exceptions, and
    not just output to stdout, for example when CodeRunner is executed
    as part of a network.  This method calls our special runcode() method
    as well.

    Arguments are as for compile_command(), but pass in interp instance as
    first parameter!

    """
    try:
        # this could raise OverflowError, SyntaxEror, ValueError
        code = self.compile(source, filename, symbol)
    except (OverflowError, SyntaxError, ValueError):
        # Case 1
        raise
        #return False

    if code is None:
        # Case 2
        return True

    # Case 3
    runcode(self, code)
    return False

class PythonShellMixin:

    def __init__(self, shell_window, module_manager):
        # init close handlers
        self.close_handlers = []
        self.shell_window = shell_window
        self.module_manager = module_manager

    def close(self, exception_printer):
        for ch in self.close_handlers:
            try:
                ch()
            except Exception, e:
                exception_printer(
                    'Exception during PythonShellMixin close_handlers: %s' %
                    (str(e),))

        del self.shell_window

    def _open_python_file(self, parent_window):
        fd = wx.FileDialog(
            parent_window,
            'Select file to open into current edit',
            wildcard='*.py', style=wx.OPEN)

        if fd.ShowModal() == wx.ID_OK:
            filename = fd.GetPath()

            f = open(filename, 'r')

            t = f.read()
            t = sanitise_text(t)
            f.close()

            return filename, t

        else:
            return (None, None)

    def _save_python_file(self, filename, text):
        text = sanitise_text(text)

        f = open(filename, 'w')
        f.write(text)
        f.close()

    def _saveas_python_file(self, text, parent_window):
        fd = wx.FileDialog(
            parent_window,
            'Select filename to save current edit to',
            wildcard='*.py', style=wx.SAVE)

        if fd.ShowModal() == wx.ID_OK:
            filename = fd.GetPath()

            self._save_python_file(filename, text)

            return filename

        return None

    def _run_source(self, text, raise_exceptions=False):
        """Compile and run the source given in text in the shell interpreter's
        local namespace.

        The idiot pyshell goes through the whole shell.push -> interp.push
        -> interp.runsource -> InteractiveInterpreter.runsource hardcoding the
        'mode' parameter (effectively) to 'single', thus breaking multi-line
        definitions and whatnot.

        Here we do some deep magic (ha ha) to externally override the interp
        runsource.  Python does completely rule.

        We do even deeper magic when raise_exceptions is True: we then
        raise real exceptions when errors occur instead of just outputting to
        stederr.
        """

        text = sanitise_text(text)
        interp = self.shell_window.interp

        if raise_exceptions:
            # run our local runsource, don't do any stdout/stderr redirection,
            # this is happening as part of a network.
            more = runsource(interp, text, '<input>', 'exec')

        else:
            # our 'traditional' version for normal in-shell introspection and
            # execution.  Exceptions are turned into nice stdout/stderr
            # messages.

            stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
            sys.stdin, sys.stdout, sys.stderr = \
                       interp.stdin, interp.stdout, interp.stderr

            # look: calling class method with interp instance as first
            # parameter comes down to the same as interp calling runsource()
            # as its parent method.
            more = code.InteractiveInterpreter.runsource(
                interp, text, '<input>', 'exec')

            # make sure the user can type again
            self.shell_window.prompt()

            sys.stdin = stdin
            sys.stdout = stdout
            sys.stderr = stderr

        return more

    def output_text(self, text):
        self.shell_window.write(text + '\n')
        self.shell_window.prompt()

    def support_vtk(self, interp):
        if hasattr(self, 'vtk_renderwindows'):
            return

        import module_kits
        if 'vtk_kit' not in module_kits.module_kit_list:
            self.output_text('No VTK support.')
            return

        from module_kits import vtk_kit
        vtk = vtk_kit.vtk

        def get_render_info(instance_name):
            instance = self.module_manager.get_instance(instance_name)

            if instance is None:
                return None

            class RenderInfo:
                pass

            render_info = RenderInfo()

            render_info.renderer = instance.get_3d_renderer()
            render_info.render_window = instance.get_3d_render_window()
            render_info.interactor = instance.\
                                     get_3d_render_window_interactor()

            return render_info

        new_dict = {'vtk' : vtk,
                    'vtk_get_render_info' : get_render_info}

        interp.locals.update(new_dict)
        self.__dict__.update(new_dict)

        self.output_text('VTK support loaded.')

    def support_matplotlib(self, interp):
        if hasattr(self, 'mpl_figure_handles'):
            return

        import module_kits

        if 'matplotlib_kit' not in module_kits.module_kit_list:
            self.output_text('No matplotlib support.')
            return

        from module_kits import matplotlib_kit
        pylab = matplotlib_kit.pylab

        # setup shutdown logic ########################################
        self.mpl_figure_handles = []

        def mpl_close_handler():
            for fh in self.mpl_figure_handles:
                pylab.close(fh)

        self.close_handlers.append(mpl_close_handler)

        # hook our mpl_new_figure method ##############################

        # mpl_new_figure hook so that all created figures are registered
        # and will be closed when the module is closed
        def mpl_new_figure(*args, **kwargs):
            handle = pylab.figure(*args, **kwargs)
            self.mpl_figure_handles.append(handle)
            return handle

        def mpl_close_figure(handle):
            """Close matplotlib figure.
            """
            pylab.close(handle)
            if handle in self.mpl_figure_handles:
                idx = self.mpl_figure_handles.index(handle)
                del self.mpl_figure_handles[idx]

        # replace our hook's documentation with the 'real' documentation
        mpl_new_figure.__doc__ = pylab.figure.__doc__

        # stuff the required symbols into the module's namespace ######
        new_dict = {'matplotlib' : matplotlib_kit.matplotlib,
                    'pylab' : matplotlib_kit.pylab,
                    'mpl_new_figure' : mpl_new_figure,
                    'mpl_close_figure' : mpl_close_figure}

        interp.locals.update(new_dict)
        self.__dict__.update(new_dict)

        self.output_text('matplotlib support loaded.')

<commit_msg>PythonShellMixin now explicitly stores last saved to / loaded from directory.  Also changed to use FileSelector.<commit_after>import code
from code import softspace
import os
import sys
import wx
import new

def sanitise_text(text):
    """When we process text before saving or executing, we sanitise it
    by changing all CR/LF pairs into LF, and then nuking all remaining CRs.
    This consistency also ensures that the files we save have the correct
    line-endings depending on the operating system we are running on.

    It also turns out that things break when after an indentation
    level at the very end of the code, there is no empty line.  For
    example (thanks to Emiel v. IJsseldijk for reproducing!):
    def hello():
      print "hello" # and this is the last line of the text
    Will not completely define method hello.

    To remedy this, we add an empty line at the very end if there's
    not one already.

    """

    text = text.replace('\r\n', '\n')
    text = text.replace('\r', '')

    lines = text.split('\n')

    if lines and len(lines[-1]) != 0:
        return text + '\n'
    else:
        return text

def runcode(self, code):
    """Execute a code object.

    Our extra-special verson of the runcode method.  We use this when we
    want py_shell_mixin._run_source() to generate real exceptions, and
    not just output to stdout, for example when CodeRunner is executed
    as part of a network.  This runcode() is explicitly called by our local
    runsource() method.
    """
    try:
        exec code in self.locals
    except SystemExit:
        raise
    except:
        raise
        #self.showtraceback()
    else:
        if softspace(sys.stdout, 0):
            print

def runsource(self, source, filename="<input>", symbol="single",
              runcode=runcode):
    """Compile and run some source in the interpreter.

    Our extra-special verson of the runsource method.  We use this when we
    want py_shell_mixin._run_source() to generate real exceptions, and
    not just output to stdout, for example when CodeRunner is executed
    as part of a network.  This method calls our special runcode() method
    as well.

    Arguments are as for compile_command(), but pass in interp instance as
    first parameter!

    """
    try:
        # this could raise OverflowError, SyntaxEror, ValueError
        code = self.compile(source, filename, symbol)
    except (OverflowError, SyntaxError, ValueError):
        # Case 1
        raise
        #return False

    if code is None:
        # Case 2
        return True

    # Case 3
    runcode(self, code)
    return False

class PythonShellMixin:

    def __init__(self, shell_window, module_manager):
        # init close handlers
        self.close_handlers = []
        self.shell_window = shell_window
        self.module_manager = module_manager

        self._last_fileselector_dir = ''

    def close(self, exception_printer):
        for ch in self.close_handlers:
            try:
                ch()
            except Exception, e:
                exception_printer(
                    'Exception during PythonShellMixin close_handlers: %s' %
                    (str(e),))

        del self.shell_window

    def _open_python_file(self, parent_window):
        filename = wx.FileSelector(
                'Select file to open into current edit',
                self._last_fileselector_dir, "", "py",
                "Python files (*.py)|*.py|All files (*.*)|*.*",
                wx.OPEN, parent_window)

        if filename:
            # save directory for future use
            self._last_fileselector_dir = \
                    os.path.dirname(filename)

            f = open(filename, 'r')

            t = f.read()
            t = sanitise_text(t)
            f.close()

            return filename, t

        else:
            return (None, None)

    def _save_python_file(self, filename, text):
        text = sanitise_text(text)

        f = open(filename, 'w')
        f.write(text)
        f.close()

    def _saveas_python_file(self, text, parent_window):
        filename = wx.FileSelector(
                'Select filename to save current edit to',
                self._last_fileselector_dir, "", "py",
                "Python files (*.py)|*.py|All files (*.*)|*.*",
                wx.SAVE, parent_window)

        if filename:
            # save directory for future use
            self._last_fileselector_dir = \
                    os.path.dirname(filename)

            # if the user has NOT specified any fileextension, we
            # add .py.  (on Win this gets added by the
            # FileSelector automatically, on Linux it doesn't)
            if os.path.splitext(filename)[1] == '':
                filename = '%s.py' % (filename,)

            self._save_python_file(filename, text)

            return filename

        return None

    def _run_source(self, text, raise_exceptions=False):
        """Compile and run the source given in text in the shell interpreter's
        local namespace.

        The idiot pyshell goes through the whole shell.push -> interp.push
        -> interp.runsource -> InteractiveInterpreter.runsource hardcoding the
        'mode' parameter (effectively) to 'single', thus breaking multi-line
        definitions and whatnot.

        Here we do some deep magic (ha ha) to externally override the interp
        runsource.  Python does completely rule.

        We do even deeper magic when raise_exceptions is True: we then
        raise real exceptions when errors occur instead of just outputting to
        stederr.
        """

        text = sanitise_text(text)
        interp = self.shell_window.interp

        if raise_exceptions:
            # run our local runsource, don't do any stdout/stderr redirection,
            # this is happening as part of a network.
            more = runsource(interp, text, '<input>', 'exec')

        else:
            # our 'traditional' version for normal in-shell introspection and
            # execution.  Exceptions are turned into nice stdout/stderr
            # messages.

            stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
            sys.stdin, sys.stdout, sys.stderr = \
                       interp.stdin, interp.stdout, interp.stderr

            # look: calling class method with interp instance as first
            # parameter comes down to the same as interp calling runsource()
            # as its parent method.
            more = code.InteractiveInterpreter.runsource(
                interp, text, '<input>', 'exec')

            # make sure the user can type again
            self.shell_window.prompt()

            sys.stdin = stdin
            sys.stdout = stdout
            sys.stderr = stderr

        return more

    def output_text(self, text):
        self.shell_window.write(text + '\n')
        self.shell_window.prompt()

    def support_vtk(self, interp):
        if hasattr(self, 'vtk_renderwindows'):
            return

        import module_kits
        if 'vtk_kit' not in module_kits.module_kit_list:
            self.output_text('No VTK support.')
            return

        from module_kits import vtk_kit
        vtk = vtk_kit.vtk

        def get_render_info(instance_name):
            instance = self.module_manager.get_instance(instance_name)

            if instance is None:
                return None

            class RenderInfo:
                pass

            render_info = RenderInfo()

            render_info.renderer = instance.get_3d_renderer()
            render_info.render_window = instance.get_3d_render_window()
            render_info.interactor = instance.\
                                     get_3d_render_window_interactor()

            return render_info

        new_dict = {'vtk' : vtk,
                    'vtk_get_render_info' : get_render_info}

        interp.locals.update(new_dict)
        self.__dict__.update(new_dict)

        self.output_text('VTK support loaded.')

    def support_matplotlib(self, interp):
        if hasattr(self, 'mpl_figure_handles'):
            return

        import module_kits

        if 'matplotlib_kit' not in module_kits.module_kit_list:
            self.output_text('No matplotlib support.')
            return

        from module_kits import matplotlib_kit
        pylab = matplotlib_kit.pylab

        # setup shutdown logic ########################################
        self.mpl_figure_handles = []

        def mpl_close_handler():
            for fh in self.mpl_figure_handles:
                pylab.close(fh)

        self.close_handlers.append(mpl_close_handler)

        # hook our mpl_new_figure method ##############################

        # mpl_new_figure hook so that all created figures are registered
        # and will be closed when the module is closed
        def mpl_new_figure(*args, **kwargs):
            handle = pylab.figure(*args, **kwargs)
            self.mpl_figure_handles.append(handle)
            return handle

        def mpl_close_figure(handle):
            """Close matplotlib figure.
            """
            pylab.close(handle)
            if handle in self.mpl_figure_handles:
                idx = self.mpl_figure_handles.index(handle)
                del self.mpl_figure_handles[idx]

        # replace our hook's documentation with the 'real' documentation
        mpl_new_figure.__doc__ = pylab.figure.__doc__

        # stuff the required symbols into the module's namespace ######
        new_dict = {'matplotlib' : matplotlib_kit.matplotlib,
                    'pylab' : matplotlib_kit.pylab,
                    'mpl_new_figure' : mpl_new_figure,
                    'mpl_close_figure' : mpl_close_figure}

        interp.locals.update(new_dict)
        self.__dict__.update(new_dict)

        self.output_text('matplotlib support loaded.')

<|endoftext|>


<commit_before>"""
Fix the SES collections with NULL source model (the ones associated to
scenario calculations) by creating fake source models for them.
Then add a NOT NULL constraint on lt_model_id.
"""

GET_SESCOLL_AND_JOBS = """\
SELECT a.id AS ses_coll_id, b.oq_job_id
FROM hzrdr.ses_collection AS a, uiapi.output as b
WHERE output_id=b.id AND lt_model_id IS NULL;
"""

CREATE_LT_MODEL = """\
INSERT INTO hzrdr.lt_source_model
(hazard_calculation_id, ordinal, sm_lt_path, sm_name)
VALUES (%s, 0, %s, 'fake-from-rupture')
RETURNING id;
"""

UPDATE_SES_COLL = """\
UPDATE hzrdr.ses_collection
SET lt_model_id=%s WHERE id=%s;
"""

FIX_SES_COLL = """\
TRUNCATE TABLE hzrdr.ses_collection CASCADE;  -- to fix

ALTER TABLE hzrdr.ses_collection ADD COLUMN trt_model_id INTEGER NOT NULL
REFERENCES hzrdr.trt_model (id);

ALTER TABLE hzrdr.ses_collection DROP COLUMN lt_model;
"""

def upgrade(conn):
    curs = conn.cursor()
    curs.execute(GET_SESCOLL_AND_JOBS)
    for ses_coll_id, oq_job_id in curs.fetchall():
        curs.execute(CREATE_LT_MODEL, (oq_job_id, []))
        [[lt_model_id]] = curs.fetchall()
        curs.execute(UPDATE_SES_COLL, (lt_model_id, ses_coll_id))
    curs.execute(FIX_SES_COLL)
<commit_msg>Fixed a misprint<commit_after>"""
Fix the SES collections with NULL source model (the ones associated to
scenario calculations) by creating fake source models for them.
Then add a NOT NULL constraint on lt_model_id.
"""

GET_SESCOLL_AND_JOBS = """\
SELECT a.id AS ses_coll_id, b.oq_job_id
FROM hzrdr.ses_collection AS a, uiapi.output as b
WHERE output_id=b.id AND lt_model_id IS NULL;
"""

CREATE_LT_MODEL = """\
INSERT INTO hzrdr.lt_source_model
(hazard_calculation_id, ordinal, sm_lt_path, sm_name)
VALUES (%s, 0, %s, 'fake-from-rupture')
RETURNING id;
"""

UPDATE_SES_COLL = """\
UPDATE hzrdr.ses_collection
SET lt_model_id=%s WHERE id=%s;
"""

FIX_SES_COLL = """\
TRUNCATE TABLE hzrdr.ses_collection CASCADE;  -- to fix

ALTER TABLE hzrdr.ses_collection ADD COLUMN trt_model_id INTEGER NOT NULL
REFERENCES hzrdr.trt_model (id);

ALTER TABLE hzrdr.ses_collection DROP COLUMN lt_model_id;
"""

def upgrade(conn):
    curs = conn.cursor()
    curs.execute(GET_SESCOLL_AND_JOBS)
    for ses_coll_id, oq_job_id in curs.fetchall():
        curs.execute(CREATE_LT_MODEL, (oq_job_id, []))
        [[lt_model_id]] = curs.fetchall()
        curs.execute(UPDATE_SES_COLL, (lt_model_id, ses_coll_id))
    curs.execute(FIX_SES_COLL)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Production Configurations

- Use djangosecure
- Use mailgun to send emails

- Use sentry for error logging

'''
from __future__ import absolute_import, unicode_literals

import logging

from django.utils import six

from .common import *  # noqa

# SECRET CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ
SECRET_KEY = env("DJANGO_SECRET_KEY")

# This ensures that Django will be able to detect a secure connection
# properly on Heroku.
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# raven sentry client
# See https://docs.getsentry.com/hosted/clients/python/integrations/django/
INSTALLED_APPS += ('raven.contrib.django.raven_compat', )

# Use Whitenoise to serve static files
# See: https://whitenoise.readthedocs.io/
WHITENOISE_MIDDLEWARE = ('whitenoise.middleware.WhiteNoiseMiddleware', )
MIDDLEWARE = WHITENOISE_MIDDLEWARE + MIDDLEWARE
RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware',
                    'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',)
MIDDLEWARE = RAVEN_MIDDLEWARE + MIDDLEWARE

# SECURITY CONFIGURATION
# ------------------------------------------------------------------------------
# See https://docs.djangoproject.com/en/1.9/ref/middleware/#module-django.middleware.security
# and https://docs.djangoproject.com/ja/1.9/howto/deployment/checklist/#run-manage-py-check-deploy

# set this to 60 seconds and then to 518400 when you can prove it works
SECURE_HSTS_SECONDS = 60
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
    'DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True)
SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
    'DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True)
SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
X_FRAME_OPTIONS = 'DENY'

# SITE CONFIGURATION
# ------------------------------------------------------------------------------
# Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['geomat.uni-frankfurt.de'])
# END SITE CONFIGURATION

INSTALLED_APPS += ("gunicorn", )

# STORAGE CONFIGURATION
# ------------------------------------------------------------------------------
# Uploaded Media Files
# ------------------------
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'

# URL that handles the media served from MEDIA_ROOT, used for managing
# stored files.
# TODO: We will change this domain, as soon as the university configures our new one!
MEDIA_URL = 'https://cdn.geomat.idiotism.us/'

# Static Assets
# ------------------------
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# EMAIL
# ------------------------------------------------------------------------------
DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL',
                         default='GU Geomat <noreply@geomat.uni-frankfurt.de>')
EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default='[GU Geomat] ')
SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL)

# Anymail with Mailgun
INSTALLED_APPS += ("anymail",)
ANYMAIL = {
    "MAILGUN_API_KEY": env('DJANGO_MAILGUN_API_KEY'),
    "MAILGUN_SENDER_DOMAIN": env('MAILGUN_SENDER_DOMAIN')
}
EMAIL_BACKEND = "anymail.backends.mailgun.MailgunBackend"

# TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------
# See:
# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader
TEMPLATES[0]['OPTIONS']['loaders'] = [
    ('django.template.loaders.cached.Loader', [
        'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]),
]

# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
DATABASES['default'] = env.db("DATABASE_URL")

# Sentry Configuration
SENTRY_DSN = env('DJANGO_SENTRY_DSN')
SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient')
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'root': {
        'level': 'WARNING',
        'handlers': ['sentry'],
    },
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s '
                      '%(process)d %(thread)d %(message)s'
        },
    },
    'handlers': {
        'sentry': {
            'level': 'ERROR',
            'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        }
    },
    'loggers': {
        'django.db.backends': {
            'level': 'ERROR',
            'handlers': ['console'],
            'propagate': False,
        },
        'raven': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
        'sentry.errors': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
        'django.security.DisallowedHost': {
            'level': 'ERROR',
            'handlers': ['console', 'sentry'],
            'propagate': False,
        },
    },
}
SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO)
RAVEN_CONFIG = {
    'CELERY_LOGLEVEL': env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO),
    'DSN': SENTRY_DSN
}

# Custom Admin URL, use {% url 'admin:index' %}
ADMIN_URL = env('DJANGO_ADMIN_URL')

# Your production stuff: Below this line define 3rd party library settings
<commit_msg>Changed CDN domain to the one provided by the GU.<commit_after># -*- coding: utf-8 -*-
'''
Production Configurations

- Use djangosecure
- Use mailgun to send emails

- Use sentry for error logging

'''
from __future__ import absolute_import, unicode_literals

import logging

from django.utils import six

from .common import *  # noqa

# SECRET CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ
SECRET_KEY = env("DJANGO_SECRET_KEY")

# This ensures that Django will be able to detect a secure connection
# properly on Heroku.
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# raven sentry client
# See https://docs.getsentry.com/hosted/clients/python/integrations/django/
INSTALLED_APPS += ('raven.contrib.django.raven_compat', )

# Use Whitenoise to serve static files
# See: https://whitenoise.readthedocs.io/
WHITENOISE_MIDDLEWARE = ('whitenoise.middleware.WhiteNoiseMiddleware', )
MIDDLEWARE = WHITENOISE_MIDDLEWARE + MIDDLEWARE
RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware',
                    'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',)
MIDDLEWARE = RAVEN_MIDDLEWARE + MIDDLEWARE

# SECURITY CONFIGURATION
# ------------------------------------------------------------------------------
# See https://docs.djangoproject.com/en/1.9/ref/middleware/#module-django.middleware.security
# and https://docs.djangoproject.com/ja/1.9/howto/deployment/checklist/#run-manage-py-check-deploy

# set this to 60 seconds and then to 518400 when you can prove it works
SECURE_HSTS_SECONDS = 60
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
    'DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True)
SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
    'DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True)
SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
X_FRAME_OPTIONS = 'DENY'

# SITE CONFIGURATION
# ------------------------------------------------------------------------------
# Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['geomat.uni-frankfurt.de'])
# END SITE CONFIGURATION

INSTALLED_APPS += ("gunicorn", )

# STORAGE CONFIGURATION
# ------------------------------------------------------------------------------
# Uploaded Media Files
# ------------------------
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'

# URL that handles the media served from MEDIA_ROOT, used for managing
# stored files.
MEDIA_URL = 'https://cdn.geomat.uni-frankfurt.de/'

# Static Assets
# ------------------------
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# EMAIL
# ------------------------------------------------------------------------------
DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL',
                         default='GU Geomat <noreply@geomat.uni-frankfurt.de>')
EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default='[GU GeoMat] ')
SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL)

# Anymail with Mailgun
INSTALLED_APPS += ("anymail",)
ANYMAIL = {
    "MAILGUN_API_KEY": env('DJANGO_MAILGUN_API_KEY'),
    "MAILGUN_SENDER_DOMAIN": env('MAILGUN_SENDER_DOMAIN')
}
EMAIL_BACKEND = "anymail.backends.mailgun.MailgunBackend"

# TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------
# See:
# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader
TEMPLATES[0]['OPTIONS']['loaders'] = [
    ('django.template.loaders.cached.Loader', [
        'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]),
]

# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
DATABASES['default'] = env.db("DATABASE_URL")

# Sentry Configuration
SENTRY_DSN = env('DJANGO_SENTRY_DSN')
SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient')
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'root': {
        'level': 'WARNING',
        'handlers': ['sentry'],
    },
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s '
                      '%(process)d %(thread)d %(message)s'
        },
    },
    'handlers': {
        'sentry': {
            'level': 'ERROR',
            'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        }
    },
    'loggers': {
        'django.db.backends': {
            'level': 'ERROR',
            'handlers': ['console'],
            'propagate': False,
        },
        'raven': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
        'sentry.errors': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
        'django.security.DisallowedHost': {
            'level': 'ERROR',
            'handlers': ['console', 'sentry'],
            'propagate': False,
        },
    },
}
SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO)
RAVEN_CONFIG = {
    'CELERY_LOGLEVEL': env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO),
    'DSN': SENTRY_DSN
}

# Custom Admin URL, use {% url 'admin:index' %}
ADMIN_URL = env('DJANGO_ADMIN_URL')

# Your production stuff: Below this line define 3rd party library settings
<|endoftext|>


<commit_before>import sublime
import sublime_plugin
import os
import subprocess
import re
import tempfile

def syntax_settings(lang, key, default=None):
    settings = sublime.load_settings("SendTextPlus.sublime-settings")
    ret = None
    plat = sublime.platform()
    if lang:
        lang_settings = settings.get(lang)
        os_settings = lang_settings.get(plat)
        if os_settings:
            ret = os_settings.get(key)
        if ret is None:
            ret = lang_settings.get(key)
    if ret is None:
        ret = settings.get("default").get(plat).get(key)
    if ret is None:
        ret = default
    return ret

def clean(cmd):
    cmd = cmd.expandtabs(4)
    cmd = cmd.rstrip('\n')
    if len(re.findall("\n", cmd)) == 0:
        cmd = cmd.lstrip()
    return cmd

def escape_dq(cmd):
    cmd = cmd.replace('\\', '\\\\')
    cmd = cmd.replace('"', '\\"')
    return cmd

def sendtext(prog, cmd):
    if cmd.strip() == "":
        return
    plat = sublime.platform()
    settings = sublime.load_settings("SendTextPlus.sublime-settings")

    if re.match('Terminal', prog):
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        args = ['osascript']
        args.extend(['-e', 'tell app "Terminal" to do script "' + cmd + '" in front window\n'])
        subprocess.Popen(args)

    elif re.match('iTerm', prog):
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        # when cmd ends in a space, iterm does not execute. Thus append a line break.
        if (cmd[-1:] == ' '):
            cmd += '\n'
        try:
            # iterm <2.9
            args = ['osascript', '-e', 'tell app "iTerm" to tell the first terminal '
                    'to tell current session to write text "' + cmd + '"']
            subprocess.check_call(args)
        except:
            # iterm >=2.9
            args = ['osascript', '-e', 'tell app "iTerm" to tell the first terminal window '
                    'to tell current session to write text "' + cmd + '"']
            subprocess.check_call(args)

    elif prog == "tmux":
        cmd = clean(cmd) + "\n"
        progpath = RBoxSettings("tmux", "tmux")
        n = 200
        chunks = [cmd[i:i+n] for i in range(0, len(cmd), n)]
        for chunk in chunks:
            subprocess.call([progpath, 'set-buffer', chunk])
            subprocess.call([progpath, 'paste-buffer', '-d'])

    elif prog == "screen":
        cmd = clean(cmd) + "\n"
        progpath = RBoxSettings("screen", "screen")
        n = 200
        chunks = [cmd[i:i+n] for i in range(0, len(cmd), n)]
        for chunk in chunks:
            if plat == "linux":
                chunk = chunk.replace("\\", r"\\")
                chunk = chunk.replace("$", r"\$")
            subprocess.call([progpath, '-X', 'stuff', chunk])

    elif prog == "SublimeREPL":
        cmd = clean(cmd)
        view = sublime.active_window().active_view()
        external_id = view.scope_name(0).split(" ")[0].split(".", 1)[1]
        sublime.active_window().run_command("repl_send", {"external_id": external_id, "text": cmd})
        return

    if plat == 'windows':
        raise Exception("not yet supported")

class SendTextPlusCommand(sublime_plugin.TextCommand):
    def get_syntax(self):
        view = self.view
        pt = view.sel()[0].begin() if len(view.sel()) > 0 else 0
        if view.score_selector(pt, "source.r"):
            return "r"
        elif view.score_selector(pt, "source.python"):
            return "python"
        elif view.score_selector(pt, "source.julia"):
            return "julia"

    def r_expand_block(self, sel):
        # expand selection to {...} when being triggered
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r".*\{\s*$", thiscmd):
            esel = view.find(
                r"""^(?:.*(\{(?:(["\'])(?:[^\\]|\\.)*?\2|#.*$|[^\{\}]|(?1))*\})[^\{\}\n]*)+""",
                view.line(sel).begin()
            )
            if view.line(sel).begin() == esel.begin():
                sel = esel
        return sel

    def python_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r"^[ \t]*\S", thiscmd):
            indentation = re.match(r"^([ \t]*)", thiscmd).group(1)
            row = view.rowcol(sel.begin())[0]
            prevline = view.line(sel.begin())
            lastrow = view.rowcol(view.size())[0]
            while row < lastrow:
                row = row + 1
                line = view.line(view.text_point(row, 0))
                m = re.match(r"^([ \t]*)([^\n\s]+)", view.substr(line))
                if m and len(m.group(1)) <= len(indentation) and \
                        (len(m.group(1)) < len(indentation) or
                            not re.match(r"else|elif|except|finally", m.group(2))):
                    sel = sublime.Region(sel.begin(), prevline.end())
                    break
                elif re.match(r"^[ \t]*\S", view.substr(line)):
                    prevline = line

            if row == lastrow:
                sel = sublime.Region(sel.begin(), prevline.end())
        return sel

    def julia_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if (re.match(r"^\s*(?:function|if|for|while)", thiscmd) and
                not re.match(r".*end\s*$", thiscmd)) or \
                (re.match(r".*begin\s*$", thiscmd)):
            indentation = re.match("^(\s*)", thiscmd).group(1)
            end = view.find("^"+indentation+"end", sel.begin())
            sel = sublime.Region(sel.begin(), view.line(end.end()).end())

        return sel

    def run(self, edit):
        view = self.view
        syntax = self.get_syntax()
        cmd = ''
        for sel in [s for s in view.sel()]:
            if sel.empty():
                if syntax_settings(syntax, "block", False):
                    if syntax == "r":
                        esel = self.r_expand_block(sel)
                    elif syntax == "python":
                        esel = self.python_expand_block(sel)
                    elif syntax == "julia":
                        esel = self.julia_expand_block(sel)

                    thiscmd = view.substr(view.line(esel))
                    line = view.rowcol(esel.end())[0]
                else:
                    thiscmd = view.substr(view.line(sel))
                    line = view.rowcol(sel.end())[0]

                if syntax_settings(syntax, "auto_advance", False):
                    view.sel().subtract(sel)
                    pt = view.text_point(line+1, 0)
                    view.sel().add(sublime.Region(pt, pt))
            else:
                thiscmd = view.substr(sel)
            cmd += thiscmd + '\n'

        # ipython wrapper
        if syntax == "python" and syntax_settings(syntax, "ipython", False):
            cmd = clean(cmd)
            if len(re.findall("\n", cmd)) > 0:
                cmd = "%cpaste\n" + cmd + "\n--"

        prog = syntax_settings(syntax, "prog")
        sendtext(prog, cmd)

        if syntax_settings(syntax, "auto_advance", False):
            view.show(view.sel())

class SendTextPlusChangeDirCommand(sublime_plugin.TextCommand):
    def get_syntax(self):
        view = self.view
        pt = view.sel()[0].begin() if len(view.sel()) > 0 else 0
        if view.score_selector(pt, "source.r"):
            return "r"
        elif view.score_selector(pt, "source.python"):
            return "python"
        elif view.score_selector(pt, "source.julia"):
            return "julia"

    def run(self, edit):
        fname = self.view.file_name()
        if not fname:
            sublime.error_message("Save the file!")
            return

        dirname = os.path.dirname(fname)
        syntax = self.get_syntax()
        prog = syntax_settings(syntax, "prog")

        if syntax == "r":
            cmd = "setwd(\"" + escape_dq(dirname) + "\")"
        elif syntax == "julia":
            cmd = "cd(\"" + escape_dq(dirname) + "\")"
        elif syntax == "python" and syntax_settings(syntax, "ipython", False):
            cmd = "cd \"" + escape_dq(dirname) + "\""
        sendtext(prog, cmd + "\n")
<commit_msg>bug fix<commit_after>import sublime
import sublime_plugin
import os
import subprocess
import re
import tempfile

def syntax_settings(lang, key, default=None):
    settings = sublime.load_settings("SendTextPlus.sublime-settings")
    ret = None
    plat = sublime.platform()
    if lang:
        lang_settings = settings.get(lang)
        os_settings = lang_settings.get(plat)
        if os_settings:
            ret = os_settings.get(key)
        if ret is None:
            ret = lang_settings.get(key)
    if ret is None:
        ret = settings.get("default").get(plat).get(key)
    if ret is None:
        ret = default
    return ret

def clean(cmd):
    cmd = cmd.expandtabs(4)
    cmd = cmd.rstrip('\n')
    if len(re.findall("\n", cmd)) == 0:
        cmd = cmd.lstrip()
    return cmd

def escape_dq(cmd):
    cmd = cmd.replace('\\', '\\\\')
    cmd = cmd.replace('"', '\\"')
    return cmd

def sendtext(prog, cmd):
    if cmd.strip() == "":
        return
    plat = sublime.platform()
    settings = sublime.load_settings("SendTextPlus.sublime-settings")

    if re.match('Terminal', prog):
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        args = ['osascript']
        args.extend(['-e', 'tell app "Terminal" to do script "' + cmd + '" in front window\n'])
        subprocess.Popen(args)

    elif re.match('iTerm', prog):
        cmd = clean(cmd)
        cmd = escape_dq(cmd)
        # when cmd ends in a space, iterm does not execute. Thus append a line break.
        if (cmd[-1:] == ' '):
            cmd += '\n'
        try:
            # iterm <2.9
            args = ['osascript', '-e', 'tell app "iTerm" to tell the first terminal '
                    'to tell current session to write text "' + cmd + '"']
            subprocess.check_call(args)
        except:
            # iterm >=2.9
            args = ['osascript', '-e', 'tell app "iTerm" to tell the first terminal window '
                    'to tell current session to write text "' + cmd + '"']
            subprocess.check_call(args)

    elif prog == "tmux":
        cmd = clean(cmd) + "\n"
        progpath = settings.get("tmux", "tmux")
        n = 200
        chunks = [cmd[i:i+n] for i in range(0, len(cmd), n)]
        for chunk in chunks:
            subprocess.call([progpath, 'set-buffer', chunk])
            subprocess.call([progpath, 'paste-buffer', '-d'])

    elif prog == "screen":
        cmd = clean(cmd) + "\n"
        progpath = settings.get("screen", "screen")
        n = 200
        chunks = [cmd[i:i+n] for i in range(0, len(cmd), n)]
        for chunk in chunks:
            if plat == "linux":
                chunk = chunk.replace("\\", r"\\")
                chunk = chunk.replace("$", r"\$")
            subprocess.call([progpath, '-X', 'stuff', chunk])

    elif prog == "SublimeREPL":
        cmd = clean(cmd)
        view = sublime.active_window().active_view()
        external_id = view.scope_name(0).split(" ")[0].split(".", 1)[1]
        sublime.active_window().run_command("repl_send", {"external_id": external_id, "text": cmd})
        return

    if plat == 'windows':
        raise Exception("not yet supported")

class SendTextPlusCommand(sublime_plugin.TextCommand):
    def get_syntax(self):
        view = self.view
        pt = view.sel()[0].begin() if len(view.sel()) > 0 else 0
        if view.score_selector(pt, "source.r"):
            return "r"
        elif view.score_selector(pt, "source.python"):
            return "python"
        elif view.score_selector(pt, "source.julia"):
            return "julia"

    def r_expand_block(self, sel):
        # expand selection to {...} when being triggered
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r".*\{\s*$", thiscmd):
            esel = view.find(
                r"""^(?:.*(\{(?:(["\'])(?:[^\\]|\\.)*?\2|#.*$|[^\{\}]|(?1))*\})[^\{\}\n]*)+""",
                view.line(sel).begin()
            )
            if view.line(sel).begin() == esel.begin():
                sel = esel
        return sel

    def python_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if re.match(r"^[ \t]*\S", thiscmd):
            indentation = re.match(r"^([ \t]*)", thiscmd).group(1)
            row = view.rowcol(sel.begin())[0]
            prevline = view.line(sel.begin())
            lastrow = view.rowcol(view.size())[0]
            while row < lastrow:
                row = row + 1
                line = view.line(view.text_point(row, 0))
                m = re.match(r"^([ \t]*)([^\n\s]+)", view.substr(line))
                if m and len(m.group(1)) <= len(indentation) and \
                        (len(m.group(1)) < len(indentation) or
                            not re.match(r"else|elif|except|finally", m.group(2))):
                    sel = sublime.Region(sel.begin(), prevline.end())
                    break
                elif re.match(r"^[ \t]*\S", view.substr(line)):
                    prevline = line

            if row == lastrow:
                sel = sublime.Region(sel.begin(), prevline.end())
        return sel

    def julia_expand_block(self, sel):
        view = self.view
        thiscmd = view.substr(view.line(sel))
        if (re.match(r"^\s*(?:function|if|for|while)", thiscmd) and
                not re.match(r".*end\s*$", thiscmd)) or \
                (re.match(r".*begin\s*$", thiscmd)):
            indentation = re.match("^(\s*)", thiscmd).group(1)
            end = view.find("^"+indentation+"end", sel.begin())
            sel = sublime.Region(sel.begin(), view.line(end.end()).end())

        return sel

    def run(self, edit):
        view = self.view
        syntax = self.get_syntax()
        cmd = ''
        for sel in [s for s in view.sel()]:
            if sel.empty():
                if syntax_settings(syntax, "block", False):
                    if syntax == "r":
                        esel = self.r_expand_block(sel)
                    elif syntax == "python":
                        esel = self.python_expand_block(sel)
                    elif syntax == "julia":
                        esel = self.julia_expand_block(sel)

                    thiscmd = view.substr(view.line(esel))
                    line = view.rowcol(esel.end())[0]
                else:
                    thiscmd = view.substr(view.line(sel))
                    line = view.rowcol(sel.end())[0]

                if syntax_settings(syntax, "auto_advance", False):
                    view.sel().subtract(sel)
                    pt = view.text_point(line+1, 0)
                    view.sel().add(sublime.Region(pt, pt))
            else:
                thiscmd = view.substr(sel)
            cmd += thiscmd + '\n'

        # ipython wrapper
        if syntax == "python" and syntax_settings(syntax, "ipython", False):
            cmd = clean(cmd)
            if len(re.findall("\n", cmd)) > 0:
                cmd = "%cpaste\n" + cmd + "\n--"

        prog = syntax_settings(syntax, "prog")
        sendtext(prog, cmd)

        if syntax_settings(syntax, "auto_advance", False):
            view.show(view.sel())

class SendTextPlusChangeDirCommand(sublime_plugin.TextCommand):
    def get_syntax(self):
        view = self.view
        pt = view.sel()[0].begin() if len(view.sel()) > 0 else 0
        if view.score_selector(pt, "source.r"):
            return "r"
        elif view.score_selector(pt, "source.python"):
            return "python"
        elif view.score_selector(pt, "source.julia"):
            return "julia"

    def run(self, edit):
        fname = self.view.file_name()
        if not fname:
            sublime.error_message("Save the file!")
            return

        dirname = os.path.dirname(fname)
        syntax = self.get_syntax()
        prog = syntax_settings(syntax, "prog")

        if syntax == "r":
            cmd = "setwd(\"" + escape_dq(dirname) + "\")"
        elif syntax == "julia":
            cmd = "cd(\"" + escape_dq(dirname) + "\")"
        elif syntax == "python" and syntax_settings(syntax, "ipython", False):
            cmd = "cd \"" + escape_dq(dirname) + "\""
        sendtext(prog, cmd + "\n")
<|endoftext|>