docs: def path_completer(text, expected=None, classes=None, perm_level=None,
                     include_current_proj=False, typespec=None, visibility=None):
      '''
      :param text: String to tab-complete to a path matching the syntax project-name:folder/entity_or_folder_name
      :type text: string
      :param expected: "folder", "entity", "project", or None (no restriction) as to the types of answers to look for
      :type expected: string
      :param classes: if expected="entity", the possible data object classes that are acceptable
      :type classes: list of strings
      :param perm_level: the minimum permissions level required, e.g. "VIEW" or "CONTRIBUTE"
      :type perm_level: string
      :param include_current_proj: Indicate whether the current project's name should be a potential result
      :type include_current_proj: boolean
      :param visibility: Visibility with which to restrict the completion (one of "either", "visible", or "hidden") (default behavior is dependent on *text*)
  
      Returns a list of matches to the text and restricted by the
      requested parameters.
      '''
      colon_pos = get_last_pos_of_char(':', text)
      slash_pos = get_last_pos_of_char('/', text)
      delim_pos = max(colon_pos, slash_pos)
  
      # First get projects if necessary
      matches = []
      if expected == 'project' and colon_pos > 0 and colon_pos == len(text) - 1:
          if dxpy.find_one_project(zero_ok=True, name=text[:colon_pos]) is not None:
              return [text + " "]
  
      if colon_pos < 0 and slash_pos < 0:
          # Might be tab-completing a project, but don't ever include
          # whatever's set as dxpy.WORKSPACE_ID unless expected == "project"
          # Also, don't bother if text=="" and expected is NOT "project"
          # Also, add space if expected == "project"
          if text != "" or expected == 'project':
              results = dxpy.find_projects(describe=True, level=perm_level)
              if not include_current_proj:
                  results = [r for r in results if r['id'] != dxpy.WORKSPACE_ID]
              matches += [escape_colon(r['describe']['name'])+':' for r in results if r['describe']['name'].startswith(text)]
  
      if expected == 'project':
          return matches
  
      # Attempt to tab-complete to a folder or data object name
      if colon_pos < 0 and slash_pos >= 0:
          # Not tab-completing a project, and the project is unambiguous
          # (use dxpy.WORKSPACE_ID)
          if dxpy.WORKSPACE_ID is not None:
              # try-catch block in case dxpy.WORKSPACE_ID is garbage
              try:
                  dxproj = dxpy.get_handler(dxpy.WORKSPACE_ID)
                  folderpath, entity_name = clean_folder_path(text)
                  matches += get_folder_matches(text, slash_pos, dxproj, folderpath)
                  if expected != 'folder':
                      if classes is not None:
                          for classname in classes:
                              matches += get_data_matches(text, slash_pos, dxproj,
                                                          folderpath, classname=classname,
                                                          typespec=typespec,
                                                          visibility=visibility)
                      else:
                          matches += get_data_matches(text, slash_pos, dxproj,
                                                      folderpath, typespec=typespec,
                                                      visibility=visibility)
              except:
                  pass
      else:
          # project is given by a path, but attempt to resolve to an
          # object or folder anyway
          try:
              proj_ids, folderpath, entity_name = resolve_path(text, multi_projects=True)
          except ResolutionError as details:
              sys.stderr.write("\n" + fill(str(details)))
              return matches
          for proj in proj_ids:
              # protects against dxpy.WORKSPACE_ID being garbage
              try:
                  dxproj = dxpy.get_handler(proj)
                  matches += get_folder_matches(text, delim_pos, dxproj, folderpath)
                  if expected != 'folder':
                      if classes is not None:
                          for classname in classes:
                              matches += get_data_matches(text, delim_pos, dxproj,
                                                          folderpath, classname=classname,
                                                          typespec=typespec, visibility=visibility)
                      else:
                          matches += get_data_matches(text, delim_pos, dxproj,
                                                      folderpath, typespec=typespec,
                                                      visibility=visibility)
              except:
                  pass
      return matches