def summon(self, subl_view):
        if 'highlight' not in G.PERMS:
            return
        buf = get_buf(subl_view)
        if buf:
            msg.debug('summoning selection in subl_view ', buf['path'], ', buf id ', buf['id'])
            c = [[x.a, x.b] for x in subl_view.sel()]
            if self.joined_workspace:
                self.send({
                    'id': buf['id'],
                    'name': 'highlight',
                    'ranges': c,
                    'ping': True,
                    'summon': True,
                    'following': False,
                })
            return

        path = subl_view.file_name()
        if not utils.is_shared(path):
            sublime.error_message('Can\'t summon because %s is not in shared path %s.' % (path, G.PROJECT_PATH))
            return
        share = sublime.ok_cancel_dialog('This file isn\'t shared. Would you like to share it?', 'Share')
        if share:
            sel = [[x.a, x.b] for x in subl_view.sel()]
            self.create_buf_cbs[utils.to_rel_path(path)] = lambda buf_id: send_summon(buf_id, sel)
            self.upload(path)
Example #2
0
 def set_text(self, text):
     msg.debug('\n\nabout to patch %s %s' % (str(self), self.vim_buf.name))
     try:
         self.vim_buf[:] = text.encode('utf-8').split('\n')
     except Exception as e:
         msg.error("couldn't apply patches because: %s!\nThe unencoded text was: %s" % (str(e), text))
         raise
    def _connect(self, attempts=0):
        if attempts > 500:
            msg.error('Connection attempt timed out.')
            return self.reconnect()
        if not self.sock:
            msg.debug('_connect: No socket')
            return
        try:
            self.sock.connect((self.host, self.port))
            select.select([self.sock], [self.sock], [], 0)
        except socket.error as e:
            if e.errno == iscon_errno:
                pass
            elif e.errno in connect_errno:
                return utils.set_timeout(self._connect, 20, attempts + 1)
            else:
                msg.error('Error connecting:', e)
                return self.reconnect()
        if self.secure:
            sock_debug('SSL-wrapping socket')
            self.sock = ssl.wrap_socket(self.sock, ca_certs=self.cert_path, cert_reqs=ssl.CERT_REQUIRED, do_handshake_on_connect=False)

        self.on_connect()
        self.call_select = True
        self.select()
Example #4
0
 def _on_highlight(self, data):
     buf_id = data['id']
     user_id = data['user_id']
     username = data.get('username', 'an unknown user')
     ping = G.STALKER_MODE or data.get('ping', False)
     previous_highlight = self.user_highlights.get(user_id)
     buf = self.bufs[buf_id]
     view = self.get_view(buf_id)
     if not view:
         if not ping:
             return
         view = self.create_view(buf)
         if not view:
             return
     data['path'] = buf['path']
     self.user_highlights[user_id] = data
     if ping:
         try:
             offset = data['ranges'][0][0]
         except IndexError as e:
             msg.debug('could not get offset from range %s' % e)
         else:
             if data.get('ping'):
                 msg.log('You have been summoned by %s' % (username))
             view.focus()
             view.set_cursor_position(offset)
     if G.SHOW_HIGHLIGHTS:
         if previous_highlight and previous_highlight['id'] == data['id']:
             view.clear_highlight(user_id)
         view.highlight(data['ranges'], user_id)
Example #5
0
 def on_activated(self, view, agent):
     buf = get_buf(view)
     if not buf:
         return
     msg.debug('activated view ', buf['path'], ' buf id ', buf['id'])
     self.on_modified(view, agent, True)
     self.on_selection_modified(view)
Example #6
0
 def set_cursor_position(self, offset):
     line_num, col = self._offset_to_vim(offset)
     command = 'setpos(".", [%s, %s, %s, %s])' % (self.native_id, line_num, col, 0)
     msg.debug("setting pos: %s" % command)
     rv = int(vim.eval(command))
     if rv != 0:
         msg.debug('SHIIIIIIIIT %s' % rv)
 def clear_highlights(self, view):
     buf = get_buf(view)
     if not buf:
         return
     msg.debug('clearing highlights in ', buf['path'], ', buf id ', buf['id'])
     for user_id, username in self.workspace_info['users'].items():
         view.erase_regions('floobits-highlight-%s' % user_id)
 def clear_highlights(self, view):
     buf = get_buf(view)
     if not buf:
         return
     msg.debug("clearing highlights in %s, buf id %s" % (buf["path"], buf["id"]))
     for user_id, username in self.workspace_info["users"].items():
         view.erase_regions("floobits-highlight-%s" % user_id)
