def tick(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 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())
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 tick(self): reported = set() while self.views_changed: v, buf = self.views_changed.pop() if not G.AGENT or not G.AGENT.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) 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() if not patch.to_json(): msg.debug('Attempted to send None patch %s' % patch) return msg.debug('Sending a patch %s' % patch.to_json()) self.send(patch.to_json()) reported = set() while self.selection_changed: v, buf, summon = self.selection_changed.pop() if not G.AGENT or not G.AGENT.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) 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, } self.send(highlight_json)
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)
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)
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()
def apply_patch(patch_data): if not G.AGENT: msg.debug('Not connected. Discarding view change.') return buf_id = patch_data['id'] buf = BUFS[buf_id] if 'buf' not in buf: msg.debug('buf %s not populated yet. not patching' % buf['path']) return if buf['encoding'] == 'base64': # TODO apply binary patches return Listener.get_buf(buf_id, None) view = get_view(buf_id) if len(patch_data['patch']) == 0: msg.error('wtf? no patches to apply. server is being stupid') return msg.debug('patch is', patch_data['patch']) dmp_patches = DMP.patch_fromText(patch_data['patch']) # TODO: run this in a separate thread old_text = buf['buf'] if view and not view.is_loading(): view_text = get_text(view) if old_text == view_text: buf['forced_patch'] = False elif not buf.get('forced_patch'): 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() buf['forced_patch'] = True msg.debug('forcing patch for %s' % buf['path']) G.AGENT.put(patch.to_json()) old_text = view_text else: msg.debug( 'forced patch is true. not sending another patch for buf %s' % buf['path']) md5_before = hashlib.md5(old_text.encode('utf-8')).hexdigest() if md5_before != patch_data['md5_before']: msg.warn('starting md5s don\'t match for %s. this is dangerous!' % buf['path']) t = DMP.patch_apply(dmp_patches, old_text) clean_patch = True for applied_patch in t[1]: if not applied_patch: clean_patch = False break if G.DEBUG: if len(t[0]) == 0: try: msg.debug('OMG EMPTY!') msg.debug('Starting data:', buf['buf']) msg.debug('Patch:', patch_data['patch']) except Exception as e: print(e) if '\x01' in t[0]: msg.debug('FOUND CRAZY BYTE IN BUFFER') msg.debug('Starting data:', buf['buf']) msg.debug('Patch:', patch_data['patch']) timeout_id = buf.get('timeout_id') if timeout_id: utils.cancel_timeout(timeout_id) if not clean_patch: msg.log('Couldn\'t patch %s cleanly.' % buf['path']) return Listener.get_buf(buf_id, view) cur_hash = hashlib.md5(t[0].encode('utf-8')).hexdigest() if cur_hash != patch_data['md5_after']: buf['timeout_id'] = utils.set_timeout(Listener.get_buf, 2000, buf_id, view) buf['buf'] = t[0] buf['md5'] = cur_hash if not view: save_buf(buf) return regions = [] commands = [] for patch in t[2]: offset = patch[0] length = patch[1] patch_text = patch[2] region = sublime.Region(offset, offset + length) regions.append(region) commands.append({ 'r': [offset, offset + length], 'data': patch_text }) view.run_command('floo_view_replace_regions', {'commands': commands}) region_key = 'floobits-patch-' + patch_data['username'] view.add_regions(region_key, regions, 'floobits.patch', 'circle', sublime.DRAW_OUTLINED) utils.set_timeout(view.erase_regions, 2000, region_key) view.set_status( 'Floobits', 'Changed by %s at %s' % (patch_data['username'], datetime.now().strftime('%H:%M')))