<NME> floobits.py
<BEF> # coding: utf-8
import sys
import os
import time
import subprocess
import threading

import sublime

PY2 = sys.version_info < (3, 0)
SOCK_SINGLE_READ = False

if PY2 and sublime.platform() == 'windows':
    try:
        import select
        assert select
        # Change behavior of some low-level socket stuff so that we don't break
        SOCK_SINGLE_READ = True
    except Exception as e:
        err_msg = '''Sorry, but the Windows version of Sublime Text 2 lacks Python's select module, so the Floobits plugin won't work.
Please upgrade to Sublime Text 3 or install Package Control 3. :('''
        raise(Exception(err_msg))
elif sublime.platform() == 'osx':
    try:
        p = subprocess.Popen(['/usr/bin/sw_vers', '-productVersion'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        result = p.communicate()
        versions = result[0].decode('utf-8').split('.')
        major = float(versions[0])
        minor = float(versions[1])
        print('Floobits detected macos %.0f.%.0f' % (major, minor))
        if major < 11 and minor < 7:
            sublime.error_message('''Sorry, but the Floobits plugin doesn\'t work on 10.6 or earlier.
Please upgrade your operating system if you want to use this plugin. :(''')
    except Exception as e:
        print(e)

try:
    from .floo import version
    from .floo.listener import Listener
    from .floo.common import reactor, shared as G, utils
    from .floo.common.exc_fmt import str_e
    assert utils
except (ImportError, ValueError):
    from floo import version
    from floo.listener import Listener
    from floo.common import reactor, shared as G, utils
    from floo.common.exc_fmt import str_e
assert Listener and version

reactor = reactor.reactor
called_plugin_loaded = False


def setup():
    def _setup():
        # stupid yielding loop until we get a window from st2
        w = sublime.active_window()
        if w is None:
            return sublime.set_timeout(_setup, 50)

        try:
            settings = sublime.load_settings('Floobits.sublime-settings')
            now = time.time()
            old_time = settings.get('floobits-id')
            settings.set('floobits-id', now)
            interval = utils.set_interval(reactor.tick, G.TICK_TIME)

            def shutdown():
                print('Floobits plugin updated. Shutting down old instance.', old_time)
                try:
                    utils.cancel_timeout(interval)
                except Exception:
                    pass

            try:
                settings.clear_on_change('floobits-id')
            except Exception:
                pass
            settings.add_on_change('floobits-id', shutdown)
            w.run_command('floobits_setup')
        except Exception as e:
            print(str_e(e))

    # hop into main thread
    sublime.set_timeout(_setup, 50)


# Sublime 3 calls this once the plugin API is ready
def plugin_loaded():
    global called_plugin_loaded
    if called_plugin_loaded:
        return
    called_plugin_loaded = True
    print('Floobits: Called plugin_loaded.')

    utils.reload_settings()

    G.SOCK_SINGLE_READ = SOCK_SINGLE_READ

    # TODO: one day this can be removed (once all our users have updated)
    old_colab_dir = os.path.realpath(os.path.expanduser(os.path.join('~', '.floobits')))
    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):
        print('Renaming %s to %s' % (old_colab_dir, G.BASE_DIR))
        os.rename(old_colab_dir, G.BASE_DIR)
        os.symlink(G.BASE_DIR, old_colab_dir)

    try:
        utils.normalize_persistent_data()
    except Exception as e:
        print('Floobits: Error normalizing persistent data:', str_e(e))
        # Keep on truckin' I guess

    d = utils.get_persistent_data()
    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)
    setup()


# Sublime 2 has no way to know when plugin API is ready. Horrible hack here.
if PY2:
    for i in range(0, 20):
        threading.Timer(i, utils.set_timeout, [plugin_loaded, 1]).start()

    def warning():
        if not called_plugin_loaded:
            print('Your computer is slow and could not start the Floobits reactor. ' +
                  'Please contact us (support@floobits.com) or upgrade to Sublime Text 3.')
    threading.Timer(20, warning).start()

    @staticmethod
    def put(item):
        if not item:
            return
        SOCKET_Q.put(item + '\n')

    @staticmethod
    def push():
        reported = set()
        while Listener.views_changed:
            view = Listener.views_changed.pop()

    @staticmethod
    def apply_patch(patch_data):
        buf_id = patch_data['id']
        path = get_full_path(patch_data['path'])
        view = BUF_IDS_TO_VIEWS.get(buf_id)

    @staticmethod
    def update_buf(buf_id, path, text, md5, view=None):
        global READ_ONLY
        path = get_full_path(path)
        if not view:
            view = BUF_IDS_TO_VIEWS.get(buf_id)

<MSG> Oh hey. Python has this global keyword that we might want to use when trying to modify global variables

<DFF> @@ -129,6 +129,7 @@ class AgentConnection(object):
 
     @staticmethod
     def put(item):
+        global SOCKET_Q
         if not item:
             return
         SOCKET_Q.put(item + '\n')
@@ -270,6 +271,7 @@ class Listener(sublime_plugin.EventListener):
 
     @staticmethod
     def push():