Example #9
0
def open_workspace_window2(abs_path, cb):
    if sublime.platform() == 'linux':
        subl = open('/proc/self/cmdline').read().split(chr(0))[0]
    elif sublime.platform() == 'osx':
        floorc = utils.load_floorc_json()
        subl = floorc.get('SUBLIME_EXECUTABLE')
        if not subl:
            settings = sublime.load_settings('Floobits.sublime-settings')
            subl = settings.get('sublime_executable', '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl')
        if not os.path.exists(subl):
            return sublime.error_message('''Can't find your Sublime Text executable at %s.
Please add "sublime_executable": "/path/to/subl" to your ~/.floorc.json and restart Sublime Text''' % subl)
    elif sublime.platform() == 'windows':
        subl = sys.executable
    else:
        raise Exception('WHAT PLATFORM ARE WE ON?!?!?')

    command = [subl]
    if get_workspace_window(abs_path) is None:
        command.append('--new-window')
    command.append('--add')
    command.append(G.PROJECT_PATH)

    msg.debug('command:', command)
    p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poll_result = p.poll()
    msg.debug('poll:', poll_result)
    cb()
 def put(self, item):
     if not item:
         return
     self.sock_q.put(json.dumps(item) + "\n")
     qsize = self.sock_q.qsize()
     if qsize > 0:
         msg.debug("%s items in q" % qsize)
 def connect(self, cb=None):
     self.stop(False)
     self.empty_selects = 0
     self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     if self.secure:
         if ssl:
             cert_path = os.path.join(G.COLAB_DIR, "startssl-ca.pem")
             with open(cert_path, "wb") as cert_fd:
                 cert_fd.write(cert.CA_CERT.encode("utf-8"))
             self.sock = ssl.wrap_socket(self.sock, ca_certs=cert_path, cert_reqs=ssl.CERT_REQUIRED)
         else:
             msg.log("No SSL module found. Connection will not be encrypted.")
             if self.port == G.DEFAULT_PORT:
                 self.port = 3148  # plaintext port
     msg.debug("Connecting to %s:%s" % (self.host, self.port))
     try:
         self.sock.connect((self.host, self.port))
         if self.secure and ssl:
             self.sock.do_handshake()
     except socket.error as e:
         msg.error("Error connecting:", e)
         self.reconnect()
         return
     self.sock.setblocking(0)
     msg.debug("Connected!")
     self.reconnect_delay = self.INITIAL_RECONNECT_DELAY
     self.send_auth()
     if cb:
         cb()
Example #12
0
 def clear_highlight(self, user_id):
     msg.debug('clearing selections for user %s in view %s' % (user_id, self.vim_buf.name))
     if user_id not in self.current_highlights:
         return
     for hl in self.current_highlights[user_id]:
         vim.command(":silent! :call matchdelete(%s)" % (hl,))
     del self.current_highlights[user_id]
Example #13
0
 def rename(self, name):
     msg.debug("renaming %s" % name)
     self._emacs.send({
         'name': 'rename',
         'new_name': name,
         'full_path': self.full_path
     })
Example #14
0
 def on_highlight(self, data):
     #     floobits.highlight(data['id'], region_key, data['username'], data['ranges'], data.get('ping', False))
     #buf_id, region_key, username, ranges, ping=False):
     ping = data.get('ping', False)
     if self.follow_mode:
         ping = True
     buf = self.FLOO_BUFS[data['id']]
     view = self.get_view(data['id'])
     if not view:
         if not ping:
             return
         view = self.create_view(buf)
         if not view:
             return
     if ping:
         try:
             offset = data['ranges'][0][0]
         except IndexError as e:
             msg.debug('could not get offset from range %s' % e)
         else:
             msg.log('You have been summoned by %s' % (data.get('username', 'an unknown user')))
             view.focus()
             view.set_cursor_position(offset)
     if G.SHOW_HIGHLIGHTS:
         view.highlight(data['ranges'], data['user_id'])
Example #15
0
    def _scan_dir(ig):
        path = ig.path

        if not utils.is_shared(path):
            msg.error('Skipping adding %s because it is not in shared path %s.' % (path, G.PROJECT_PATH))
            return
        ignored = ig.is_ignored(path)
        if ignored:
            msg.log('Not creating buf: %s' % (ignored))
            return

        msg.debug('create_buf: path is %s' % path)

        if not os.path.isdir(path):
            yield path
            return

        try:
            paths = os.listdir(path)
        except Exception as e:
            msg.error('Error listing path %s: %s' % (path, unicode(e)))
            return
        for p in paths:
            p_path = os.path.join(path, p)
            if p[0] == '.':
                if p not in ignore.HIDDEN_WHITELIST:
                    msg.log('Not creating buf for hidden path %s' % p_path)
                    continue
            ignored = ig.is_ignored(p_path)
            if ignored:
                msg.log('Not creating buf: %s' % (ignored))
                continue

            yield p_path
Example #16
0
def open_workspace_window2(abs_path, cb):
    if sublime.platform() == "linux":
        subl = open("/proc/self/cmdline").read().split(chr(0))[0]
    elif sublime.platform() == "osx":
        floorc = utils.load_floorc_json()
        subl = floorc.get("SUBLIME_EXECUTABLE")
        if not subl:
            settings = sublime.load_settings("Floobits.sublime-settings")
            subl = settings.get(
                "sublime_executable", "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl"
            )
        if not os.path.exists(subl):
            return sublime.error_message(
                """Can't find your Sublime Text executable at %s.
Please add "sublime_executable": "/path/to/subl" to your ~/.floorc.json and restart Sublime Text"""
                % subl
            )
    elif sublime.platform() == "windows":
        subl = sys.executable
    else:
        raise Exception("WHAT PLATFORM ARE WE ON?!?!?")

    command = [subl]
    if get_workspace_window(abs_path) is None:
        command.append("--new-window")
    command.append("--add")
    command.append(G.PROJECT_PATH)

    msg.debug("command:", command)
    p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poll_result = p.poll()
    msg.debug("poll:", poll_result)
    cb()
Example #17
0
 def put(self, item):
     if not item:
         return
     self.sock_q.put(json.dumps(item) + '\n')
     qsize = self.sock_q.qsize()
     if qsize > 0:
         msg.debug('%s items in q' % qsize)
