def launch_browser(): url = S.get_config_value('url') if not url: sublime.status_message( 'Xdebug: No URL defined in (project) settings file.') return ide_key = S.get_config_value('ide_key', S.DEFAULT_IDE_KEY) operator = '?' # Check if url already has query string if url.count("?"): operator = '&' # Start debug session if S.SESSION and (S.SESSION.listening or not S.SESSION.connected): webbrowser.open(url + operator + 'XDEBUG_SESSION_START=' + ide_key) # Stop debug session else: # Check if we should execute script if S.get_config_value('browser_no_execute'): # Without executing script webbrowser.open(url + operator + 'XDEBUG_SESSION_STOP_NO_EXEC=' + ide_key) else: # Run script normally webbrowser.open(url + operator + 'XDEBUG_SESSION_STOP=' + ide_key)
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 S.get_config_value('disable_layout'): S.RESTORE_LAYOUT = window.get_layout() S.set_window_value('restore_layout', S.RESTORE_LAYOUT) S.RESTORE_INDEX = H.new_dictionary() S.set_window_value('restore_index', S.RESTORE_INDEX) return # Show debug layout if layout == 'debug': debug_layout = S.get_config_value('debug_layout', S.LAYOUT_DEBUG) if window.get_layout() != debug_layout: # 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(debug_layout) # 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"]) # 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() # Do not set layout when disabled if S.get_config_value('disable_layout'): S.RESTORE_LAYOUT = window.get_layout() S.set_window_value('restore_layout', S.RESTORE_LAYOUT) S.RESTORE_INDEX = H.new_dictionary() S.set_window_value('restore_index', S.RESTORE_INDEX) return # Show debug layout if layout == 'debug': debug_layout = S.get_config_value('debug_layout', S.LAYOUT_DEBUG) if window.get_layout() != debug_layout: # 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(debug_layout) # 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"]) # Restore focus to previous active view if not previous_active is None: window.focus_view(previous_active)
def get_context_values(): """ Get variables in current context. """ if S.SESSION: context = H.new_dictionary() try: # Super global variables if S.get_config_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 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 launch_browser(): url = S.get_config_value('url') if not url: sublime.status_message('Xdebug: No URL defined in (project) settings file.') return ide_key = S.get_config_value('ide_key', S.DEFAULT_IDE_KEY) operator = '?' # Check if url already has query string if url.count("?"): operator = '&' # Start debug session if S.SESSION and (S.SESSION.listening or not S.SESSION.connected): webbrowser.open(url + operator + 'XDEBUG_SESSION_START=' + ide_key) # Stop debug session else: # Check if we should execute script if S.get_config_value('browser_no_execute'): # Without executing script webbrowser.open(url + operator + 'XDEBUG_SESSION_STOP_NO_EXEC=' + ide_key) else: # Run script normally webbrowser.open(url + operator + 'XDEBUG_SESSION_STOP=' + ide_key)
def get_region_icon(icon): # Default icons for color schemes from default theme default_current = 'bookmark' default_disabled = 'dot' default_enabled = 'circle' # Package icons (without .png extension) package_breakpoint_current = 'breakpoint_current' package_breakpoint_disabled = 'breakpoint_disabled' package_breakpoint_enabled = 'breakpoint_enabled' package_current_line = 'current_line' # List to check for duplicate icon entries icon_list = [default_current, default_disabled, default_enabled] # Determine icon path icon_path = None if S.PACKAGE_FOLDER is not None: # Strip .sublime-package of package name for comparison package_extension = ".sublime-package" current_package = S.PACKAGE_FOLDER if current_package.endswith(package_extension): current_package = current_package[:-len(package_extension)] if sublime.version() == '' or int(sublime.version()) > 3000: # ST3: Packages/Xdebug Client/icons/breakpoint_enabled.png icon_path = "Packages/" + current_package + '/icons/{0}.png' else: # ST2: ../Xdebug Client/icons/breakpoint_enabled icon_path = "../" + current_package + '/icons/{0}' # Append icon path to package icons package_breakpoint_current = icon_path.format( package_breakpoint_current) package_breakpoint_disabled = icon_path.format( package_breakpoint_disabled) package_breakpoint_enabled = icon_path.format( package_breakpoint_enabled) package_current_line = icon_path.format(package_current_line) # Add to duplicate list icon_list.append(icon_path.format(package_breakpoint_current)) icon_list.append(icon_path.format(package_breakpoint_disabled)) icon_list.append(icon_path.format(package_breakpoint_enabled)) icon_list.append(icon_path.format(package_current_line)) # Get user defined icons from settings breakpoint_current = S.get_config_value(S.KEY_BREAKPOINT_CURRENT) breakpoint_disabled = S.get_config_value(S.KEY_BREAKPOINT_DISABLED) breakpoint_enabled = S.get_config_value(S.KEY_BREAKPOINT_ENABLED) current_line = S.get_config_value(S.KEY_CURRENT_LINE) # Duplicate check, enabled breakpoint if breakpoint_enabled not in icon_list: icon_list.append(breakpoint_enabled) else: breakpoint_enabled = None # Duplicate check, disabled breakpoint if breakpoint_disabled not in icon_list: icon_list.append(breakpoint_disabled) else: breakpoint_disabled = None # Duplicate check, current line if current_line not in icon_list: icon_list.append(current_line) else: current_line = None # Duplicate check, current breakpoint if breakpoint_current not in icon_list: icon_list.append(breakpoint_current) else: breakpoint_current = None # Use default/package icon if no user defined or duplicate detected if not breakpoint_current and icon_path is not None: breakpoint_current = package_breakpoint_current if not breakpoint_disabled: breakpoint_disabled = default_disabled if icon_path is None else package_breakpoint_disabled if not breakpoint_enabled: breakpoint_enabled = default_enabled if icon_path is None else package_breakpoint_enabled if not current_line: current_line = default_current if icon_path is None else package_current_line # Return icon for icon name if icon == S.KEY_CURRENT_LINE: return current_line elif icon == S.KEY_BREAKPOINT_CURRENT: return breakpoint_current elif icon == S.KEY_BREAKPOINT_DISABLED: return breakpoint_disabled elif icon == S.KEY_BREAKPOINT_ENABLED: return breakpoint_enabled else: info("Invalid icon name. (" + icon + ")") return
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_region_icon(icon): # Default icons for color schemes from default theme default_current = 'bookmark' default_disabled = 'dot' default_enabled = 'circle' # Package icons (without .png extension) package_breakpoint_current = 'breakpoint_current' package_breakpoint_disabled = 'breakpoint_disabled' package_breakpoint_enabled = 'breakpoint_enabled' package_current_line = 'current_line' # List to check for duplicate icon entries icon_list = [default_current, default_disabled, default_enabled] # Determine icon path icon_path = None if S.PACKAGE_FOLDER is not None: # Strip .sublime-package of package name for comparison package_extension = ".sublime-package" current_package = S.PACKAGE_FOLDER if current_package.endswith(package_extension): current_package = current_package[:-len(package_extension)] if sublime.version() == '' or int(sublime.version()) > 3000: # ST3: Packages/Xdebug Client/icons/breakpoint_enabled.png icon_path = "Packages/" + current_package + '/icons/{0}.png' else: # ST2: ../Xdebug Client/icons/breakpoint_enabled icon_path = "../" + current_package + '/icons/{0}' # Append icon path to package icons package_breakpoint_current = icon_path.format(package_breakpoint_current) package_breakpoint_disabled = icon_path.format(package_breakpoint_disabled) package_breakpoint_enabled = icon_path.format(package_breakpoint_enabled) package_current_line = icon_path.format(package_current_line) # Add to duplicate list icon_list.append(icon_path.format(package_breakpoint_current)) icon_list.append(icon_path.format(package_breakpoint_disabled)) icon_list.append(icon_path.format(package_breakpoint_enabled)) icon_list.append(icon_path.format(package_current_line)) # Get user defined icons from settings breakpoint_current = S.get_config_value(S.KEY_BREAKPOINT_CURRENT) breakpoint_disabled = S.get_config_value(S.KEY_BREAKPOINT_DISABLED) breakpoint_enabled = S.get_config_value(S.KEY_BREAKPOINT_ENABLED) current_line = S.get_config_value(S.KEY_CURRENT_LINE) # Duplicate check, enabled breakpoint if breakpoint_enabled not in icon_list: icon_list.append(breakpoint_enabled) else: breakpoint_enabled = None # Duplicate check, disabled breakpoint if breakpoint_disabled not in icon_list: icon_list.append(breakpoint_disabled) else: breakpoint_disabled = None # Duplicate check, current line if current_line not in icon_list: icon_list.append(current_line) else: current_line = None # Duplicate check, current breakpoint if breakpoint_current not in icon_list: icon_list.append(breakpoint_current) else: breakpoint_current = None # Use default/package icon if no user defined or duplicate detected if not breakpoint_current and icon_path is not None: breakpoint_current = package_breakpoint_current if not breakpoint_disabled: breakpoint_disabled = default_disabled if icon_path is None else package_breakpoint_disabled if not breakpoint_enabled: breakpoint_enabled = default_enabled if icon_path is None else package_breakpoint_enabled if not current_line: current_line = default_current if icon_path is None else package_current_line # Return icon for icon name if icon == S.KEY_CURRENT_LINE: return current_line elif icon == S.KEY_BREAKPOINT_CURRENT: return breakpoint_current elif icon == S.KEY_BREAKPOINT_DISABLED: return breakpoint_disabled elif icon == S.KEY_BREAKPOINT_ENABLED: return breakpoint_enabled else: info("Invalid icon name. (" + icon + ")") return
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_debug_index(name=None): """ Retrieve configured group/index position of of debug view(s) within active window. Returns list with tuple entries for all debug views or single tuple when specified name of debug view. Structure of tuple entry for debug view is as followed: (group position in window, index position in group, name/title of debug view) Keyword arguments: name -- Name of debug view to get group/index position. """ # Set group and index for each debug view breakpoint_group = S.get_config_value('breakpoint_group', -1) breakpoint_index = S.get_config_value('breakpoint_index', 0) context_group = S.get_config_value('context_group', -1) context_index = S.get_config_value('context_index', 0) stack_group = S.get_config_value('stack_group', -1) stack_index = S.get_config_value('stack_index', 0) watch_group = S.get_config_value('watch_group', -1) watch_index = S.get_config_value('watch_index', 0) # Create list with all debug views and sort by group/index debug_list = [] debug_list.append( (breakpoint_group, breakpoint_index, TITLE_WINDOW_BREAKPOINT)) debug_list.append((context_group, context_index, TITLE_WINDOW_CONTEXT)) debug_list.append((stack_group, stack_index, TITLE_WINDOW_STACK)) debug_list.append((watch_group, watch_index, TITLE_WINDOW_WATCH)) debug_list.sort(key=operator.itemgetter(0, 1)) # Recalculate group/index position within boundaries of active window window = sublime.active_window() group_limit = window.num_groups() - 1 sorted_list = [] last_group = None last_index = 0 for debug in debug_list: group, index, title = debug # Set group position if group > group_limit: group = group_limit # Set index position if group == last_group: last_index += 1 else: index_limit = len(window.views_in_group(group)) if index > index_limit: index = index_limit last_group = group last_index = index # Add debug view with new group/index sorted_list.append((group, last_index, title)) # Sort recalculated list by group/index sorted_list.sort(key=operator.itemgetter(0, 1)) # Find specified view by name/title of debug view if name is not None: try: return [view[2] for view in sorted_list].index(name) except ValueError: return None # List with all debug views return sorted_list
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_value = None if child.text: try: # Try to base64 decode value property_value = H.base64_decode(child.text) except: # Return raw value property_value = child.text 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 S.get_config_value('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_debug_index(name=None): """ Retrieve configured group/index position of of debug view(s) within active window. Returns list with tuple entries for all debug views or single tuple when specified name of debug view. Structure of tuple entry for debug view is as followed: (group position in window, index position in group, name/title of debug view) Keyword arguments: name -- Name of debug view to get group/index position. """ # Set group and index for each debug view breakpoint_group = S.get_config_value('breakpoint_group', -1) breakpoint_index = S.get_config_value('breakpoint_index', 0) context_group = S.get_config_value('context_group', -1) context_index = S.get_config_value('context_index', 0) stack_group = S.get_config_value('stack_group', -1) stack_index = S.get_config_value('stack_index', 0) watch_group = S.get_config_value('watch_group', -1) watch_index = S.get_config_value('watch_index', 0) # Create list with all debug views and sort by group/index debug_list = [] debug_list.append((breakpoint_group, breakpoint_index, TITLE_WINDOW_BREAKPOINT)) debug_list.append((context_group, context_index, TITLE_WINDOW_CONTEXT)) debug_list.append((stack_group, stack_index, TITLE_WINDOW_STACK)) debug_list.append((watch_group, watch_index, TITLE_WINDOW_WATCH)) debug_list.sort(key=operator.itemgetter(0,1)) # Recalculate group/index position within boundaries of active window window = sublime.active_window() group_limit = window.num_groups()-1 sorted_list = [] last_group = None last_index = 0 for debug in debug_list: group, index, title = debug # Set group position if group > group_limit: group = group_limit # Set index position if group == last_group: last_index += 1 else: index_limit = len(window.views_in_group(group)) if index > index_limit: index = index_limit last_group = group last_index = index # Add debug view with new group/index sorted_list.append((group, last_index, title)) # Sort recalculated list by group/index sorted_list.sort(key=operator.itemgetter(0,1)) # Find specified view by name/title of debug view if name is not None: try: return [view[2] for view in sorted_list].index(name) except ValueError: return None # List with all debug views return sorted_list
def __init__(self): # Set port number to listen for response self.port = S.get_config_value('port', S.DEFAULT_PORT) self.clear()
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 S.get_config_value( '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 debug(message=None): if not S.get_config_value('debug') or message is None: return # Write message to output file logging.debug(message)