+        global BUF_STATE
         reported = set()
         while Listener.views_changed:
             view = Listener.views_changed.pop()
@@ -303,6 +305,7 @@ class Listener(sublime_plugin.EventListener):
 
     @staticmethod
     def apply_patch(patch_data):
+        global BUF_IDS_TO_VIEWS, BUF_STATE, MODIFIED_EVENTS
         buf_id = patch_data['id']
         path = get_full_path(patch_data['path'])
         view = BUF_IDS_TO_VIEWS.get(buf_id)
@@ -380,7 +383,7 @@ class Listener(sublime_plugin.EventListener):
 
     @staticmethod
     def update_buf(buf_id, path, text, md5, view=None):
-        global READ_ONLY
+        global BUF_IDS_TO_VIEWS, BUF_STATE, MODIFIED_EVENTS, READ_ONLY
         path = get_full_path(path)
         if not view:
             view = BUF_IDS_TO_VIEWS.get(buf_id)

{'commit': "diff --git a/floobits.py b/floobits.py\nindex 7a7ead6..57293c3 100644\n--- a/floobits.py\n+++ b/floobits.py\n@@ -129,6 +129,7 @@ class AgentConnection(object):\n \n     @staticmethod\n     def put(item):\n+        global SOCKET_Q\n         if not item:\n             return\n         SOCKET_Q.put(item + '\\n')\n@@ -270,6 +271,7 @@ class Listener(sublime_plugin.EventListener):\n \n     @staticmethod\n     def push():\n+        global BUF_STATE\n         reported = set()\n         while Listener.views_changed:\n             view = Listener.views_changed.pop()\n@@ -303,6 +305,7 @@ class Listener(sublime_plugin.EventListener):\n \n     @staticmethod\n     def apply_patch(patch_data):\n+        global BUF_IDS_TO_VIEWS, BUF_STATE, MODIFIED_EVENTS\n         buf_id = patch_data['id']\n         path = get_full_path(patch_data['path'])\n         view = BUF_IDS_TO_VIEWS.get(buf_id)\n@@ -380,7 +383,7 @@ class Listener(sublime_plugin.EventListener):\n \n     @staticmethod\n     def update_buf(buf_id, path, text, md5, view=None):\n-        global READ_ONLY\n+        global BUF_IDS_TO_VIEWS, BUF_STATE, MODIFIED_EVENTS, READ_ONLY\n         path = get_full_path(path)\n         if not view:\n             view = BUF_IDS_TO_VIEWS.get(buf_id)\n", 'commit_subject': 'Oh hey. Python has this global keyword that we might want to use when trying to modify global variables', 'repo_name': 'Floobits/floobits-sublime', 'committer': {'name': 'Geoff Greer', 'email': 'c3918f39022407dee6a0056ceca9b1aa80e8e4ce@greer.fm', 'time_sec': '1353776507', 'tz_offset': '-480', 'date': {'seconds': '1353776507'}}, 'commit_tree': '7af47eabfcd9e50d44ef582ee8c0738879a22d08', 'commit_message': 'Oh hey. Python has this global keyword that we might want to use when trying to modify global variables\n', 'language_name': 'Python', 'license': 'apache-2.0', 'hunks': "@@ -129,6 +129,7 @@ class AgentConnection(object):\n \n     @staticmethod\n     def put(item):\n+        global SOCKET_Q\n         if not item:\n             return\n         SOCKET_Q.put(item + '\\n')\n@@ -270,6 +271,7 @@ class Listener(sublime_plugin.EventListener):\n \n     @staticmethod\n     def push():\n+        global BUF_STATE\n         reported = set()\n         while Listener.views_changed:\n             view = Listener.views_changed.pop()\n@@ -303,6 +305,7 @@ class Listener(sublime_plugin.EventListener):\n \n     @staticmethod\n     def apply_patch(patch_data):\n+        global BUF_IDS_TO_VIEWS, BUF_STATE, MODIFIED_EVENTS\n         buf_id = patch_data['id']\n         path = get_full_path(patch_data['path'])\n         view = BUF_IDS_TO_VIEWS.get(buf_id)\n@@ -380,7 +383,7 @@ class Listener(sublime_plugin.EventListener):\n \n     @staticmethod\n     def update_buf(buf_id, path, text, md5, view=None):\n-        global READ_ONLY\n+        global BUF_IDS_TO_VIEWS, BUF_STATE, MODIFIED_EVENTS, READ_ONLY\n         path = get_full_path(path)\n         if not view:\n             view = BUF_IDS_TO_VIEWS.get(buf_id)\n", 'addition_count': 4, 'deletion_count': 1, 'src_file': 'a/floobits.py', 'tgt_file': 'b/floobits.py', 'file_extension': '.py', 'before_file': "# coding: utf-8\nimport sys\nimport os\nimport time\nimport subprocess\nimport threading\n\nimport sublime\n\nPY2 = sys.version_info < (3, 0)\nSOCK_SINGLE_READ = False\n\nif PY2 and sublime.platform() == 'windows':\n    try:\n        import select\n        assert select\n        # Change behavior of some low-level socket stuff so that we don't break\n        SOCK_SINGLE_READ = True\n    except Exception as e:\n        err_msg = '''Sorry, but the Windows version of Sublime Text 2 lacks Python's select module, so the Floobits plugin won't work.\nPlease upgrade to Sublime Text 3 or install Package Control 3. :('''\n        raise(Exception(err_msg))\nelif sublime.platform() == 'osx':\n    try:\n        p = subprocess.Popen(['/usr/bin/sw_vers', '-productVersion'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n        result = p.communicate()\n        versions = result[0].decode('utf-8').split('.')\n        major = float(versions[0])\n        minor = float(versions[1])\n        print('Floobits detected macos %.0f.%.0f' % (major, minor))\n        if major < 11 and minor < 7:\n            sublime.error_message('''Sorry, but the Floobits plugin doesn\\'t work on 10.6 or earlier.\nPlease upgrade your operating system if you want to use this plugin. :(''')\n    except Exception as e:\n        print(e)\n\ntry:\n    from .floo import version\n    from .floo.listener import Listener\n    from .floo.common import reactor, shared as G, utils\n    from .floo.common.exc_fmt import str_e\n    assert utils\nexcept (ImportError, ValueError):\n    from floo import version\n    from floo.listener import Listener\n    from floo.common import reactor, shared as G, utils\n    from floo.common.exc_fmt import str_e\nassert Listener and version\n\nreactor = reactor.reactor\ncalled_plugin_loaded = False\n\n\ndef setup():\n    def _setup():\n        # stupid yielding loop until we get a window from st2\n        w = sublime.active_window()\n        if w is None:\n            return sublime.set_timeout(_setup, 50)\n\n        try:\n            settings = sublime.load_settings('Floobits.sublime-settings')\n            now = time.time()\n            old_time = settings.get('floobits-id')\n            settings.set('floobits-id', now)\n            interval = utils.set_interval(reactor.tick, G.TICK_TIME)\n\n            def shutdown():\n                print('Floobits plugin updated. Shutting down old instance.', old_time)\n                try:\n                    utils.cancel_timeout(interval)\n                except Exception:\n                    pass\n\n            try:\n                settings.clear_on_change('floobits-id')\n            except Exception:\n                pass\n            settings.add_on_change('floobits-id', shutdown)\n            w.run_command('floobits_setup')\n        except Exception as e:\n            print(str_e(e))\n\n    # hop into main thread\n    sublime.set_timeout(_setup, 50)\n\n\n# Sublime 3 calls this once the plugin API is ready\ndef plugin_loaded():\n    global called_plugin_loaded\n    if called_plugin_loaded:\n        return\n    called_plugin_loaded = True\n    print('Floobits: Called plugin_loaded.')\n\n    utils.reload_settings()\n\n    G.SOCK_SINGLE_READ = SOCK_SINGLE_READ\n\n    # TODO: one day this can be removed (once all our users have updated)\n    old_colab_dir = os.path.realpath(os.path.expanduser(os.path.join('~', '.floobits')))\n    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):\n        print('Renaming %s to %s' % (old_colab_dir, G.BASE_DIR))\n        os.rename(old_colab_dir, G.BASE_DIR)\n        os.symlink(G.BASE_DIR, old_colab_dir)\n\n    try:\n        utils.normalize_persistent_data()\n    except Exception as e:\n        print('Floobits: Error normalizing persistent data:', str_e(e))\n        # Keep on truckin' I guess\n\n    d = utils.get_persistent_data()\n    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)\n    setup()\n\n\n# Sublime 2 has no way to know when plugin API is ready. Horrible hack here.\nif PY2:\n    for i in range(0, 20):\n        threading.Timer(i, utils.set_timeout, [plugin_loaded, 1]).start()\n\n    def warning():\n        if not called_plugin_loaded:\n            print('Your computer is slow and could not start the Floobits reactor. ' +\n                  'Please contact us (support@floobits.com) or upgrade to Sublime Text 3.')\n    threading.Timer(20, warning).start()\n\n    @staticmethod\n    def put(item):\n        if not item:\n            return\n        SOCKET_Q.put(item + '\\n')\n\n    @staticmethod\n    def push():\n        reported = set()\n        while Listener.views_changed:\n            view = Listener.views_changed.pop()\n\n    @staticmethod\n    def apply_patch(patch_data):\n        buf_id = patch_data['id']\n        path = get_full_path(patch_data['path'])\n        view = BUF_IDS_TO_VIEWS.get(buf_id)\n\n    @staticmethod\n    def update_buf(buf_id, path, text, md5, view=None):\n        global READ_ONLY\n        path = get_full_path(path)\n        if not view:\n            view = BUF_IDS_TO_VIEWS.get(buf_id)\n", 'message': 'Oh hey. Python has this global keyword that we might want to use when trying to modify global variables\n', 'author_name': 'Geoff Greer', 'lang': 'py'}