Example #18
0
 def on_rename_buf(self, data):
     buf = self.FLOO_BUFS[int(data['id'])]
     # This can screw up if someone else renames the buffer around the same time as us. Oh well.
     buf = self.get_buf_by_path(utils.get_full_path(data['path']))
     if not buf:
         return super(Protocol, self).on_rename_buf(data)
     msg.debug('We already renamed %s. Skipping' % buf['path'])
Example #19
0
    def _set_highlight(self, ranges, user_id):
        msg.debug('highlighting ranges %s' % (ranges))
        if vim.current.buffer.number != self.vim_buf.number:
            return
        region = user_id_to_region(user_id)

        hl_rule = HL_RULES[user_id % len(HL_RULES)]
        vim.command(":silent! highlight %s %s" % (region, hl_rule))

        self.clear_highlight(user_id)

        for _range in ranges:
            start_row, start_col = self._offset_to_vim(_range[0])
            end_row, end_col = self._offset_to_vim(_range[1])
            if start_row == end_row and start_col == end_col:
                if end_col >= len(self.vim_buf[end_row - 1]):
                    end_row += 1
                    end_col = 1
                else:
                    end_col += 1
            vim_region = "matchadd('{region}', '\%{start_row}l\%{start_col}v\_.*\%{end_row}l\%{end_col}v', 100)".\
                format(region=region, start_row=start_row, start_col=start_col, end_row=end_row, end_col=end_col)
            msg.debug("vim_region: %s" % (vim_region,))
            self.current_highlights[user_id].append(vim.eval(vim_region))
        redraw()
Example #20
0
 def _on_delete_buf(self, req):
     buf = self.get_buf_by_path(req["path"])
     if not buf:
         msg.debug("No buffer for path %s" % req["path"])
         return
     msg.log("deleting buffer ", buf["path"])
     self.send_to_floobits({"name": "delete_buf", "id": buf["id"]})
Example #21
0
 def update_view(self, buf, view=None):
     msg.debug('updating view for buf %s' % buf['id'])
     view = view or self.get_view(buf['id'])
     if not view:
         msg.log('view for buf %s not found. not updating' % buf['id'])
         return
     self.MODIFIED_EVENTS.put(1)
     view.set_text(buf['buf'])
 def put(item):
     if not item:
         return
     msg.debug('writing %s: %s' % (item.get('name', 'NO NAME'), item))
     SOCKET_Q.append(json.dumps(item) + '\n')
     qsize = len(SOCKET_Q)
     if qsize > 0:
         msg.debug('%s items in q' % qsize)
Example #23
0
 def maybe_selection_changed(self, vim_buf, is_ping):
     buf = self.get_buf(vim_buf)
     if not buf:
         msg.debug('no buffer found for view %s' % vim_buf.number)
         return
     view = self.get_view(buf['id'])
     msg.debug("selection changed: %s %s %s" % (vim_buf.number, buf['id'], view))
     self.SELECTION_CHANGED.append([view, is_ping])
Example #24
0
 def on_load(self, view):
     msg.debug('Sublime loaded %s' % self.name(view))
     buf = get_buf(view)
     if buf:
         f = ON_LOAD.get(buf['id'])
         if f:
             del ON_LOAD[buf['id']]
             f()
Example #25
0
 def set_text(self, text):
     msg.debug('\n\nabout to patch %s %s' % (str(self), self.vim_buf.name))
     try:
         msg.debug("now buf is loadedish? %s" % vim.eval('bufloaded(%s)' % self.native_id))
         self.vim_buf[:] = text.encode('utf-8').split('\n')
     except Exception as e:
         msg.error("couldn't apply patches because: %s!\nThe unencoded text was: %s" % (str(e), text))
         raise
Example #26
0
 def complete_signup(self):
     if not self.start_ticker():
         return
     msg.debug('Completing signup.')
     if not utils.has_browser():
         msg.log('You need a modern browser to complete the sign up. Go to https://floobits.com to sign up.')
         return
     VUI.pinocchio()
Example #27
0
def check_credentials():
    msg.debug('Print checking credentials.')
    if utils.can_auth():
        return
    if not utils.has_browser():
        msg.log('You need a Floobits account to use the Floobits plugin. Go to https://floobits.com to sign up.')
        return
    yield VUI.create_or_link_account, None, G.DEFAULT_HOST, False
 def maybe_selection_changed(self, vim_buf, is_ping):
     buf = self.get_buf_by_path(vim_buf.name)
     if not buf:
         msg.debug('no buffer found for view %s' % vim_buf.number)
         return
     view = self.get_view(buf['id'])
     msg.debug("selection changed: %s %s %s" % (vim_buf.number, buf['id'], view))
     self.selection_changed.append([vim_buf, buf, is_ping])
Example #29
0
 def is_shared(self, p):
     if not self.agent.is_ready():
         msg.debug('agent is not ready. %s is not shared' % p)
         return False
     p = utils.unfuck_path(p)
     # TODO: tokenize on path seps and then look for ..
     if utils.to_rel_path(p).find("../") == 0:
         return False
     return True
Example #30
0
 def clear_highlights(view):
     if not G.AGENT:
         return
     buf = get_buf(view)
     if not buf:
         return
     msg.debug('clearing highlights in %s, buf id %s' % (buf['path'], buf['id']))
     for user_id, username in G.AGENT.workspace_info['users'].items():
         view.erase_regions('floobits-highlight-%s' % user_id)
