def generate_watch_output(): """ Generate output with all watch expressions. """ values = H.unicode_string('') if S.WATCH is None: return values for watch_data in S.WATCH: watch_entry = '' if watch_data and isinstance(watch_data, dict): # Whether watch expression is enabled or disabled if 'enabled' in watch_data.keys(): if watch_data['enabled']: watch_entry += '|+|' else: watch_entry += '|-|' # Watch expression if 'expression' in watch_data.keys(): watch_entry += ' "%s"' % watch_data['expression'] # Evaluated value if watch_data['value'] is not None: watch_entry += ' = ' + generate_context_output(watch_data['value']) else: watch_entry += "\n" values += H.unicode_string(watch_entry) return values
def generate_breakpoint_output(): """ Generate output with all configured breakpoints. """ # Get breakpoints for files values = H.unicode_string('') if S.BREAKPOINT is None: return values for filename, breakpoint_data in sorted(S.BREAKPOINT.items()): breakpoint_entry = '' if breakpoint_data: breakpoint_entry += "=> %s\n" % filename # Sort breakpoint data by line number for lineno, bp in sorted(breakpoint_data.items(), key=lambda item: (int(item[0]) if isinstance(item[0], int) or H.is_digit(item[0]) else float('inf'), item[0])): # Do not show temporary breakpoint if S.BREAKPOINT_RUN is not None and S.BREAKPOINT_RUN['filename'] == filename and S.BREAKPOINT_RUN['lineno'] == lineno: continue # Whether breakpoint is enabled or disabled breakpoint_entry += '\t' if bp['enabled']: breakpoint_entry += '|+|' else: breakpoint_entry += '|-|' # Line number breakpoint_entry += ' %s' % lineno # Conditional expression if bp['expression'] is not None: breakpoint_entry += ' -- "%s"' % bp['expression'] breakpoint_entry += "\n" values += H.unicode_string(breakpoint_entry) return values
def get_stack_values(): """ Get stack information for current context. """ values = H.unicode_string('') if S.SESSION: try: # Get stack information S.SESSION.send(dbgp.STACK_GET) response = S.SESSION.read() for child in response: # Get stack attribute values if child.tag == dbgp.ELEMENT_STACK or child.tag == dbgp.ELEMENT_PATH_STACK: stack_level = child.get(dbgp.STACK_LEVEL, 0) stack_type = child.get(dbgp.STACK_TYPE) stack_file = H.url_decode(child.get(dbgp.STACK_FILENAME)) stack_line = child.get(dbgp.STACK_LINENO, 0) stack_where = child.get(dbgp.STACK_WHERE, '{unknown}') # Append values values += H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=stack_level, type=stack_type, where=stack_where, lineno=stack_line, filename=stack_file)) except (socket.error, ProtocolConnectionException): e = sys.exc_info()[1] connection_error("%s" % e) return values
def generate_stack_output(response): values = H.unicode_string('') # Display exception name and message if S.BREAKPOINT_EXCEPTION: values += H.unicode_string('[{name}] {message}\n' \ .format(name=S.BREAKPOINT_EXCEPTION['name'], message=S.BREAKPOINT_EXCEPTION['message'])) # Walk through elements in response has_output = False try: for child in response: # Get stack attribute values if child.tag == dbgp.ELEMENT_STACK or child.tag == dbgp.ELEMENT_PATH_STACK: stack_level = child.get(dbgp.STACK_LEVEL, 0) stack_type = child.get(dbgp.STACK_TYPE) stack_file = H.url_decode(child.get(dbgp.STACK_FILENAME)) stack_line = child.get(dbgp.STACK_LINENO, 0) stack_where = child.get(dbgp.STACK_WHERE, '{unknown}') # Append values values += H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=stack_level, type=stack_type, where=stack_where, lineno=stack_line, filename=stack_file)) has_output = True except: pass # When no stack use values from exception if not has_output and S.BREAKPOINT_EXCEPTION: values += H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=0, where='{unknown}', lineno=S.BREAKPOINT_EXCEPTION['lineno'], filename=S.BREAKPOINT_EXCEPTION['filename'])) return values
def generate_context_output(context, indent=0): """ Generate readable context from dictionary with context data. Keyword arguments: context -- Dictionary with context data. indent -- Indent level. """ # Generate output text for values values = H.unicode_string('') if not isinstance(context, dict): return values for variable in context.values(): has_children = False property_text = '' # Set indentation for i in range(indent): property_text += '\t' # Property with value if variable['value'] is not None: if variable['name']: property_text += '{name} = ' property_text += '({type}) {value}\n' # Property with children elif isinstance(variable['children'], dict) and variable['numchildren'] is not None: has_children = True if variable['name']: property_text += '{name} = ' property_text += '{type}[{numchildren}]\n' # Unknown property else: if variable['name']: property_text += '{name} = ' property_text += '<{type}>\n' # Remove newlines in value to prevent incorrect indentation value = '' if variable['value'] and len(variable['value']) > 0: value = variable['value'].replace("\r\n", "\n").replace("\n", " ") # Format string and append to output values += H.unicode_string(property_text \ .format(value=value, type=variable['type'], name=variable['name'], numchildren=variable['numchildren'])) # Append property children to output if has_children: # Get children for property (no need to convert, already unicode) values += generate_context_output(variable['children'], indent+1) # Use ellipsis to indicate that results have been truncated limited = False if isinstance(variable['numchildren'], int) or H.is_digit(variable['numchildren']): if int(variable['numchildren']) != len(variable['children']): limited = True elif len(variable['children']) > 0 and not variable['numchildren']: limited = True if limited: for i in range(indent+1): values += H.unicode_string('\t') values += H.unicode_string('...\n') return values
def set_layout(layout): """ Toggle between debug and default window layouts. """ # Get active window and set reference to active view window = sublime.active_window() previous_active = window.active_view() # Do not set layout when disabled if get_value(S.KEY_DISABLE_LAYOUT): S.RESTORE_LAYOUT = window.get_layout() set_window_value('restore_layout', S.RESTORE_LAYOUT) S.RESTORE_INDEX = H.new_dictionary() set_window_value('restore_index', S.RESTORE_INDEX) return # Show debug layout if layout == 'debug': debug_layout = get_value(S.KEY_DEBUG_LAYOUT, S.LAYOUT_DEBUG) if window.get_layout() != debug_layout: # Save current layout S.RESTORE_LAYOUT = window.get_layout() set_window_value('restore_layout', S.RESTORE_LAYOUT) # Remember view indexes S.RESTORE_INDEX = H.new_dictionary() for view in window.views(): view_id = '%d' % view.id() group, index = window.get_view_index(view) S.RESTORE_INDEX[view_id] = {'group': group, 'index': index} set_window_value('restore_index', S.RESTORE_INDEX) # Set debug layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(debug_layout) # Show previous (single) layout else: # Get previous layout configuration if S.RESTORE_LAYOUT is None: S.RESTORE_LAYOUT = get_window_value('restore_layout', S.LAYOUT_NORMAL) if S.RESTORE_INDEX is None: S.RESTORE_INDEX = get_window_value('restore_index', {}) # Restore layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(S.RESTORE_LAYOUT) for view in window.views(): view_id = '%d' % view.id() # Set view indexes if view_id in H.dictionary_keys(S.RESTORE_INDEX): v = S.RESTORE_INDEX[view_id] window.set_view_index(view, v['group'], v['index']) # Restore focus to previous active view if previous_active is not None: window.focus_view(previous_active)
def set_layout(layout): """ Toggle between debug and default window layouts. """ # Get active window and set reference to active view window = sublime.active_window() previous_active = window.active_view() # Do not set layout when disabled if get_value(S.KEY_DISABLE_LAYOUT): S.RESTORE_LAYOUT = window.get_layout() set_window_value('restore_layout', S.RESTORE_LAYOUT) S.RESTORE_INDEX = H.new_dictionary() set_window_value('restore_index', S.RESTORE_INDEX) return # Show debug layout if layout == 'debug': debug_layout = get_value(S.KEY_DEBUG_LAYOUT, S.LAYOUT_DEBUG) if window.get_layout() != debug_layout: # Save current layout S.RESTORE_LAYOUT = window.get_layout() set_window_value('restore_layout', S.RESTORE_LAYOUT) # Remember view indexes S.RESTORE_INDEX = H.new_dictionary() for view in window.views(): view_id = "%d" % view.id() group, index = window.get_view_index(view) S.RESTORE_INDEX[view_id] = { "group": group, "index": index } set_window_value('restore_index', S.RESTORE_INDEX) # Set debug layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(debug_layout) # Show previous (single) layout else: # Get previous layout configuration if S.RESTORE_LAYOUT is None: S.RESTORE_LAYOUT = get_window_value('restore_layout', S.LAYOUT_NORMAL) if S.RESTORE_INDEX is None: S.RESTORE_INDEX = get_window_value('restore_index', {}) # Restore layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(S.RESTORE_LAYOUT) for view in window.views(): view_id = "%d" % view.id() # Set view indexes if view_id in H.dictionary_keys(S.RESTORE_INDEX): v = S.RESTORE_INDEX[view_id] window.set_view_index(view, v["group"], v["index"]) # Restore focus to previous active view if not previous_active is None: window.focus_view(previous_active)
def set_layout(layout): """ Toggle between debug and default window layouts. """ # Get active window and set reference to active view window = sublime.active_window() previous_active = window.active_view() # Show debug layout if layout == 'debug': if window.get_layout() != S.LAYOUT_DEBUG: # Save current layout S.RESTORE_LAYOUT = window.get_layout() S.set_window_value('restore_layout', S.RESTORE_LAYOUT) # Remember view indexes S.RESTORE_INDEX = H.new_dictionary() for view in window.views(): view_id = "%d" % view.id() group, index = window.get_view_index(view) S.RESTORE_INDEX[view_id] = {"group": group, "index": index} S.set_window_value('restore_index', S.RESTORE_INDEX) # Set debug layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(S.LAYOUT_DEBUG) # Show previous (single) layout else: # Get previous layout configuration if S.RESTORE_LAYOUT is None: S.RESTORE_LAYOUT = S.get_window_value('restore_layout', S.LAYOUT_NORMAL) if S.RESTORE_INDEX is None: S.RESTORE_INDEX = S.get_window_value('restore_index', {}) # Restore layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(S.RESTORE_LAYOUT) for view in window.views(): view_id = "%d" % view.id() # Set view indexes if view_id in H.dictionary_keys(S.RESTORE_INDEX): v = S.RESTORE_INDEX[view_id] window.set_view_index(view, v["group"], v["index"]) # Close all debugging related windows if view.name() == TITLE_WINDOW_BREAKPOINT or view.name( ) == TITLE_WINDOW_CONTEXT or view.name( ) == TITLE_WINDOW_STACK or view.name() == TITLE_WINDOW_WATCH: window.focus_view(view) window.run_command('close') window.run_command('hide_panel', {"panel": 'output.xdebug'}) # Restore focus to previous active view if not previous_active is None: window.focus_view(previous_active)
def generate_stack_output(response): values = H.unicode_string('') # Display exception name and message if S.BREAKPOINT_EXCEPTION: values += H.unicode_string('[{name}] {message}\n' \ .format(name=S.BREAKPOINT_EXCEPTION['name'], message=S.BREAKPOINT_EXCEPTION['message'])) # Walk through elements in response has_output = False try: for child in response: # Get stack attribute values if child.tag == dbgp.ELEMENT_STACK or child.tag == dbgp.ELEMENT_PATH_STACK: stack_level = child.get(dbgp.STACK_LEVEL, 0) stack_type = child.get(dbgp.STACK_TYPE) stack_file = H.url_decode(child.get(dbgp.STACK_FILENAME)) stack_line = child.get(dbgp.STACK_LINENO, 0) stack_where = child.get(dbgp.STACK_WHERE, '{unknown}') # Append values filename = os.path.basename(stack_file) values += H.unicode_string('[{level}] {lineno} {filename} {where} {filepath}\n' \ .format(level=stack_level, type=stack_type, where=stack_where, lineno=stack_line, filepath=stack_file, filename=filename)) has_output = True except: pass # When no stack use values from exception if not has_output and S.BREAKPOINT_EXCEPTION: filename = os.path.basename(stack_file) values += H.unicode_string('[{level}] {lineno} {filename} {where} {filepath}\n' \ .format(level=0, where='{unknown}', lineno=S.BREAKPOINT_EXCEPTION['lineno'], filepath=S.BREAKPOINT_EXCEPTION['filename'], filename=filename)) # Space all out equally lines = values.split('\n') lines_bits = [x.strip().split(' ') for x in lines] bit_widths = [] for line_bits in lines_bits: for i, line_bit in enumerate(line_bits): line_bits[i] = line_bit.strip() if len(bit_widths) <= i: bit_widths.append(0) bit_widths[i] = max(bit_widths[i], len(line_bit.strip())) new_lines = [] for i, line_bits in enumerate(lines_bits): if(len(line_bits) > 1): line_bits[1] = line_bits[1].rjust(bit_widths[1]) new_lines.append(' '.join([b.ljust(bit_widths[j]) for j, b in enumerate(line_bits)])) values = '\n'.join(new_lines) return values
def set_layout(layout): """ Toggle between debug and default window layouts. """ # Get active window and set reference to active view window = sublime.active_window() previous_active = window.active_view() # Show debug layout if layout == 'debug': if window.get_layout() != S.LAYOUT_DEBUG: # Save current layout S.RESTORE_LAYOUT = window.get_layout() S.set_window_value('restore_layout', S.RESTORE_LAYOUT) # Remember view indexes S.RESTORE_INDEX = H.new_dictionary() for view in window.views(): view_id = "%d" % view.id() group, index = window.get_view_index(view) S.RESTORE_INDEX[view_id] = { "group": group, "index": index } S.set_window_value('restore_index', S.RESTORE_INDEX) # Set debug layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(S.LAYOUT_DEBUG) # Show previous (single) layout else: # Get previous layout configuration if S.RESTORE_LAYOUT is None: S.RESTORE_LAYOUT = S.get_window_value('restore_layout', S.LAYOUT_NORMAL) if S.RESTORE_INDEX is None: S.RESTORE_INDEX = S.get_window_value('restore_index', {}) # Restore layout window.set_layout(S.LAYOUT_NORMAL) window.set_layout(S.RESTORE_LAYOUT) for view in window.views(): view_id = "%d" % view.id() # Set view indexes if view_id in H.dictionary_keys(S.RESTORE_INDEX): v = S.RESTORE_INDEX[view_id] window.set_view_index(view, v["group"], v["index"]) # Close all debugging related windows if view.name() == TITLE_WINDOW_BREAKPOINT or view.name() == TITLE_WINDOW_CONTEXT or view.name() == TITLE_WINDOW_STACK or view.name() == TITLE_WINDOW_WATCH: window.focus_view(view) window.run_command('close') window.run_command('hide_panel', {"panel": 'output.xdebug'}) # Restore focus to previous active view if not previous_active is None: window.focus_view(previous_active)
def get_context_values(self): """ Get variables in current context. """ if not is_connected(): return context = H.new_dictionary() try: # Super global variables if get_value(S.KEY_SUPER_GLOBALS): S.SESSION.send(dbgp.CONTEXT_GET, c=1) response = S.SESSION.read() context.update(get_response_properties(response)) # Local variables S.SESSION.send(dbgp.CONTEXT_GET) response = S.SESSION.read() context.update(get_response_properties(response)) except ProtocolConnectionException: e = sys.exc_info()[1] self.timeout(lambda: connection_error("%s" % e)) # Store context variables in session S.CONTEXT_DATA = context return generate_context_output(context)
def get_context_values(self): """ Get variables in current context. """ if not is_connected(): return context = H.new_dictionary() try: # Super global variables if get_value(S.KEY_SUPER_GLOBALS): S.SESSION.send(dbgp.CONTEXT_GET, c=dbgp.CONTEXT_ID_SUPERGLOBALS) response = S.SESSION.read() context.update(get_response_properties(response)) # Local variables S.SESSION.send(dbgp.CONTEXT_GET) response = S.SESSION.read() context.update(get_response_properties(response)) except ProtocolConnectionException: e = sys.exc_info()[1] self.timeout(lambda: connection_error('%s' % e)) # Store context variables in session S.CONTEXT_DATA = context return generate_context_output(context)
def get_context_values(): """ Get variables in current context. """ if S.SESSION: context = H.new_dictionary() try: # Super global variables if S.get_project_value('super_globals') or S.get_package_value('super_globals'): S.SESSION.send(dbgp.CONTEXT_GET, c=1) response = S.SESSION.read() context.update(get_response_properties(response)) # Local variables S.SESSION.send(dbgp.CONTEXT_GET) response = S.SESSION.read() context.update(get_response_properties(response)) except (socket.error, ProtocolConnectionException): e = sys.exc_info()[1] connection_error("%s" % e) # Store context variables in session S.CONTEXT_DATA = context return generate_context_output(context)
def get_context_values(self, thread, stack_level): """ Get variables in current context. """ if not is_connected(): return context = H.new_dictionary() try: # local variables #if get_value(S.KEY_SUPER_GLOBALS): with S.PROTOCOL as protocol: protocol.send("locals") protocol.send(thread) protocol.send(stack_level) response = protocol.read() properties = self.transform_grld_context_response( response, "local") context.update(properties) # upvalues protocol.send("upvalues") protocol.send(thread) protocol.send(stack_level) response = protocol.read() properties = self.transform_grld_context_response( response, "upvalue") context.update(properties) except ProtocolConnectionException as e: self.timeout(lambda: connection_error(e)) # Store context variables in session S.CONTEXT_DATA = context return generate_context_output(context)
def show_context_output(view): """ Show selected variable in an output panel when clicked in context window. Keyword arguments: view -- View reference which holds the context window. """ # Check if there is a debug session and context data if S.SESSION and S.SESSION.connected and S.CONTEXT_DATA: try: # Get selected point in view point = view.sel()[0] # Check if selected point uses variable scope if point.size() == 0 and sublime.score_selector(view.scope_name(point.a), 'variable'): # Find variable in line which contains the point line = view.substr(view.line(point)) pattern = re.compile('^\\s*(\\$.*?)\\s+\\=') match = pattern.match(line) if match: # Get variable details from context data variable_name = match.group(1) variable = get_context_variable(S.CONTEXT_DATA, variable_name) if variable: # Convert details to text output variables = H.new_dictionary() variables[variable_name] = variable data = generate_context_output(variables) # Show context variables and children in output panel window = sublime.active_window() panel = window.get_output_panel('xdebug') panel.run_command("xdebug_view_update", {'data' : data} ) panel.run_command('set_setting', {"setting": 'word_wrap', "value": True}) window.run_command('show_panel', {"panel": 'output.xdebug'}) except: pass
def load_watch_data(): data_path = os.path.join(sublime.packages_path(), 'User', S.FILE_WATCH_DATA) data = [] try: data_file = open(data_path, 'rb') except: e = sys.exc_info()[1] info('Failed to open %s.' % data_path) debug(e) try: data = json.loads(H.data_read(data_file.read())) except: e = sys.exc_info()[1] info('Failed to parse %s.' % data_path) debug(e) # Check if expression is not already defined duplicates = [] for index, entry in enumerate(data): matches = [x for x in S.WATCH if x['expression'] == entry['expression']] if matches: duplicates.append(entry) else: # Unset any previous value data[index]['value'] = None for duplicate in duplicates: data.remove(duplicate) if not isinstance(S.WATCH, list): S.WATCH = [] # Set watch data S.WATCH.extend(data)
def load_breakpoint_data(): data_path = os.path.join(sublime.packages_path(), 'User', S.FILE_BREAKPOINT_DATA) data = {} try: data_file = open(data_path, 'rb') except: e = sys.exc_info()[1] info('Failed to open %s.' % data_path) debug(e) try: data = json.loads(H.data_read(data_file.read())) except: e = sys.exc_info()[1] info('Failed to parse %s.' % data_path) debug(e) # Do not use deleted files or entries without breakpoints if data: for filename, breakpoint_data in data.copy().items(): if not breakpoint_data or not os.path.isfile(filename): del data[filename] if not isinstance(S.BREAKPOINT, dict): S.BREAKPOINT = {} # Set breakpoint data S.BREAKPOINT.update(data)
def rows_to_region(rows): """ Convert rows (line numbers) to a region (selection/cursor position). Keyword arguments: - rows -- Row number(s) to convert to region(s). """ # Get current active view view = sublime.active_window().active_view() # Unable to convert rows to regions when no view available if view is None: return # List for containing regions to return region = [] # Create list if it is a singleton if not isinstance(rows, list): rows = [rows] for row in rows: # Check if row is a digit if isinstance(row, int) or H.is_digit(row): # Convert from 1 based to a 0 based row (line) number row_number = int(row) - 1 # Calculate offset point for row offset_point = view.text_point(row_number, 0) # Get region for row by offset point region_row = view.line(offset_point) # Add to list for result region.append(region_row) return region
def get_context_values(): """ Get variables in current context. """ if S.SESSION: context = H.new_dictionary() try: # Super global variables if S.get_project_value('super_globals') or S.get_package_value( 'super_globals'): S.SESSION.send(dbgp.CONTEXT_GET, c=1) response = S.SESSION.read() context.update(get_response_properties(response)) # Local variables S.SESSION.send(dbgp.CONTEXT_GET) response = S.SESSION.read() context.update(get_response_properties(response)) except (socket.error, ProtocolConnectionException): e = sys.exc_info()[1] connection_error("%s" % e) # Store context variables in session S.CONTEXT_DATA = context return generate_context_output(context)
def load_watch_data(): data_path = os.path.join(sublime.packages_path(), 'User', S.FILE_WATCH_DATA) data = [] try: data_file = open(data_path, 'rb') except: e = sys.exc_info()[1] info('Failed to open %s.' % data_path) debug(e) try: data = json.loads(H.data_read(data_file.read())) except: e = sys.exc_info()[1] info('Failed to parse %s.' % data_path) debug(e) # Check if expression is not already defined for entry in data: matches = [x for x in S.WATCH if x['expression'] == entry['expression']] if matches: data.remove(entry) if not isinstance(S.WATCH, list): S.WATCH = [] # Set watch data S.WATCH.extend(data)
def listen(self): """ Create socket server which listens for connection on configured port. """ # Create socket server server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if server: # Configure socket server try: server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.settimeout(1) server.bind((self.host, self.port)) server.listen(1) self.listening = True self.socket = None except: e = sys.exc_info()[1] debug('Failed to create socket: %s' % e) # Substitute exception with readable (custom) message if isinstance(e, TypeError) and not H.is_number(self.port): e = 'Configured port is not a valid integer.' elif isinstance(e, socket.gaierror) and self.host != '': e = 'Hostname (%s) is not specified in hosts file or is an IPv6 address.' % self.host elif hasattr(e, 'errno'): address_or_port = 'address (%s:%d)' % (self.host, self.port) if self.host != '' else 'port (%d)' % self.port if e.errno == errno.EADDRINUSE: e = 'Another application is already listening on configured %s.' % address_or_port elif e.errno == errno.EADDRNOTAVAIL: e = 'Configured %s is not accessible.' % address_or_port raise ProtocolListenException(e) # Accept incoming connection on configured port while self.listening: try: self.socket, address = server.accept() self.listening = False except socket.timeout: pass # Check if a connection has been made if self.socket: self.connected = True self.socket.settimeout(None) else: self.connected = False self.listening = False # Close socket server try: server.close() except: pass server = None # Return socket connection return self.socket else: raise ProtocolListenException('Could not create socket server.')
def init(self): if not is_connected(): return # Connection initialization init = S.SESSION.read() # More detailed internal information on properties S.SESSION.send(dbgp.FEATURE_SET, n='show_hidden', v=1) response = S.SESSION.read() # Set max depth limit max_depth = self.get_option('max_depth', S.MAX_DEPTH) S.SESSION.send(dbgp.FEATURE_SET, n=dbgp.FEATURE_NAME_MAXDEPTH, v=max_depth) response = S.SESSION.read() # Set max children limit max_children = self.get_option('max_children', S.MAX_CHILDREN) S.SESSION.send(dbgp.FEATURE_SET, n=dbgp.FEATURE_NAME_MAXCHILDREN, v=max_children) response = S.SESSION.read() # Set breakpoints for files for filename, breakpoint_data in S.BREAKPOINT.items(): if breakpoint_data: for lineno, bp in breakpoint_data.items(): if bp['enabled']: self.set_breakpoint(filename, lineno, bp['expression']) debug('breakpoint_set: ' + filename + ':' + lineno) # Determine if client should break at first line on connect if self.get_option('break_on_start'): # Get init attribute values fileuri = init.get(dbgp.INIT_FILEURI) filename = get_real_path(fileuri) # Show debug/status output self.status_message('Xdebug: Break on start') info('Break on start: ' + filename ) # Store line number of breakpoint for displaying region marker S.BREAKPOINT_ROW = { 'filename': filename, 'lineno': 1 } # Focus/Open file window view self.timeout(lambda: show_file(filename, 1)) # Context variables context = self.get_context_values() self.timeout(lambda: show_content(DATA_CONTEXT, context)) # Stack history stack = self.get_stack_values() if not stack: stack = H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=0, where='{main}', lineno=1, filename=fileuri)) self.timeout(lambda: show_content(DATA_STACK, stack)) # Watch expressions self.watch_expression() else: # Tell script to run it's process self.run_command('xdebug_execute', {'command': 'run'})
def generate_stack_output(response): values = H.unicode_string('') # Walk through elements in response try: for child in response: # Get stack attribute values if child.tag == dbgp.ELEMENT_STACK or child.tag == dbgp.ELEMENT_PATH_STACK: stack_level = child.get(dbgp.STACK_LEVEL, 0) stack_type = child.get(dbgp.STACK_TYPE) stack_file = H.url_decode(child.get(dbgp.STACK_FILENAME)) stack_line = child.get(dbgp.STACK_LINENO, 0) stack_where = child.get(dbgp.STACK_WHERE, '{unknown}') # Append values values += H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=stack_level, type=stack_type, where=stack_where, lineno=stack_line, filename=stack_file)) except: pass return values
def convert(matches): text = matches.group(0) # Character reference if text[:2] == '&#': try: if text[:3] == '&#x': return H.unicode_chr(int(text[3:-1], 16)) else: return H.unicode_chr(int(text[2:-1])) except ValueError: pass # Named entity else: try: # Following are not needed to be converted for XML if text[1:-1] in ('amp', 'apos', 'gt', 'lt', 'quot'): pass else: text = H.unicode_chr(name2codepoint[text[1:-1]]) except KeyError: pass return text
def send(self, data, channel='default'): s_data = serialize(data) formatted_data = channel + '\n' + str(len(s_data)) + '\n' + s_data exception = None try: sent = self.socket.send(H.data_write(formatted_data)) except socket.error as e: sent = 0 exception = e if sent == 0: self.disconnect(exception)
def convert(matches): text = matches.group(0) # Character reference if text[:2] == "&#": try: if text[:3] == "&#x": return H.unicode_chr(int(text[3:-1], 16)) else: return H.unicode_chr(int(text[2:-1])) except ValueError: pass # Named entity else: try: # Following are not needed to be converted for XML if text[1:-1] == "amp" or text[1:-1] == "gt" or text[1:-1] == "lt": pass else: text = H.unicode_chr(name2codepoint[text[1:-1]]) except KeyError: pass return text
def read_until_null(self): """ Get response data from debugger engine. """ # Check socket connection if self.connected: # Get result data from debugger engine while not '\x00' in self.buffer: self.buffer += H.data_read(self.socket.recv(self.read_size)) data, self.buffer = self.buffer.split('\x00', 1) return data else: raise ProtocolConnectionException("Xdebug is not connected")
def send(self, command, *args, **kwargs): """ Send command to the debugger engine according to DBGp protocol. """ # Expression is used for conditional and watch type breakpoints expression = None # Separate 'expression' from kwargs if 'expression' in kwargs: expression = kwargs['expression'] del kwargs['expression'] # Generate unique Transaction ID transaction_id = self.transaction_id # Append command/arguments to build list build_command = [command, '-i %i' % transaction_id] if args: build_command.extend(args) if kwargs: build_command.extend(['-%s %s' % pair for pair in kwargs.items()]) # Remove leading/trailing spaces and build command string build_command = [ part.strip() for part in build_command if part.strip() ] command = ' '.join(build_command) if expression: command += ' -- ' + H.base64_encode(expression) # Show debug output debug('[Send command] %s' % command) # Send command to debugger engine try: self.socket.send(H.data_write(command + '\x00')) except: e = sys.exc_info()[1] raise ProtocolConnectionException(e)
def send(self, command, *args, **kwargs): """ Send command to the debugger engine according to DBGp protocol. """ # Expression is used for conditional and watch type breakpoints expression = None # Seperate 'expression' from kwargs if 'expression' in kwargs: expression = kwargs['expression'] del kwargs['expression'] # Generate unique Transaction ID transaction_id = self.transaction_id # Append command/arguments to build list build_command = [command, '-i %i' % transaction_id] if args: build_command.extend(args) if kwargs: build_command.extend(['-%s %s' % pair for pair in kwargs.items()]) # Remove leading/trailing spaces and build command string build_command = [part.strip() for part in build_command if part.strip()] command = ' '.join(build_command) if expression: command += ' -- ' + H.base64_encode(expression) # Show debug output debug('[Send command] %s' % command) # Send command to debugger engine try: self.socket.send(H.data_write(command + '\x00')) except: e = sys.exc_info()[1] raise ProtocolConnectionException(e)
def read_until_null(self): """ Get response data from debugger engine. """ # Check socket connection if self.connected: # Get result data from debugger engine try: while not "\x00" in self.buffer: self.buffer += H.data_read(self.socket.recv(self.read_size)) data, self.buffer = self.buffer.split("\x00", 1) return data except: e = sys.exc_info()[1] raise ProtocolConnectionException(e) else: raise ProtocolConnectionException("Xdebug is not connected")
def read_until_null(self): """ Get response data from debugger engine. """ # Check socket connection if self.connected: # Get result data from debugger engine try: while '\x00' not in self.buffer: self.buffer += H.data_read(self.socket.recv(self.read_size)) data, self.buffer = self.buffer.split('\x00', 1) return data except: e = sys.exc_info()[1] raise ProtocolConnectionException(e) else: raise ProtocolConnectionException('Xdebug is not connected')
def generate_stack_output(response): values = H.unicode_string('') # Display exception name and message if S.BREAKPOINT_EXCEPTION: values += H.unicode_string('[{name}] {message}\n' \ .format(name=S.BREAKPOINT_EXCEPTION['name'], message=S.BREAKPOINT_EXCEPTION['message'])) has_output = False for level, stackData in response.items(): stack_level = level stack_type = 'file' #child.get(dbgp.STACK_TYPE) stack_file = get_real_path(H.url_decode(stackData['source'])) stack_line = stackData['line'] stack_name = stackData.get( 'name', '') #child.get(dbgp.STACK_WHERE, '{unknown}') stack_namewhat = stackData[ 'namewhat'] #child.get(dbgp.STACK_WHERE, '{unknown}') if stack_namewhat != '': values += H.unicode_string('[{level}] {filename}:{lineno} - {name}({namewhat})\n' \ .format(level=stack_level, type=stack_type, name=stack_name, namewhat = stack_namewhat, lineno=stack_line, filename=stack_file)) else: values += H.unicode_string('[{level}] {filename}:{lineno}\n' \ .format(level=stack_level, type=stack_type, lineno=stack_line, filename=stack_file)) has_output = True # Walk through elements in response #try: # for child in response: # # Get stack attribute values # if child.tag == dbgp.ELEMENT_STACK or child.tag == dbgp.ELEMENT_PATH_STACK: # stack_level = child.get(dbgp.STACK_LEVEL, 0) # stack_type = child.get(dbgp.STACK_TYPE) # stack_file = H.url_decode(child.get(dbgp.STACK_FILENAME)) # stack_line = child.get(dbgp.STACK_LINENO, 0) # stack_where = child.get(dbgp.STACK_WHERE, '{unknown}') # # Append values # values += H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ # .format(level=stack_level, type=stack_type, where=stack_where, lineno=stack_line, filename=stack_file)) # has_output = True #except: # pass # When no stack use values from exception if not has_output and S.BREAKPOINT_EXCEPTION: values += H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=0, where='{unknown}', lineno=S.BREAKPOINT_EXCEPTION['lineno'], filename=S.BREAKPOINT_EXCEPTION['filename'])) return values
def handle_break_command(self, filename, line): S.SESSION_BUSY = True filename = get_real_path(filename) # Show debug/status output self.status_message('GRLD: Break') info('Break: ' + filename) # Store line number of breakpoint for displaying region marker S.BREAKPOINT_ROW = {'filename': filename, 'lineno': str(line)} # Focus/Open file window view self.timeout(lambda: show_file(filename, line)) coroutines_dict = self.get_all_coroutines() self.update_current_thread(coroutines_dict) coroutines_str = generate_coroutines_output(coroutines_dict, self.current_thread) self.timeout(lambda: show_content(DATA_COROUTINES, coroutines_str)) # Stack history stack = self.get_stack_values() if stack: stack_levels = [int(level) for level in stack.keys()] min_stack_level = min(stack_levels) self.current_stack_level = min_stack_level stack_str = generate_stack_output(stack) else: stack_str = H.unicode_string('[{level}] {filename}.{where}:{lineno}\n' \ .format(level=0, where='{main}', lineno=1, filename=fileuri)) self.timeout(lambda: show_content(DATA_STACK, stack_str)) self.update_contextual_data(self.current_thread, self.current_stack_level) #self.timeout(lambda: render_regions()) S.SESSION_BUSY = False
def get_real_path(uri, server=False): """ Get real path Keyword arguments: uri -- Uri of file that needs to be mapped and located server -- Map local path to server path TODO: Fix mapping for root (/) and drive letters (P:/) """ if uri is None: return uri # URLdecode uri uri = H.url_decode(uri) # Split scheme from uri to get absolute path try: # scheme:///path/file => scheme, /path/file # scheme:///C:/path/file => scheme, C:/path/file transport, filename = uri.split(':///', 1) except: filename = uri # Normalize path for comparison and remove duplicate/trailing slashes uri = os.path.normpath(filename) # Pattern for checking if uri is a windows path drive_pattern = re.compile(r'^[a-zA-Z]:[\\/]') # Append leading slash if filesystem is not Windows if not drive_pattern.match(uri) and not os.path.isabs(uri): uri = os.path.normpath('/' + uri) path_mapping = S.get_config_value('path_mapping') if isinstance(path_mapping, dict): # Go through path mappings for server_path, local_path in path_mapping.items(): server_path = os.path.normpath(server_path) local_path = os.path.normpath(local_path) # Replace path if mapping available if server: # Map local path to server path if local_path in uri: uri = uri.replace(local_path, server_path) break else: # Map server path to local path if server_path in uri: uri = uri.replace(server_path, local_path) break else: sublime.set_timeout( lambda: sublime.status_message( "Xdebug: No path mapping defined, returning given path."), 0) # Replace slashes if not drive_pattern.match(uri): uri = uri.replace("\\", "/") # Append scheme if server: return H.url_encode("file://" + uri) return uri
def get_response_properties(response, default_key=None): """ Return a dictionary with available properties from response. Keyword arguments: response -- Response from debugger engine. default_key -- Index key to use when property has no name. """ properties = H.new_dictionary() # Walk through elements in response for child in response: # Read property elements if child.tag == dbgp.ELEMENT_PROPERTY or child.tag == dbgp.ELEMENT_PATH_PROPERTY: # Get property attribute values property_name_short = child.get(dbgp.PROPERTY_NAME) property_name = child.get(dbgp.PROPERTY_FULLNAME, property_name_short) property_type = child.get(dbgp.PROPERTY_TYPE) property_children = child.get(dbgp.PROPERTY_CHILDREN) property_numchildren = child.get(dbgp.PROPERTY_NUMCHILDREN) property_classname = child.get(dbgp.PROPERTY_CLASSNAME) property_encoding = child.get(dbgp.PROPERTY_ENCODING) property_value = None # Set property value if child.text: property_value = child.text # Try to decode property value when encoded with base64 if property_encoding is not None and property_encoding == 'base64': try: property_value = H.base64_decode(child.text) except: pass if property_name is not None and len(property_name) > 0: property_key = property_name # Ignore following properties if property_name == "::": continue # Avoid nasty static functions/variables from turning in an infinitive loop if property_name.count("::") > 1: continue # Filter password values if get_value(S.KEY_HIDE_PASSWORD, True) and property_name.lower().find('password') != -1 and property_value is not None: property_value = '******' else: property_key = default_key # Store property if property_key: properties[property_key] = { 'name': property_name, 'type': property_type, 'value': property_value, 'numchildren': property_numchildren, 'children' : None } # Get values for children if property_children: properties[property_key]['children'] = get_response_properties(child, default_key) # Set classname, if available, as type for object if property_classname and property_type == 'object': properties[property_key]['type'] = property_classname # Handle error elements elif child.tag == dbgp.ELEMENT_ERROR or child.tag == dbgp.ELEMENT_PATH_ERROR: message = 'error' for step_child in child: if step_child.tag == dbgp.ELEMENT_MESSAGE or step_child.tag == dbgp.ELEMENT_PATH_MESSAGE and step_child.text: message = step_child.text break if default_key: properties[default_key] = { 'name': None, 'type': message, 'value': None, 'numchildren': None, 'children': None } return properties
def get_real_path(uri, server=False): """ Get real path Keyword arguments: uri -- Uri of file that needs to be mapped and located server -- Map local path to server path TODO: Fix mapping for root (/) and drive letters (P:/) """ if uri is None: return uri # URLdecode uri uri = H.url_decode(uri) # Split scheme from uri to get absolute path try: # scheme:///path/file => scheme, /path/file # scheme:///C:/path/file => scheme, C:/path/file transport, filename = uri.split(':///', 1) except: filename = uri # Normalize path for comparison and remove duplicate/trailing slashes uri = os.path.normpath(filename) # Pattern for checking if uri is a windows path drive_pattern = re.compile(r'^[a-zA-Z]:[\\/]') # Append leading slash if filesystem is not Windows if not drive_pattern.match(uri) and not os.path.isabs(uri): uri = os.path.normpath('/' + uri) path_mapping = S.get_config_value('path_mapping') if isinstance(path_mapping, dict): # Go through path mappings for server_path, local_path in path_mapping.items(): server_path = os.path.normpath(server_path) local_path = os.path.normpath(local_path) # Replace path if mapping available if server: # Map local path to server path if local_path in uri: uri = uri.replace(local_path, server_path) break else: # Map server path to local path if server_path in uri: uri = uri.replace(server_path, local_path) break else: sublime.set_timeout(lambda: sublime.status_message("Xdebug: No path mapping defined, returning given path."), 0) # Replace slashes if not drive_pattern.match(uri): uri = uri.replace("\\", "/") # Append scheme if server: return H.url_encode("file://" + uri) return uri
from .elementtree import SimpleXMLTreeBuilder ET.XMLTreeBuilder = SimpleXMLTreeBuilder.TreeBuilder ILLEGAL_XML_UNICODE_CHARACTERS = [ (0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0x7F, 0x84), (0x86, 0x9F), (0xD800, 0xDFFF), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF), (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF) ] ILLEGAL_XML_RANGES = ["%s-%s" % (H.unicode_chr(low), H.unicode_chr(high)) for (low, high) in ILLEGAL_XML_UNICODE_CHARACTERS if low < sys.maxunicode] ILLEGAL_XML_RE = re.compile(H.unicode_string('[%s]') % H.unicode_string('').join(ILLEGAL_XML_RANGES)) class Protocol(object): """ Class for connecting with debugger engine which uses DBGp protocol. """ # Maximum amount of data to be received at once by socket read_size = 1024
UNESCAPE_RESPONSE_DATA = False ILLEGAL_XML_UNICODE_CHARACTERS = [(0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0x7F, 0x84), (0x86, 0x9F), (0xD800, 0xDFFF), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF), (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF)] ILLEGAL_XML_RANGES = [ '%s-%s' % (H.unicode_chr(low), H.unicode_chr(high)) for (low, high) in ILLEGAL_XML_UNICODE_CHARACTERS if low < sys.maxunicode ] ILLEGAL_XML_RE = re.compile( H.unicode_string('[%s]') % H.unicode_string('').join(ILLEGAL_XML_RANGES)) class Protocol(object): """ Class for connecting with debugger engine which uses DBGp protocol. """ # Maximum amount of data to be received at once by socket read_size = 1024
def save_breakpoint_data(): data_path = os.path.join(sublime.packages_path(), 'User', S.FILE_BREAKPOINT_DATA) with open(data_path, 'wb') as data: data.write(H.data_write(json.dumps(S.BREAKPOINT)))
def save_watch_data(): data_path = os.path.join(sublime.packages_path(), 'User', S.FILE_WATCH_DATA) with open(data_path, 'wb') as data: data.write(H.data_write(json.dumps(S.WATCH)))
def generate_controls_output(): content = '<Run>\n<Step Over> <Step Into> <Step Out>\n<Evaluate> <Stop> <Detach>\n<Auto Evaluate>' if S.AUTO_EVALUATE is not None: content += '\n' + S.AUTO_EVALUATE return H.unicode_string(content)
(0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF), ] ILLEGAL_XML_RANGES = [ "%s-%s" % (H.unicode_chr(low), H.unicode_chr(high)) for (low, high) in ILLEGAL_XML_UNICODE_CHARACTERS if low < sys.maxunicode ] ILLEGAL_XML_RE = re.compile(H.unicode_string("[%s]") % H.unicode_string("").join(ILLEGAL_XML_RANGES)) class Protocol(object): """ Class for connecting with debugger engine which uses DBGp protocol. """ # Maximum amount of data to be received at once by socket read_size = 1024