Mon, 19 Feb 2024 15:56:51 +0100
Adapted the file browser incl. the class browsers to support the 'eric-ide' server.
--- a/src/eric7/UI/Browser.py Mon Feb 19 15:34:54 2024 +0100 +++ b/src/eric7/UI/Browser.py Mon Feb 19 15:56:51 2024 +0100 @@ -35,6 +35,7 @@ from eric7.EricWidgets import EricFileDialog, EricMessageBox from eric7.EricWidgets.EricApplication import ericApp from eric7.Project.ProjectBrowserModel import ProjectBrowserSimpleDirectoryItem +from eric7.RemoteServerInterface import EricServerFileDialog from eric7.SystemUtilities import FileSystemUtilities from eric7.UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog from eric7.Utilities import MimeTypes @@ -106,10 +107,12 @@ pdfFile = pyqtSignal(str) testFile = pyqtSignal(str) - def __init__(self, parent=None): + def __init__(self, serverInterface, parent=None): """ Constructor + @param serverInterface reference to the 'eric-ide' server interface object + @type EricServerInterface @param parent parent widget @type QWidget """ @@ -118,7 +121,10 @@ self.setWindowTitle(QCoreApplication.translate("Browser", "File-Browser")) self.setWindowIcon(EricPixmapCache.getIcon("eric")) - self.__model = BrowserModel() + self.__ericServerInterface = serverInterface + self.__remotefsInterface = serverInterface.getServiceInterface("FileSystem") + + self.__model = BrowserModel(fsInterface=self.__remotefsInterface) self.__sortModel = BrowserSortFilterProxyModel() self.__sortModel.setSourceModel(self.__model) self.setModel(self.__sortModel) @@ -338,15 +344,19 @@ # create the directory menu self.dirMenu = QMenu(self) self.dirMenu.addAction( - QCoreApplication.translate("Browser", "New toplevel directory..."), - self.__newToplevelDir, + QCoreApplication.translate("Browser", "New Top Level Directory..."), + self.__newTopLevelDir, + ) + self.__dmRemoteTopLevelAct = self.dirMenu.addAction( + QCoreApplication.translate("Browser", "New Remote Top Level Directory..."), + self.__newRemoteTopLevelDir, ) self.addAsTopLevelAct = self.dirMenu.addAction( - QCoreApplication.translate("Browser", "Add as toplevel directory"), + QCoreApplication.translate("Browser", "Add as top level directory"), self.__addAsToplevelDir, ) self.removeFromToplevelAct = self.dirMenu.addAction( - QCoreApplication.translate("Browser", "Remove from toplevel"), + QCoreApplication.translate("Browser", "Remove from top level"), self.__removeToplevel, ) self.dirMenu.addSeparator() @@ -387,8 +397,12 @@ self.attributeMenu = QMenu(self) self.attributeMenu.addAction( - QCoreApplication.translate("Browser", "New toplevel directory..."), - self.__newToplevelDir, + QCoreApplication.translate("Browser", "New Top Level Directory..."), + self.__newTopLevelDir, + ) + self.__amRemoteTopLevelAct = self.attributeMenu.addAction( + QCoreApplication.translate("Browser", "New Remote Top Level Directory..."), + self.__newRemoteTopLevelDir, ) self.attributeMenu.addSeparator() self.attributeMenu.addMenu(self.gotoMenu) @@ -396,8 +410,12 @@ # create the background menu self.backMenu = QMenu(self) self.backMenu.addAction( - QCoreApplication.translate("Browser", "New toplevel directory..."), - self.__newToplevelDir, + QCoreApplication.translate("Browser", "New Top Level Directory..."), + self.__newTopLevelDir, + ) + self.__bmRemoteTopLevelAct = self.backMenu.addAction( + QCoreApplication.translate("Browser", "New Remote Top Level Directory..."), + self.__newRemoteTopLevelDir, ) self.backMenu.addSeparator() self.backMenu.addAction(self.showHiddenFilesAct) @@ -431,7 +449,7 @@ def _contextMenuRequested(self, coord): """ - Protected slot to show the context menu of the listview. + Protected slot to show the context menu of the list view. @param coord the position of the mouse pointer @type QPoint @@ -475,6 +493,9 @@ self.openInPdfViewerAct.setVisible(False) self.menu.popup(coord) elif isinstance(itm, BrowserClassAttributeItem): + self.__amRemoteTopLevelAct.setEnabled( + self.__ericServerInterface.isServerConnected() + ) self.attributeMenu.popup(coord) elif isinstance(itm, BrowserDirectoryItem): if not index.parent().isValid(): @@ -483,10 +504,19 @@ else: self.removeFromToplevelAct.setEnabled(False) self.addAsTopLevelAct.setEnabled(True) + self.__dmRemoteTopLevelAct.setEnabled( + self.__ericServerInterface.isServerConnected() + ) self.dirMenu.popup(coord) else: + self.__bmRemoteTopLevelAct.setEnabled( + self.__ericServerInterface.isServerConnected() + ) self.backMenu.popup(coord) else: + self.__bmRemoteTopLevelAct.setEnabled( + self.__ericServerInterface.isServerConnected() + ) self.backMenu.popup(self.mapToGlobal(coord)) def _showGotoMenu(self): @@ -755,6 +785,7 @@ # remember the current state Preferences.setUI("BrowsersListHiddenFiles", checked) + @pyqtSlot() def handleTesting(self): """ Public slot to handle the testing popup menu entry. @@ -769,13 +800,14 @@ if pyfn is not None: self.testFile.emit(pyfn) - def __newToplevelDir(self): + @pyqtSlot() + def __newTopLevelDir(self): """ - Private slot to handle the New toplevel directory popup menu entry. + Private slot to handle the New Top Level Directory popup menu entry. """ dname = EricFileDialog.getExistingDirectory( None, - QCoreApplication.translate("Browser", "New toplevel directory"), + QCoreApplication.translate("Browser", "New Top Level Directory"), "", EricFileDialog.ShowDirsOnly, ) @@ -783,22 +815,39 @@ dname = os.path.abspath(FileSystemUtilities.toNativeSeparators(dname)) self.__model.addTopLevelDir(dname) + @pyqtSlot() + def __newRemoteTopLevelDir(self): + """ + Private slot to handle the New Remote Top Level Directory popup menu entry. + """ + dname = EricServerFileDialog.getExistingDirectory( + None, + QCoreApplication.translate("Browser", "New Remote Top Level Directory"), + "", + dirsOnly=True, + ) + if dname: + self.__model.addTopLevelDir(dname) + + @pyqtSlot() def __removeToplevel(self): """ - Private slot to handle the Remove from toplevel popup menu entry. + Private slot to handle the Remove from top level popup menu entry. """ index = self.currentIndex() sindex = self.model().mapToSource(index) self.__model.removeToplevelDir(sindex) + @pyqtSlot() def __addAsToplevelDir(self): """ - Private slot to handle the Add as toplevel directory popup menu entry. + Private slot to handle the Add as top level directory popup menu entry. """ index = self.currentIndex() dname = self.model().item(index).dirName() self.__model.addTopLevelDir(dname) + @pyqtSlot() def __refreshDirectory(self): """ Private slot to refresh a directory entry. @@ -807,6 +856,7 @@ refreshDir = self.model().item(index).dirName() self.__model.directoryChanged(refreshDir) + @pyqtSlot() def __findInDirectory(self): """ Private slot to handle the Find in directory popup menu entry. @@ -816,6 +866,7 @@ ericApp().getObject("UserInterface").showFindFilesWidget(searchDir=searchDir) + @pyqtSlot() def __replaceInDirectory(self): """ Private slot to handle the Find&Replace in directory popup menu entry. @@ -825,6 +876,7 @@ ericApp().getObject("UserInterface").showReplaceFilesWidget(searchDir=searchDir) + @pyqtSlot(str) def handleProgramChange(self, fn): """ Public slot to handle the programChange signal. @@ -834,6 +886,7 @@ """ self.__model.programChange(os.path.dirname(fn)) + @pyqtSlot(str) def handleInterpreterChanged(self, interpreter): """ Public slot to handle a change of the debug client's interpreter.
--- a/src/eric7/UI/BrowserModel.py Mon Feb 19 15:34:54 2024 +0100 +++ b/src/eric7/UI/BrowserModel.py Mon Feb 19 15:56:51 2024 +0100 @@ -62,14 +62,17 @@ Class implementing the browser model. """ - def __init__(self, parent=None, nopopulate=False): + def __init__(self, parent=None, nopopulate=False, fsInterface=None): """ Constructor - @param parent reference to parent object - @type QObject - @param nopopulate flag indicating to not populate the model - @type bool + @param parent reference to parent object (defaults to None) + @type QObject (optional) + @param nopopulate flag indicating to not populate the model (defaults to False) + @type bool (optional) + @param fsInterface reference to the 'eric-ide' server interface object + (defaults to None) + @type EricServerFileSystemInterface (optional) """ super().__init__(parent) @@ -78,6 +81,8 @@ self.__sysPathInterpreter = "" self.__sysPathItem = None + self.__remotefsInterface = fsInterface + if not nopopulate: self.watchedItems = {} self.watchedFileItems = {} @@ -326,8 +331,8 @@ dirName = itm.dirName() if ( dirName != "" - and not dirName.startswith("//") - and not dirName.startswith("\\\\") + and not FileSystemUtilities.isRemoteFileName(dirName) + and not dirName.startswith(("//", "\\\\")) ): if dirName not in self.watcher.directories(): self.watcher.addPath(dirName) @@ -442,7 +447,9 @@ ) for d in self.toplevelDirs: - itm = BrowserDirectoryItem(self.rootItem, d) + itm = BrowserDirectoryItem( + self.rootItem, d, fsInterface=self.__remotefsInterface + ) self._addItem(itm, self.rootItem) def interpreterChanged(self, interpreter): @@ -502,7 +509,9 @@ self.endRemoveRows() self.progDir = None - itm = BrowserDirectoryItem(self.rootItem, dirname) + itm = BrowserDirectoryItem( + self.rootItem, dirname, fsInterface=self.__remotefsInterface + ) self.addItem(itm) self.progDir = itm @@ -514,7 +523,9 @@ @type str """ if dirname not in self.toplevelDirs: - itm = BrowserDirectoryItem(self.rootItem, dirname) + itm = BrowserDirectoryItem( + self.rootItem, dirname, fsInterface=self.__remotefsInterface + ) self.addItem(itm) self.toplevelDirs.append(itm.dirName()) @@ -607,39 +618,74 @@ """ self._addWatchedItem(parentItem) - qdir = QDir(parentItem.dirName()) + # TODO: add support for 'remote:' directories + dirName = parentItem.dirName() + if FileSystemUtilities.isPlainFileName(dirName): + qdir = QDir(dirName) - dirFilter = ( - QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot | QDir.Filter.Hidden - ) - entryInfoList = qdir.entryInfoList(dirFilter) - if len(entryInfoList) > 0: - if repopulate: - self.beginInsertRows( - self.createIndex(parentItem.row(), 0, parentItem), - 0, - len(entryInfoList) - 1, - ) - for f in entryInfoList: - if f.isDir(): - node = BrowserDirectoryItem( - parentItem, - FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), - False, + dirFilter = ( + QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot | QDir.Filter.Hidden + ) + entryInfoList = qdir.entryInfoList(dirFilter) + if len(entryInfoList) > 0: + if repopulate: + self.beginInsertRows( + self.createIndex(parentItem.row(), 0, parentItem), + 0, + len(entryInfoList) - 1, ) - else: - fileFilters = Preferences.getUI("BrowsersFileFilters").split(";") - if fileFilters: - fn = f.fileName() - if any(fnmatch.fnmatch(fn, ff.strip()) for ff in fileFilters): - continue - node = BrowserFileItem( - parentItem, - FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), + for f in entryInfoList: + if f.isDir(): + node = BrowserDirectoryItem( + parentItem, + FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), + False, + ) + else: + fileFilters = Preferences.getUI("BrowsersFileFilters").split(";") + if fileFilters: + fn = f.fileName() + if any(fnmatch.fnmatch(fn, ff.strip()) for ff in fileFilters): + continue + node = BrowserFileItem( + parentItem, + FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), + ) + self._addItem(node, parentItem) + if repopulate: + self.endInsertRows() + + elif FileSystemUtilities.isRemoteFileName(dirName): + entriesList = self.__remotefsInterface.listdir(dirName)[2] + if len(entriesList) > 0: + if repopulate: + self.beginInsertRows( + self.createIndex(parentItem.row(), 0, parentItem), + 0, + len(entryInfoList) - 1, ) - self._addItem(node, parentItem) - if repopulate: - self.endInsertRows() + for entry in entriesList: + if entry["is_dir"]: + node = BrowserDirectoryItem( + parentItem, + FileSystemUtilities.remoteFileName(entry["path"]), + False, + fsInterface=self.__remotefsInterface, + ) + else: + fileFilters = Preferences.getUI("BrowsersFileFilters").split(";") + if fileFilters: + fn = entry["name"] + if any(fnmatch.fnmatch(fn, ff.strip()) for ff in fileFilters): + continue + node = BrowserFileItem( + parentItem, + FileSystemUtilities.remoteFileName(entry["path"]), + fsInterface=self.__remotefsInterface, + ) + self._addItem(node, parentItem) + if repopulate: + self.endInsertRows() def populateSysPathItem(self, parentItem, repopulate=False): """ @@ -692,6 +738,7 @@ """ from eric7.Utilities import ClassBrowsers + # TODO: add support for 'remote:' directories moduleName = parentItem.moduleName() fileName = parentItem.fileName() try: @@ -721,11 +768,16 @@ cl = dictionary[key] with contextlib.suppress(AttributeError): if cl.module == moduleName: - if isinstance(cl, ClbrBaseClasses.Class): + if isinstance( + cl, (ClbrBaseClasses.Class, ClbrBaseClasses.Module) + ): node = BrowserClassItem(parentItem, cl, fileName) elif isinstance(cl, ClbrBaseClasses.Function): node = BrowserMethodItem(parentItem, cl, fileName) - self._addItem(node, parentItem) + else: + node = None + if node: + self._addItem(node, parentItem) if "@@Coding@@" in dictionary and Preferences.getUI("BrowserShowCoding"): node = BrowserCodingItem( parentItem, @@ -1147,6 +1199,7 @@ Class implementing the data structure for browser simple directory items. """ + # TODO: add support for 'remote:' directories def __init__(self, parent, text, path=""): """ Constructor @@ -1181,6 +1234,7 @@ @param full flag indicating full path name should be displayed @type bool """ + # TODO: add support for 'remote:' directories self._dirName = os.path.abspath(dinfo) self.itemData[0] = os.path.basename(self._dirName) @@ -1228,7 +1282,7 @@ Class implementing the data structure for browser directory items. """ - def __init__(self, parent, dinfo, full=True): + def __init__(self, parent, dinfo, full=True, fsInterface=None): """ Constructor @@ -1236,21 +1290,37 @@ @type BrowserItem @param dinfo dinfo is the string for the directory @type str - @param full flag indicating full pathname should be displayed - @type bool + @param full flag indicating full pathname should be displayed (defaults to True) + @type bool (optional) + @param fsInterface reference to the 'eric-ide' server file system interface + (defaults to None) + @type EricServerFileSystemInterface (optional) """ - self._dirName = os.path.abspath(dinfo) - dn = self._dirName if full else os.path.basename(self._dirName) + self.__fsInterface = fsInterface + + if FileSystemUtilities.isRemoteFileName(dinfo): + self._dirName = dinfo + dn = ( + self._dirName + if full + else self.__fsInterface.basename(self._dirName) + ) + else: + self._dirName = os.path.abspath(dinfo) + dn = self._dirName if full else os.path.basename(self._dirName) BrowserItem.__init__(self, parent, dn) self.type_ = BrowserItemType.Directory if ( - not FileSystemUtilities.isDrive(self._dirName) + FileSystemUtilities.isPlainFileName(self._dirName) + and not FileSystemUtilities.isDrive(self._dirName) and os.path.lexists(self._dirName) and os.path.islink(self._dirName) ): self.symlink = True self.icon = EricPixmapCache.getSymlinkIcon("dirClosed") + elif FileSystemUtilities.isRemoteFileName(self._dirName): + self.icon = EricPixmapCache.getIcon("open-remote") else: self.icon = EricPixmapCache.getIcon("dirClosed") self._populated = False @@ -1265,8 +1335,16 @@ @param full flag indicating full pathname should be displayed @type bool """ - self._dirName = os.path.abspath(dinfo) - dn = self._dirName if full else os.path.basename(self._dirName) + if FileSystemUtilities.isRemoteFileName(dinfo): + self._dirName = dinfo + dn = ( + self._dirName + if full + else self.__fsInterface.basename(self._dirName) + ) + else: + self._dirName = os.path.abspath(dinfo) + dn = self._dirName if full else os.path.basename(self._dirName) self.itemData[0] = dn def dirName(self): @@ -1337,12 +1415,13 @@ return "sys.path" +# TODO: add support for 'remote:' directories class BrowserFileItem(BrowserItem): """ Class implementing the data structure for browser file items. """ - def __init__(self, parent, finfo, full=True, sourceLanguage=""): + def __init__(self, parent, finfo, full=True, sourceLanguage="", fsInterface=None): """ Constructor @@ -1350,17 +1429,29 @@ @type BrowserItem @param finfo the string for the file @type str - @param full flag indicating full pathname should be displayed - @type bool - @param sourceLanguage source code language of the project - @type str + @param full flag indicating full pathname should be displayed (defaults to True) + @type bool (optional) + @param sourceLanguage source code language of the project (defaults to "") + @type str (optional) + @param fsInterface reference to the 'eric-ide' server file system interface + (defaults to None) + @type EricServerFileSystemInterface (optional) """ - BrowserItem.__init__(self, parent, os.path.basename(finfo)) + self.__fsInterface = fsInterface + if FileSystemUtilities.isRemoteFileName(finfo): + dirname, basename = self.__fsInterface.split(finfo) + self.fileext = self.__fsInterface.splitext(finfo)[1].lower() + self._filename = finfo + else: + dirname, basename = os.path.split(finfo) + self.fileext = os.path.splitext(finfo)[1].lower() + self._filename = os.path.abspath(finfo) + + BrowserItem.__init__(self, parent, basename) + + self._dirName = dirname self.type_ = BrowserItemType.File - self.fileext = os.path.splitext(finfo)[1].lower() - self._filename = os.path.abspath(finfo) - self._dirName = os.path.dirname(finfo) self.sourceLanguage = sourceLanguage self._moduleName = "" @@ -1370,17 +1461,17 @@ pixName = "filePython" self._populated = False self._lazyPopulation = True - self._moduleName = os.path.basename(finfo) + self._moduleName = basename elif self.isCythonFile(): pixName = "lexerCython" self._populated = False self._lazyPopulation = True - self._moduleName = os.path.basename(finfo) + self._moduleName = basename elif self.isRubyFile(): pixName = "fileRuby" self._populated = False self._lazyPopulation = True - self._moduleName = os.path.basename(finfo) + self._moduleName = basename elif self.isDesignerFile(): pixName = "fileDesigner" elif self.isLinguistFile(): @@ -1404,18 +1495,22 @@ pixName = "fileJavascript" self._populated = False self._lazyPopulation = True - self._moduleName = os.path.basename(finfo) + self._moduleName = basename elif self.isEricGraphicsFile(): pixName = "fileUML" elif self.isParsableFile(): pixName = ClassBrowsers.getIcon(self._filename) self._populated = False self._lazyPopulation = True - self._moduleName = os.path.basename(finfo) + self._moduleName = basename else: pixName = "fileMisc" - if os.path.lexists(self._filename) and os.path.islink(self._filename): + if ( + FileSystemUtilities.isPlainFileName(self._filename) + and os.path.lexists(self._filename) + and os.path.islink(self._filename) + ): self.symlink = True self.icon = EricPixmapCache.getSymlinkIcon(pixName) else: @@ -1430,12 +1525,25 @@ @param full flag indicating full pathname should be displayed @type bool """ - self._filename = os.path.abspath(finfo) - self.itemData[0] = os.path.basename(finfo) - self.fileext = os.path.splitext(finfo)[1].lower() - if self.isPython3File() or self.isRubyFile() or self.isParsableFile(): - self._dirName = os.path.dirname(finfo) - self._moduleName = os.path.basename(finfo) + if FileSystemUtilities.isRemoteFileName(finfo): + dirname, basename = self.__fsInterface.split(finfo) + self.fileext = self.__fsInterface.splitext(finfo)[1].lower() + self._filename = finfo + else: + dirname, basename = os.path.split(finfo) + self.fileext = os.path.splitext(finfo)[1].lower() + self._filename = os.path.abspath(finfo) + + self.itemData[0] = basename + if ( + self.isPython3File() + or self.isCythonFile() + or self.isRubyFile() + or self.isJavaScriptFile() + or self.isParsableFile() + ): + self._dirName = dirname + self._moduleName = basename def fileName(self): """ @@ -1649,8 +1757,18 @@ return order == Qt.SortOrder.DescendingOrder if issubclass(other.__class__, BrowserFileItem): - sinit = os.path.basename(self._filename).startswith("__init__.py") - oinit = os.path.basename(other.fileName()).startswith("__init__.py") + if FileSystemUtilities.isRemoteFileName(self._filename): + basename = self.__fsInterface.basename(self._filename) + else: + basename = os.path.basename(self._filename) + sinit = basename.startswith("__init__.py") + + if FileSystemUtilities.isRemoteFileName(other.fileName()): + basename = self.__fsInterface.basename(other.fileName()) + else: + basename = os.path.basename(other.fileName()) + oinit = basename.startswith("__init__.py") + if sinit and not oinit: return order == Qt.SortOrder.AscendingOrder if not sinit and oinit:
--- a/src/eric7/UI/UserInterface.py Mon Feb 19 15:34:54 2024 +0100 +++ b/src/eric7/UI/UserInterface.py Mon Feb 19 15:56:51 2024 +0100 @@ -394,9 +394,6 @@ self.stdout = Redirector(False, self) self.stderr = Redirector(True, self) - # create the remote server interface - self.__ericServerInterface = EricServerInterface(self) - # set a few dialog members for non-modal dialogs created on demand self.programsDialog = None self.shortcutsDialog = None @@ -807,6 +804,11 @@ from .PythonAstViewer import PythonAstViewer from .PythonDisViewer import PythonDisViewer + + # create the remote server interface + logging.debug("Creating 'eric-ide' Server Interface...") + self.__ericServerInterface = EricServerInterface(self) + # Create the view manager depending on the configuration setting logging.debug("Creating Viewmanager...") self.viewmanager = ViewManager.factory( @@ -867,7 +869,7 @@ logging.debug("Creating File Browser...") from .Browser import Browser # noqa: I101 - self.browser = Browser() + self.browser = Browser(self.__ericServerInterface) else: logging.debug("File Browser disabled") self.browser = None
--- a/src/eric7/Utilities/ClassBrowsers/__init__.py Mon Feb 19 15:34:54 2024 +0100 +++ b/src/eric7/Utilities/ClassBrowsers/__init__.py Mon Feb 19 15:56:51 2024 +0100 @@ -108,7 +108,7 @@ return None -def readmodule(module, path=None, isPyFile=False): +def readmodule(module, searchPath=None, isPyFile=False): """ Function to read a source file and return a dictionary of classes, functions, modules, etc. . @@ -118,7 +118,7 @@ @param module name of the source file @type str - @param path list of paths the file should be searched in + @param searchPath list of paths the file should be searched in @type list of str @param isPyFile flag indicating a Python file @type bool @@ -126,13 +126,13 @@ @rtype dict """ ext = os.path.splitext(module)[1].lower() - path = [] if path is None else path[:] + searchPath = [] if searchPath is None else searchPath[:] if not isPyFile: for classBrowserName in ClassBrowserRegistry: if ext in ClassBrowserRegistry[classBrowserName]["Extensions"]: return ClassBrowserRegistry[classBrowserName]["ReadModule"]( - module, path + module, searchPath ) if ext in __extensions["Ruby"]: @@ -145,7 +145,7 @@ classBrowserModule = getClassBrowserModule(moduleType) dictionary = ( - classBrowserModule.readmodule_ex(module, path, isTypeFile=isPyFile) + classBrowserModule.readmodule_ex(module, searchPath, isTypeFile=isPyFile) if classBrowserModule else {} ) @@ -244,6 +244,34 @@ raise ImportError +def determineSourceType(name, isPyFile=False): + """ + Function to determine the type of a source file given its name. + + @param name file name or module name + @type str + @param isPyFile flag indicating a Python file (defaults to False) + @type bool (optional) + @return source file type + @rtype int + """ + ext = os.path.splitext(name)[1].lower() + + if ext in __extensions["Ruby"]: + sourceType = RB_SOURCE + elif ext == ".ptl": + sourceType = PTL_SOURCE + elif ( + name.lower().endswith(tuple(Preferences.getPython("Python3Extensions"))) + or isPyFile + ): + sourceType = PY_SOURCE + else: + sourceType = UNKNOWN_SOURCE + + return sourceType + + def getIcon(filename): """ Function to get an icon name for the given file (only for class browsers provided
--- a/src/eric7/Utilities/ClassBrowsers/pyclbr.py Mon Feb 19 15:34:54 2024 +0100 +++ b/src/eric7/Utilities/ClassBrowsers/pyclbr.py Mon Feb 19 15:56:51 2024 +0100 @@ -20,6 +20,8 @@ from PyQt6.QtCore import QRegularExpression from eric7 import Utilities +from eric7.EricWidgets.EricApplication import ericApp +from eric7.SystemUtilities import FileSystemUtilities from eric7.Utilities import ClassBrowsers from . import ClbrBaseClasses @@ -395,7 +397,7 @@ self.importedNames[name].append(lineno) -def readmodule_ex(module, path=None, isTypeFile=False): +def readmodule_ex(module, searchPath=None, isTypeFile=False): """ Read a module file and return a dictionary of classes. @@ -405,29 +407,37 @@ @param module name of the module file @type str - @param path path the module should be searched in + @param searchPath path the module should be searched in @type list of str @param isTypeFile flag indicating a file of this type @type bool @return the resulting dictionary @rtype dict """ - # search the path for the module - path = [] if path is None else path[:] - f = None - if f is None: - fullpath = path[:] + sys.path[:] + fsInterface = ericApp().getObject("EricServer").getServiceInterface("FileSystem") + + if searchPath and FileSystemUtilities.isRemoteFileName(searchPath[0]): + type = ClassBrowsers.determineSourceType(module, isTypeFile) + file = fsInterface.join(searchPath[0], module) + else: + # search the path for the module + searchPath = [] if searchPath is None else searchPath[:] + fullpath = searchPath[:] + sys.path[:] f, file, (suff, mode, type) = ClassBrowsers.find_module( module, fullpath, isTypeFile ) - if f: - f.close() + if f: + f.close() + if type not in SUPPORTED_TYPES: # not Python source, can't do anything with this module return {} try: - src = Utilities.readEncodedFile(file)[0] + if FileSystemUtilities.isRemoteFileName(file): + src = fsInterface.readEncodedFile(file)[0] + else: + src = Utilities.readEncodedFile(file)[0] except (OSError, UnicodeError): # can't do anything with this module return {}
--- a/src/eric7/Utilities/ClassBrowsers/rbclbr.py Mon Feb 19 15:34:54 2024 +0100 +++ b/src/eric7/Utilities/ClassBrowsers/rbclbr.py Mon Feb 19 15:56:51 2024 +0100 @@ -17,6 +17,8 @@ from PyQt6.QtCore import QRegularExpression from eric7 import Utilities +from eric7.EricWidgets.EricApplication import ericApp +from eric7.SystemUtilities import FileSystemUtilities from eric7.Utilities import ClassBrowsers from . import ClbrBaseClasses @@ -277,31 +279,40 @@ self.setPrivate() -def readmodule_ex(module, path=None, isTypeFile=False): # noqa: U100 +def readmodule_ex(module, searchPath=None, isTypeFile=False): # noqa: U100 """ Read a Ruby file and return a dictionary of classes, functions and modules. @param module name of the Ruby file @type str - @param path path the file should be searched in + @param searchPath path the file should be searched in @type list of str @param isTypeFile flag indicating a file of this type @type bool @return the resulting dictionary @rtype dict """ - # search the path for the file - f = None - fullpath = [] if path is None else path[:] - f, file, (suff, mode, type) = ClassBrowsers.find_module(module, fullpath) - if f: - f.close() + fsInterface = ericApp().getObject("EricServer").getServiceInterface("FileSystem") + + if searchPath and FileSystemUtilities.isRemoteFileName(searchPath[0]): + type = ClassBrowsers.determineSourceType(module) + file = fsInterface.join(searchPath[0], module) + else: + # search the path for the module + fullpath = [] if searchPath is None else searchPath[:] + f, file, (suff, mode, type) = ClassBrowsers.find_module(module, fullpath) + if f: + f.close() + if type not in SUPPORTED_TYPES: # not Ruby source, can't do anything with this module return {} try: - src = Utilities.readEncodedFile(file)[0] + if FileSystemUtilities.isRemoteFileName(file): + src = fsInterface.readEncodedFile(file)[0] + else: + src = Utilities.readEncodedFile(file)[0] except (OSError, UnicodeError): # can't do anything with this module return {}