Example #31
0
 def check_and_join_workspace(self, args):
     if not self.start_ticker():
         return
     workspace_url = args[0]
     self.set_globals()
     try:
         r = api.get_workspace_by_url(workspace_url)
     except Exception as e:
         return editor.error_message('Error joining %s: %s' % (workspace_url, str(e)))
     if r.code >= 400:
         return editor.error_message('Error joining %s: %s' % (workspace_url, r.body))
     msg.debug('Workspace %s exists' % workspace_url)
     return self.join_workspace(workspace_url)
Example #32
0
 def get_view_by_path(self, path):
     """Warning: side effects!"""
     if not path:
         return None
     buf = self.get_buf_by_path(path)
     if not buf:
         msg.debug("buf not found for path %s" % path)
         return None
     view = self.get_view(buf['id'])
     if not view:
         msg.debug("view not found for %s %s" % (buf['id'], buf['path']))
         return None
     return view
Example #33
0
 def _on_highlight(self, req):
     view = self.get_view_by_path(req['full_path'])
     if not view:
         return
     highlight_json = {
         'id': view.buf['id'],
         'name': 'highlight',
         'ranges': req['ranges'],
         'following': bool(req['following']),
         'ping': req.get("ping"),
     }
     msg.debug("sending highlight upstream %s" % highlight_json)
     self.send_to_floobits(highlight_json)
Example #34
0
 def create_view(self, buf):
     path = buf['path']
     utils.save_buf(buf)
     vb = self.get_vim_buf_by_path(path)
     if vb:
         return View(vb)
     vim.command(':edit! %s' % path)
     vb = self.get_vim_buf_by_path(path)
     if vb is None:
         msg.debug(
             'vim buffer is none even though we tried to open it: %s' %
             path)
         return
     return View(vb)
Example #35
0
    def _on_buffer_list_change(self, req):
        added = req.get('added') or {}
        for path, text in added.items():
            buf = self.get_buf_by_path(path)
            buf_id = buf and int(buf.get('id'))
            d = buf and 'buf' in buf and self.agent.on_load.get(buf_id)
            if d:
                self.emacs_bufs[path][0] = buf['buf']
            else:
                self.emacs_bufs[path][0] = text
            if not buf:
                msg.debug('no buf for path %s' % path)
                if 'create_buf' in G.PERMS and utils.is_shared(path) and G.IGNORE and not G.IGNORE.is_ignored(path):
                    self.agent._upload(path, text=text)
                elif path in self.emacs_bufs:
                    del self.emacs_bufs[path]
                continue
            view = self.views.get(buf_id)
            if view is None:
                self.get_view(buf_id)
            elif view.is_loading():
                view._emacs_buf = self.emacs_bufs[path]
            else:
                msg.debug('view for buf %s already exists. this is not good. we got out of sync' % buf['path'])
            if d:
                del self.agent.on_load[buf_id]
                for _, f in d.items():
                    f()

        deleted = req.get('deleted') or []
        for path in deleted:
            if self.emacs_bufs.get(path) is None:
                msg.debug('emacs deleted %s but we already deleted it from emacs_bufs' % path)
            if path in self.emacs_bufs:
                del self.emacs_bufs[path]
            buf = self.get_buf_by_path(path)
            if buf and buf['id'] in self.views:
                del self.views[buf['id']]

        seen = set()
        current = req.get('current') or []
        for path in current:
            if self.emacs_bufs.get(path) is None:
                msg.debug('We should have buffer %s in emacs_bufs but we don\'t' % path)
            else:
                seen.add(path)

        for buf_id, view in self.views.items():
            if utils.get_full_path(view.buf['path']) not in seen:
                msg.debug('We should not have buffer %s in our views but we do.' % view.buf['path'])
Example #36
0
    def apply_patches(self, buf, patches, username):
        cursor_offset = self.get_cursor_offset()
        msg.debug('cursor offset is %s bytes' % cursor_offset)
        self.set_text(patches[0])

        for patch in patches[2]:
            offset = patch[0]
            length = patch[1]
            patch_text = patch[2]
            if cursor_offset > offset:
                new_offset = len(patch_text) - length
                cursor_offset += new_offset

        self.set_cursor_position(cursor_offset)
Example #37
0
 def summon(self, view):
     buf = get_buf(view)
     if buf:
         msg.debug('summoning selection in view %s, buf id %s' % (buf['path'], buf['id']))
         self.selection_changed.append((view, buf, True))
     else:
         path = view.file_name()
         if not utils.is_shared(path):
             editor.error_message('Can\'t summon because %s is not in shared path %s.' % (path, G.PROJECT_PATH))
             return
         share = editor.ok_cancel_dialog('This file isn\'t shared. Would you like to share it?', 'Share')
         if share:
             sel = [[x.a, x.b] for x in view.sel()]
             self.create_buf_cbs[utils.to_rel_path(path)] = lambda buf_id: send_summon(buf_id, sel)
             self.upload(path)
Example #38
0
    def tick(self):
        reported = set()
        while self.views_changed:
            v, buf = self.views_changed.pop()
            if not self.joined_workspace:
                msg.debug('Not connected. Discarding view change.')
                continue
            if 'patch' not in G.PERMS:
                continue
            if 'buf' not in buf:
                msg.debug('No data for buf %s %s yet. Skipping sending patch' %
                          (buf['id'], buf['path']))
                continue
            view = View(v, buf)
            if view.is_loading():
                msg.debug(
                    'View for buf %s is not ready. Ignoring change event' %
                    buf['id'])
                continue
            if view.native_id in reported:
                continue
            reported.add(view.native_id)
            patch = utils.FlooPatch(view.get_text(), buf)
            # Update the current copy of the buffer
            buf['buf'] = patch.current
            buf['md5'] = hashlib.md5(patch.current.encode('utf-8')).hexdigest()
            self.send(patch.to_json())

        reported = set()
        while self.selection_changed:
            v, buf, summon = self.selection_changed.pop()

            if not self.joined_workspace:
                msg.debug('Not connected. Discarding selection change.')
                continue
            # consume highlight events to avoid leak
            if 'highlight' not in G.PERMS:
                continue

            view = View(v, buf)
            vb_id = view.native_id
            if vb_id in reported:
                continue

            reported.add(vb_id)
            highlight_json = {
                'id': buf['id'],
                'name': 'highlight',
                'ranges': view.get_selections(),
                'ping': summon,
                'summon': summon,
                'following': G.FOLLOW_MODE,
            }
            self.send(highlight_json)

        self._status_timeout += 1
        if self._status_timeout > (2000 / G.TICK_TIME):
            self.update_status_msg()
 def poll_for_move():
     msg.debug('poll_for_move')
     win.focus_view(view)
     win.set_view_index(view, win.num_groups() - 1, 0)
     if not get_view_in_group(view.buffer_id(), focus_group):
         return utils.set_timeout(poll_for_move, 20)
     msg.debug('found view, now moving ', view.name(),
               win.num_groups() - 1)
     swap_regions(view)
     view.show(regions[0])
     win.focus_view(view)
     utils.set_timeout(win.focus_group, 0, 0)
     try:
         del self.temp_ignore_highlight[buf_id]
     except Exception:
         pass
Example #40
0
 def buf_enter(self):
     buf = G.AGENT.get_buf_by_path(self.vim.current.buffer.name)
     if not buf:
         return
     buf_id = buf['id']
     d = G.AGENT.on_load.get(buf_id)
     if d:
         del G.AGENT.on_load[buf_id]
         try:
             d['patch']()
         except Exception as e:
             msg.debug('Error running on_load patch handler for buf %s: %s' % (buf_id, str(e)))
     # NOTE: we call highlight twice in follow mode... thats stupid
     for user_id, highlight in G.AGENT.user_highlights.items():
         if highlight['id'] == buf_id:
             G.AGENT._on_highlight(highlight)
Example #41
0
 def rename(self, name):
     msg.debug('renaming %s to %s' % (self.vim_buf.name, name))
     current = vim.current.buffer
     text = self.get_text()
     old_name = self.vim_buf.name
     old_number = self.native_id
     with open(name, 'wb') as fd:
         fd.write(text.encode('utf-8'))
     vim.command('edit! %s' % name)
     self.vim_buf = vim.current.buffer
     vim.command('edit! %s' % current.name)
     vim.command('bdelete! %s' % old_number)
     try:
         utils.rm(old_name)
     except Exception as e:
         msg.debug("couldn't delete %s... maybe thats OK?" % str(e))
Example #42
0
 def handle(self, data):
     name = data.get('name')
     if not name:
         return msg.error('no name in data?!?')
     func = getattr(self, "on_%s" % (name), None)
     if not func:
         return msg.debug('unknown name', name, 'data:', data)
     func(data)
Example #43
0
def delete_buf(buf_id):
    # TODO: somehow tell the user about this
    view = get_view(buf_id)
    try:
        if view:
            view.set_scratch(True)
            G.WORKSPACE_WINDOW.focus_view(view)
            G.WORKSPACE_WINDOW.run_command("close_file")
    except Exception as e:
        msg.debug('Error closing view: %s' % unicode(e))
    try:
        buf = BUFS.get(buf_id)
        if buf:
            del PATHS_TO_IDS[buf['path']]
            del BUFS[buf_id]
    except KeyError:
        msg.debug('KeyError deleting buf id %s' % buf_id)
Example #44
0
    def maybe_new_file(self):
        path = self.vim.current.buffer.name
        if path is None or path == '':
            msg.debug('get:buf buffer has no filename')
            return
        if not os.path.exists(path):
            return
        if not utils.is_shared(path):
            msg.debug('get_buf: %s is not shared' % path)
            return

        buf = G.AGENT.get_buf_by_path(path)
        if not buf:
            if not G.IGNORE:
                msg.warn('G.IGNORE is not set. Uploading anyway.')
                G.AGENT.upload(path)
            if G.IGNORE and not G.IGNORE.is_ignored(path, None, True):
                G.AGENT.upload(path)
Example #45
0
    def push():
        reported = set()
        while Listener.views_changed:
            view, buf = Listener.views_changed.pop()
            if not G.JOINED_WORKSPACE:
                msg.debug('Not connected. Discarding view change.')
                continue
            if view.is_loading():
                msg.debug(
                    'View for buf %s is not ready. Ignoring change event' %
                    buf['id'])
                continue
            if 'patch' not in G.PERMS:
                continue
            vb_id = view.buffer_id()
            if vb_id in reported:
                continue
            if 'buf' not in buf:
                msg.debug('No data for buf %s %s yet. Skipping sending patch' %
                          (buf['id'], buf['path']))
                continue

            reported.add(vb_id)
            patch = utils.FlooPatch(get_text(view), buf)
            # Update the current copy of the buffer
            buf['buf'] = patch.current
            buf['md5'] = hashlib.md5(patch.current.encode('utf-8')).hexdigest()
            G.AGENT.put(patch.to_json())

        reported = set()
        while Listener.selection_changed:
            view, buf, summon = Listener.selection_changed.pop()

            if not G.JOINED_WORKSPACE:
                msg.debug('Not connected. Discarding selection change.')
                continue
            # consume highlight events to avoid leak
            if 'highlight' not in G.PERMS:
                continue

            vb_id = view.buffer_id()
            if vb_id in reported:
                continue

            reported.add(vb_id)
            sel = view.sel()
            highlight_json = {
                'id': buf['id'],
                'name': 'highlight',
                'ranges': [[x.a, x.b] for x in sel],
                'ping': summon,
                'summon': summon,
            }
            G.AGENT.put(highlight_json)
Example #46
0
    def push(self):
        reported = set()
        while self.BUFS_CHANGED:
            buf_id = self.BUFS_CHANGED.pop()
            view = self.get_view(buf_id)
            buf = view.buf
            if view.is_loading():
                msg.debug('View for buf %s is not ready. Ignoring change event' % buf['id'])
                continue
            if 'patch' not in self.perms:
                continue
            vb_id = view.native_id
            if vb_id in reported:
                continue
            if 'buf' not in buf:
                msg.debug('No data for buf %s %s yet. Skipping sending patch' % (buf['id'], buf['path']))
                continue

            reported.add(vb_id)
            patch = utils.FlooPatch(view.get_text(), buf)
            # Update the current copy of the buffer
            buf['buf'] = patch.current
            buf['md5'] = hashlib.md5(patch.current.encode('utf-8')).hexdigest()
            self.agent.put(patch.to_json())

        while self.SELECTION_CHANGED:
            view, ping = self.SELECTION_CHANGED.pop()
            # consume highlight events to avoid leak
            if 'highlight' not in self.perms:
                continue
            vb_id = view.native_id
            if vb_id in reported:
                continue

            reported.add(vb_id)
            highlight_json = {
                'id': view.buf['id'],
                'name': 'highlight',
                'ranges': view.get_selections(),
                'ping': ping,
            }
            self.agent.put(highlight_json)
Example #47
0
 def _on_delete_buf(self, data):
     # TODO: somehow tell the user about this
     buf_id = data['id']
     view = self.get_view(buf_id)
     try:
         if view:
             view = view.view
             view.set_scratch(True)
             G.WORKSPACE_WINDOW.focus_view(view)
             G.WORKSPACE_WINDOW.run_command("close_file")
     except Exception as e:
         msg.debug('Error closing view: %s' % unicode(e))
     try:
         buf = self.bufs.get(buf_id)
         if buf:
             del self.paths_to_ids[buf['path']]
             del self.bufs[buf_id]
     except KeyError:
         msg.debug('KeyError deleting buf id %s' % buf_id)
     super(self.__class__, self)._on_delete_buf(data)
Example #48
0
 def _on_rename_buf(self, req):
     old_path = utils.to_rel_path(req['old_path'])
     buf = self.get_buf_by_path(old_path)
     if not buf:
         msg.debug('No buffer for path %s' % req['path'])
         return
     path = utils.to_rel_path(req['path'])
     if not utils.is_shared(path):
         msg.log('New path %s is not shared. Discarding rename event.' % path)
         return
     buf_id = buf['id']
     self.send_to_floobits({
         'name': 'rename_buf',
         'id': buf['id'],
         'path': path,
     })
     # KANS: is this right? old code...
     old_path = self.agent.bufs[buf_id]['path']
     del self.agent.paths_to_ids[old_path]
     self.agent.paths_to_ids[path] = buf_id
     self.agent.bufs[buf_id]['path'] = path
Example #49
0
    def on_modified(self, view, agent):
        buf = is_view_loaded(view)
        if not buf:
            return

        text = get_text(view)
        if buf['encoding'] != 'utf8':
            return msg.warn('Floobits does not support patching binary files at this time')

        text = text.encode('utf-8')
        view_md5 = hashlib.md5(text).hexdigest()
        if view_md5 == G.VIEW_TO_HASH.get(view.buffer_id()):
            return

        G.VIEW_TO_HASH[view.buffer_id()] = view_md5

        msg.debug('changed view %s buf id %s' % (buf['path'], buf['id']))

        self.disable_follow_mode(2000)
        buf['forced_patch'] = False
        agent.views_changed.append((view, buf))
Example #50
0
 def _on_highlight(self, data):
     buf_id = data['id']
     user_id = data['user_id']
     username = data.get('username', 'an unknown user')
     ping = data.get('ping', False)
     if ping or not data.get('following'):
         self.last_highlight = data
         self.last_highlight_by_user[username] = data
     if not ping and G.FOLLOW_MODE:
         if not G.FOLLOW_USERS:
             ping = True
         else:
             ping = username in G.FOLLOW_USERS
     previous_highlight = self.user_highlights.get(user_id)
     buf = self.bufs.get(buf_id)
     if not buf:
         return
     view = self.get_view(buf_id)
     if not view:
         if not ping:
             return
         view = self.create_view(buf)
         if not view:
             return
     data['path'] = buf['path']
     self.user_highlights[user_id] = data
     if ping:
         try:
             offset = data['ranges'][0][0]
         except IndexError as e:
             msg.debug('could not get offset from range %s' % e)
         else:
             if data.get('ping'):
                 msg.log('You have been summoned by %s' % (username))
             view.focus()
             view.set_cursor_position(offset)
     if G.SHOW_HIGHLIGHTS:
         if previous_highlight and previous_highlight['id'] == data['id']:
             view.clear_highlight(user_id)
         view.highlight(data['ranges'], user_id)
    def delete_buf(self, path, unlink=False):
        if not utils.is_shared(path):
            msg.error('Skipping deleting ', path,
                      ' because it is not in shared path ', G.PROJECT_PATH,
                      '.')
            return
        if os.path.isdir(path):
            for dirpath, dirnames, filenames in os.walk(path):
                # TODO: rexamine this assumption
                # Don't care about hidden stuff
                dirnames[:] = [d for d in dirnames if d[0] != '.']
                for f in filenames:
                    f_path = os.path.join(dirpath, f)
                    if f[0] == '.':
                        msg.log('Not deleting buf for hidden file ', f_path)
                    else:
                        self.delete_buf(f_path, unlink)
            return
        buf_to_delete = self.get_buf_by_path(path)
        if buf_to_delete is None:
            msg.error(path, ' is not in this workspace')
            if unlink:
                try:
                    path = utils.get_full_path(path)
                    msg.log('deleting ', utils.to_rel_path(path))
                    utils.rm(path)
                except Exception as e:
                    msg.debug('Error deleting ', path, ': ', str_e(e))
            return
        msg.log('deleting buffer ', utils.to_rel_path(path))
        event = {
            'name': 'delete_buf',
            'id': buf_to_delete['id'],
            'unlink': unlink,
        }

        def done(d):
            self._on_delete_buf(event)

        self.send(event, done)
Example #52
0
 def connect(self, cb=None):
     self.stop(False)
     self.empty_selects = 0
     self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     if self.secure:
         if ssl:
             with open(self.cert_path, 'wb') as cert_fd:
                 cert_fd.write(cert.CA_CERT.encode('utf-8'))
             self.sock = ssl.wrap_socket(self.sock,
                                         ca_certs=self.cert_path,
                                         cert_reqs=ssl.CERT_REQUIRED)
         else:
             msg.debug(
                 'No SSL module found. Connection will not be encrypted.')
             if self.port == G.DEFAULT_PORT:
                 self.port = 3148  # plaintext port
     msg.debug('Connecting to %s:%s' % (self.host, self.port))
     try:
         self.sock.connect((self.host, self.port))
         if self.secure and ssl:
             self.sock.do_handshake()
     except socket.error as e:
         msg.error('Error connecting:', e)
         self.reconnect()
         return
     self.sock.setblocking(0)
     msg.debug('Connected!')
     self.reconnect_delay = self.INITIAL_RECONNECT_DELAY
     self.send_auth()
     if cb:
         cb()
Example #53
0
    def tick(self):
        reported = set()
        while self.bufs_changed:
            buf_id = self.bufs_changed.pop()
            view = self.get_view(buf_id)
            if view is None:
                msg.debug('View for buf %s no longer exists. Ignoring change event' % buf_id)
                continue
            buf = view.buf
            if view.is_loading():
                msg.debug('View for buf %s is not ready. Ignoring change event' % buf['id'])
                continue
            if 'patch' not in G.PERMS:
                continue
            vb_id = view.native_id
            if vb_id in reported:
                continue
            if 'buf' not in buf:
                msg.debug('No data for buf %s %s yet. Skipping sending patch' % (buf['id'], buf['path']))
                continue

            reported.add(vb_id)
            patch = utils.FlooPatch(view.get_text(), view.buf)
            # Update the current copy of the buffer
            buf['buf'] = patch.current
            buf['md5'] = hashlib.md5(patch.current.encode('utf-8')).hexdigest()
            self.send_to_floobits(patch.to_json())
Example #54
0
    def _scan_dir(ig):
        path = ig.path

        if not utils.is_shared(path):
            msg.error(
                'Skipping adding %s because it is not in shared path %s.' %
                (path, G.PROJECT_PATH))
            return
        if os.path.islink(path):
            msg.error('Skipping adding %s because it is a symlink.' % path)
            return
        ignored = ig.is_ignored(path)
        if ignored:
            msg.log('Not creating buf: %s' % (ignored))
            return

        msg.debug('create_buf: path is %s' % path)

        if not os.path.isdir(path):
            yield path
            return

        try:
            paths = os.listdir(path)
        except Exception as e:
            msg.error('Error listing path %s: %s' % (path, unicode(e)))
            return
        for p in paths:
            p_path = os.path.join(path, p)
            if p[0] == '.':
                if p not in ignore.HIDDEN_WHITELIST:
                    msg.log('Not creating buf for hidden path %s' % p_path)
                    continue
            ignored = ig.is_ignored(p_path)
            if ignored:
                msg.log('Not creating buf: %s' % (ignored))
                continue

            yield p_path
Example #55
0
    def highlight(self, ranges, user_id):
        msg.debug('highlighting ranges %s' % (ranges))
        return
        # TODO: figure out how to highlight a region
        region = "floobitsuser%s" % str(user_id)
        for _range in ranges:
            start_row, start_col = self._offset_to_vim(_range[0])
            end_row, end_col = self._offset_to_vim(_range[1])
            vim.command(":syntax clear %s" % region)
            vim.command(":highlight %s guibg=#33ff33" % region)
            if start_row == end_row and start_col == end_col:
                end_col += 1
            # vim_region = ":syntax region {region} start=/\%{start_col}v.\%{start_row}l/ end=/\%{end_col}v.\%{end_row}l/".\
            #     format(region=region, start_col=start_col, start_row=start_row, end_col=end_col, end_row=end_row)
            # msg.debug("highlight command: %s" % vim_region)
            # vim.command(vim_region)
            # matchadd({group}, {pattern}[, {priority}[, {id}]])

            vim.command(":call matchdelete({user_id})".format(user_id=user_id))
            matchadd = ":call matchadd('{region}', '\%{start_col}v.\%{start_row}l', 10000, {user_id})" \
                .format(region=region, start_col=start_col, start_row=start_row, user_id=user_id)
            msg.debug("highlight command: %s" % matchadd)
            vim.command(matchadd)
Example #56
0
    def on_modified(self, view, agent, activated=False, *args):
        buf = is_view_loaded(view)
        if not buf:
            return

        text = get_text(view)
        if buf['encoding'] != 'utf8':
            return msg.warn(
                'Floobits does not support patching binary files at this time')

        text = text.encode('utf-8')
        view_md5 = hashlib.md5(text).hexdigest()
        bid = view.buffer_id()
        buf['forced_patch'] = False
        if view_md5 == G.VIEW_TO_HASH.get(bid):
            self._highlights.add(bid)
            return

        G.VIEW_TO_HASH[view.buffer_id()] = view_md5
        msg.debug('changed view ', buf['path'], ' buf id ', buf['id'])
        if not activated:
            self.disable_follow_mode(2000)
        agent.views_changed.append(('patch', view, buf))
Example #57
0
    def get_buf(self, vim_buf):
        """None- no sharing, False- should be but isn't """
        if vim_buf.name is None:
            msg.debug('get:buf buffer has no filename')
            return None

        if not utils.is_shared(vim_buf.name):
            msg.debug('get_buf: %s is not shared' % vim_buf.name)
            return None

        buf = self.get_buf_by_path(vim_buf.name)
        if buf:
            return buf

        msg.debug('get_buf: no buf has path %s' % vim_buf.name)
        return False
Example #58
0
    def on_room_info(self, data):
        # Success! Reset counter
        self.workspace_info = data
        self.perms = data['perms']

        if 'patch' not in data['perms']:
            msg.log('We don\'t have patch permission. Setting buffers to read-only')

        utils.mkdir(G.PROJECT_PATH)

        floo_json = {
            'url': utils.to_workspace_url({
                'host': self.agent.host,
                'owner': self.agent.owner,
                'port': self.agent.port,
                'workspace': self.agent.workspace,
                'secure': self.agent.secure,
            })
        }
        with open(os.path.join(G.PROJECT_PATH, '.floo'), 'w') as floo_fd:
            floo_fd.write(json.dumps(floo_json, indent=4, sort_keys=True))

        for buf_id, buf in data['bufs'].iteritems():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.FLOO_BUFS[buf_id] = buf
            try:
                buf_fd = open(buf_path, 'r')
                buf_buf = buf_fd.read().decode('utf-8')
                md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                if md5 == buf['md5']:
                    msg.debug('md5 sums match. not getting buffer')
                    buf['buf'] = buf_buf
                else:
                    raise Exception('different md5')
            except Exception:
                try:
                    open(buf_path, "a").close()
                except Exception as e:
                    msg.debug("couldn't touch file: %s becuase %s" % (buf_path, e))
                self.agent.send_get_buf(buf_id)

        msg.debug(G.PROJECT_PATH)

        self.agent.on_auth()
    def tick(self):
        if 'patch' not in G.PERMS:
            self.views_changed = []
        elif not self.joined_workspace:
            msg.debug('Not connected. Discarding view change.')
            self.views_changed = []
        else:
            reported = set()
            to_send = []
            while self.views_changed:
                name, v, buf = self.views_changed.pop()
                if 'buf' not in buf:
                    msg.debug('No data for buf ', buf['id'], ' ', buf['path'],
                              ' yet. Skipping sending patch')
                    continue
                view = View(v, buf)
                if view.is_loading():
                    msg.debug('View for buf ', buf['id'],
                              ' is not ready. Ignoring change event.')
                    continue
                if view.native_id in reported:
                    continue
                reported.add((name, view.native_id))
                if name == 'patch':
                    patch = utils.FlooPatch(view.get_text(), buf)
                    # Update the current copy of the buffer
                    buf['buf'] = patch.current
                    buf['md5'] = patch.md5_after
                    self.send(patch.to_json())
                    continue
                if name == 'saved':
                    to_send.append({'name': 'saved', 'id': buf['id']})
                    continue
                msg.warn('Discarding unknown event in views_changed:', name)

            for s in to_send:
                self.send(s)

        self._status_timeout += 1
        if self._status_timeout > (2000 / G.TICK_TIME):
            self.update_status_msg()
Example #60
0
 def on_close(self, view, agent):
     msg.debug('Sublime closed view %s' % self.name(view))