├── .gitignore ├── LICENSE ├── README.md ├── README_zh_CN.md ├── build.gradle ├── docs └── media │ ├── Add-Server.gif │ ├── Command.gif │ ├── Upload.gif │ └── small-logo.svg ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ ├── icons │ │ └── MyIcons.java │ └── tech │ │ └── lin2j │ │ └── idea │ │ └── plugin │ │ ├── action │ │ ├── AddCommandAction.java │ │ ├── ClassHotReloadAction.java │ │ ├── CleanConfigAction.java │ │ ├── CommandDialogAction.java │ │ ├── ConfigExportAction.java │ │ ├── ConfigImportAction.java │ │ ├── CopyCommandAction.java │ │ ├── CopyUploadProfileAction.java │ │ ├── EnterKeyAdapter.java │ │ ├── ExportAndImportAction.java │ │ ├── GithubAction.java │ │ ├── HomePageAction.java │ │ ├── HostMoreOpsAction.java │ │ ├── NewUpdateThreadAction.java │ │ ├── OpenTerminalAction.java │ │ ├── PasteCommandAction.java │ │ ├── PasteUploadProfileAction.java │ │ ├── SFTPTableMouseListener.java │ │ ├── ServerSearchKeyAdapter.java │ │ ├── TestConnectionAction.java │ │ ├── UploadDialogAction.java │ │ └── ftp │ │ │ ├── ChangePermissionAction.java │ │ │ ├── CopyFileNameAction.java │ │ │ ├── CopyFilePathAction.java │ │ │ ├── CreateNewFolderAction.java │ │ │ ├── DeleteFileAndDirAction.java │ │ │ ├── DownloadFileAndDirAction.java │ │ │ ├── FileAction.java │ │ │ ├── FilePropertiesAction.java │ │ │ ├── GoToDesktopAction.java │ │ │ ├── GoToParentFolderAction.java │ │ │ ├── HomeDirectoryAction.java │ │ │ ├── OpenFilePathAction.java │ │ │ ├── OpenPathInTerminalAction.java │ │ │ ├── ProjectPathAction.java │ │ │ ├── RefreshFolderAction.java │ │ │ ├── RowDoubleClickAction.java │ │ │ ├── ShowHiddenFileAndDirAction.java │ │ │ └── UploadFileAndDirAction.java │ │ ├── enums │ │ ├── AuthType.java │ │ ├── Constant.java │ │ ├── I18nType.java │ │ ├── SFTPAction.java │ │ ├── TransferEventType.java │ │ ├── TransferMode.java │ │ └── TransferState.java │ │ ├── event │ │ ├── ApplicationContext.java │ │ ├── ApplicationEvent.java │ │ ├── ApplicationListener.java │ │ ├── ApplicationPublisher.java │ │ └── listener │ │ │ └── UploadProfileSelectedListener.java │ │ ├── exception │ │ └── IllegalFileTypeException.java │ │ ├── factory │ │ ├── CustomTtyConnectorFactory.java │ │ └── DeployConsoleToolWindowFactory.java │ │ ├── file │ │ ├── ConsoleTransferListener.java │ │ ├── DirectoryInfo.java │ │ ├── LocalTableFile.java │ │ ├── PluginFileTypeRegistry.java │ │ ├── ProgressTableTransferListener.java │ │ ├── RemoteTableFile.java │ │ ├── TableFile.java │ │ ├── fileTypes │ │ │ ├── ConfigFileType.java │ │ │ ├── DmgFileType.java │ │ │ ├── EbookFileType.java │ │ │ ├── ExcelFileType.java │ │ │ ├── LogFileType.java │ │ │ ├── PdfFileType.java │ │ │ ├── PptFileType.java │ │ │ ├── SFTPFileType.java │ │ │ ├── SpecifiedArchiveFileType.java │ │ │ ├── VideoFileType.java │ │ │ └── WordFileType.java │ │ └── filter │ │ │ ├── ConsoleFileFilter.java │ │ │ ├── ExtExcludeFilter.java │ │ │ ├── FileAction.java │ │ │ ├── FileFilter.java │ │ │ ├── ListableFileFilter.java │ │ │ └── RegexFileFilter.java │ │ ├── model │ │ ├── Command.java │ │ ├── ConfigHelper.java │ │ ├── ConfigImportExport.java │ │ ├── ConfigPersistence.java │ │ ├── DeployProfile.java │ │ ├── EDPluginUpdateChecker.java │ │ ├── ExportOptions.java │ │ ├── HotReloadPersistence.java │ │ ├── NoneCommand.java │ │ ├── PluginConfigInitializer.java │ │ ├── PluginSetting.java │ │ ├── SeparatorCommand.java │ │ ├── UniqueModel.java │ │ ├── UploadProfile.java │ │ └── event │ │ │ ├── CommandAddEvent.java │ │ │ ├── CommandExecuteEvent.java │ │ │ ├── FileTransferEvent.java │ │ │ ├── TableRefreshEvent.java │ │ │ ├── UploadProfileAddEvent.java │ │ │ ├── UploadProfileExecuteEvent.java │ │ │ └── UploadProfileSelectedEvent.java │ │ ├── runner │ │ ├── ContentManagerAdapter.java │ │ ├── DeployConfigurationFactory.java │ │ ├── DeployRunConfiguration.java │ │ ├── DeployRunConfigurationOptions.java │ │ ├── DeployRunConfigurationType.java │ │ ├── DeployRunProfileState.java │ │ ├── DeploySettingsEditor.java │ │ ├── ParallelDeployRunProfileState.java │ │ └── process │ │ │ ├── ListExecutionResult.java │ │ │ ├── ListProcessHandler.java │ │ │ └── UploadProcessHandler.java │ │ ├── service │ │ ├── IHotReloadService.java │ │ ├── ISshService.java │ │ └── impl │ │ │ ├── HotReloadServiceImpl.java │ │ │ ├── PluginNotificationService.java │ │ │ └── SshjSshService.java │ │ ├── ssh │ │ ├── ClosableCloudTerminalProcess.java │ │ ├── CommandLog.java │ │ ├── ConsoleCommandLog.java │ │ ├── CustomTtyConnector.java │ │ ├── JavaProcess.java │ │ ├── SshConnection.java │ │ ├── SshConnectionManager.java │ │ ├── SshProcess.java │ │ ├── SshServer.java │ │ ├── SshStatus.java │ │ ├── SshUploadTask.java │ │ ├── exception │ │ │ └── RemoteSdkException.java │ │ └── sshj │ │ │ ├── SshjConnection.java │ │ │ ├── SshjLoggerFactory.java │ │ │ └── SshjTtyConnector.java │ │ ├── ui │ │ ├── DashboardView.java │ │ ├── component │ │ │ ├── ArrowLabel.java │ │ │ ├── HostActionPanel.java │ │ │ ├── HostBasicPanel.java │ │ │ ├── HostChainItem.java │ │ │ ├── HostDependencyPanel.java │ │ │ ├── HostProxyPanel.java │ │ │ └── ManualProxyPanel.java │ │ ├── dialog │ │ │ ├── AddCommandDialog.java │ │ │ ├── AddUploadProfileDialog.java │ │ │ ├── ChangePermissionsDialog.java │ │ │ ├── ClassRetransformDialog.java │ │ │ ├── FilePropertiesDialog.java │ │ │ ├── FilesDeleteConfirmDialog.java │ │ │ ├── HostSettingsDialog.java │ │ │ ├── ImportConfigPreviewDialog.java │ │ │ ├── InputConfirmDialog.java │ │ │ ├── PasswordInputDialog.java │ │ │ ├── PluginSettingsDialog.java │ │ │ ├── SelectCommandDialog.java │ │ │ ├── SelectServerDialog.java │ │ │ ├── SelectUploadProfileDialog.java │ │ │ ├── TransferConfirmDialog.java │ │ │ └── UploadProfileDialog.java │ │ ├── editor │ │ │ ├── SFTPEditor.java │ │ │ ├── SFTPEditorProvider.java │ │ │ ├── SFTPFileSystem.java │ │ │ └── SFTPVirtualFile.java │ │ ├── ftp │ │ │ ├── FTPConsole.java │ │ │ ├── ProgressTable.java │ │ │ └── container │ │ │ │ ├── AbstractFileTableContainer.java │ │ │ │ ├── FileTableContainer.java │ │ │ │ ├── LocalFileTableContainer.java │ │ │ │ └── RemoteFileTableContainer.java │ │ ├── module │ │ │ ├── ConsoleLogView.java │ │ │ └── DashboardView.java │ │ ├── render │ │ │ ├── CommandColoredListCellRenderer.java │ │ │ └── UploadProfileColoredListCellRenderer.java │ │ ├── settings │ │ │ ├── GeneralConfigurable.java │ │ │ ├── SFTPConfigurable.java │ │ │ └── ServerTagConfigurable.java │ │ └── table │ │ │ ├── ActionCellEditor.java │ │ │ ├── ActionCellRenderer.java │ │ │ ├── DeployProfileTableModel.java │ │ │ ├── FileNameCellRenderer.java │ │ │ ├── LocalFileTableModel.java │ │ │ ├── ProgressCell.java │ │ │ └── RemoteFileTableModel.java │ │ └── uitl │ │ ├── CommandUtil.java │ │ ├── EasyDeployPluginUtil.java │ │ ├── EncryptionUtil.java │ │ ├── FTPUtil.java │ │ ├── FileTransferSpeed.java │ │ ├── FileUtil.java │ │ ├── ImportExportUtil.java │ │ ├── MessagesBundle.java │ │ ├── PosixUtil.java │ │ ├── TerminalRunnerUtil.java │ │ ├── UiUtil.java │ │ └── WebBrowseUtil.java └── resources │ ├── META-INF │ ├── plugin.xml │ └── pluginIcon.svg │ ├── arthas.tar.gz │ ├── icons │ ├── actions │ │ ├── copy.svg │ │ ├── export_import.svg │ │ ├── github.svg │ │ ├── home-page.svg │ │ ├── host.svg │ │ ├── my-add.svg │ │ ├── my_clean.svg │ │ ├── my_connect.svg │ │ ├── my_export.svg │ │ ├── my_import.svg │ │ ├── my_lost_connect.svg │ │ ├── my_refresh.svg │ │ ├── my_settings.svg │ │ ├── my_share.svg │ │ ├── my_share_selected.svg │ │ ├── my_upload.svg │ │ ├── paste.svg │ │ ├── showHiddens.svg │ │ └── showHiddens_dark.svg │ ├── deploy.svg │ ├── deploy_dark.svg │ ├── easy-deploy.svg │ ├── fileTypes │ │ ├── c.svg │ │ ├── c_dark.svg │ │ ├── cpp.svg │ │ ├── cpp_dark.svg │ │ ├── dmg.svg │ │ ├── ebook.svg │ │ ├── excel.svg │ │ ├── log.svg │ │ ├── pdf.svg │ │ ├── ppt.svg │ │ ├── video.svg │ │ └── word.svg │ ├── filter.svg │ ├── message_blue.svg │ ├── sftp.svg │ ├── tag.svg │ ├── tag_dark.svg │ ├── transferToolWindow.svg │ ├── transferToolWindow_dark.svg │ └── upload_profile.svg │ ├── messages_en.properties │ └── messages_zh.properties └── test └── java └── tech └── lin2j └── idea └── plugin └── file └── FilterTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /target 3 | /logs 4 | .idea/ 5 | .svn/ 6 | *.iml 7 | *.ipr 8 | *.iws 9 | */*.log 10 | */target/ 11 | *.DS_Store 12 | *.classpath 13 | *.settings 14 | *.project 15 | .flattened-pom.xml 16 | .gradle 17 | build -------------------------------------------------------------------------------- /README_zh_CN.md: -------------------------------------------------------------------------------- 1 |

Easy Deploy

2 | 3 |

方便开发过程中部署升级服务的 Intellij 平台插件

4 | 5 |
6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | Easy Deploy 是我借鉴 Alibaba Cloud Toolkit 插件开发的一个方便自己在开发过程中部署服务的插件。相比较 Alibaba Cloud Toolkit,我开发的插件功能会少很多很多,因为 ACT 很多的功能我都用不上,对我来说它有点臃肿。 15 | 16 | 因此,我只取自己关注的那部分功能进行开发,这部分就是对服务器的管理以及发布的过程。我给这个插件起这个名是希望他能够帮助开发者简化开发过程的部署步骤,我会不断地优化它,完善它的功能。 17 | 18 | 这也是我开发的第一款 Idea 插件,很多问题都是通过长时间的搜索才一点一点的解决的,特别是 Swing 相关的知识,毕竟很多年没写了,再加上 Intellj 的封装,不同版本的 UI 可能会有些不同。因此如果你在下载和使用它过程中有问题的话,可以给我提 Issue。 19 | 20 | 👉👉 [去插件市场下载](https://plugins.jetbrains.com/plugin/19432-easy-deploy) 21 | 22 | # 支持 23 | 24 | 如果这个插件对你有帮助的话,请动动小手给仓库一个 star ⭐️⭐️。 25 | 26 | # 功能 27 | 28 | - [x] 添加/编辑/删除/搜索服务器信息 29 | - [x] 添加/编辑/删除/分享命令 30 | - [x] 上传文件或者目录,并支持过滤 31 | - [x] 文件(目录)上传配置 32 | - [x] 终端连接 33 | - [x] SSH 免密登录(私钥登录) 34 | - [x] SSH 代理跳板机 35 | - [x] Run/Debug Configuration (并行部署) 36 | - [x] 国际化 37 | - [x] SFTP 传输面板 38 | - [x] 插件设置 39 | - [x] 导出、导入、清除插件配置 40 | 41 | # 联系我🐾 42 | 43 | 在开发 Idea 插件方面我是一个新手,有很多问题可能处理得不是很好。 44 | 45 | 如果你有什么建议或者遇到什么bug,可以提 issues 也可以邮箱联系我,我会尽快回复你。 46 | 47 | 📮📮 linjinjia047@163.com 48 | 49 | 👻👻[去 Github 提 Issue](https://github.com/lin2j/easy-deploy/issues) -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.jetbrains.intellij' version '1.17.4' 3 | id 'java' 4 | } 5 | 6 | group 'tech.lin2j' 7 | version '1.3.8-241' 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | implementation 'com.hierynomus:sshj:0.39.0' 15 | } 16 | 17 | // See https://github.com/JetBrains/gradle-intellij-plugin/ 18 | intellij { 19 | version = '2024.1' 20 | // type = 'IU' 21 | plugins = [ 22 | 'com.intellij.java', 23 | "org.jetbrains.plugins.terminal", 24 | ] 25 | updateSinceUntilBuild = false 26 | } 27 | 28 | tasks.withType(JavaCompile).configureEach { 29 | sourceCompatibility = "17" 30 | targetCompatibility = "17" 31 | options.encoding = "UTF-8" 32 | options.compilerArgs << "-Xlint:unchecked" 33 | } 34 | 35 | test { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /docs/media/Add-Server.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lin2j/easy-deploy/b9fc0ec2029ef5149418180c6d737ffd8feadec8/docs/media/Add-Server.gif -------------------------------------------------------------------------------- /docs/media/Command.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lin2j/easy-deploy/b9fc0ec2029ef5149418180c6d737ffd8feadec8/docs/media/Command.gif -------------------------------------------------------------------------------- /docs/media/Upload.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lin2j/easy-deploy/b9fc0ec2029ef5149418180c6d737ffd8feadec8/docs/media/Upload.gif -------------------------------------------------------------------------------- /docs/media/small-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx2024m -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lin2j/easy-deploy/b9fc0ec2029ef5149418180c6d737ffd8feadec8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Easy-Deploy' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/AddCommandAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.project.Project; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import tech.lin2j.idea.plugin.model.Command; 8 | import tech.lin2j.idea.plugin.model.ConfigHelper; 9 | import tech.lin2j.idea.plugin.ui.dialog.AddCommandDialog; 10 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 11 | 12 | import java.util.List; 13 | import java.util.function.Consumer; 14 | 15 | /** 16 | * @author linjinjia 17 | * @date 2024/7/7 16:07 18 | */ 19 | public class AddCommandAction extends NewUpdateThreadAction { 20 | 21 | private static final String text = MessagesBundle.getText("action.common.command.add.text"); 22 | 23 | private final int sshId; 24 | private final Project project; 25 | private final Consumer action; 26 | 27 | public AddCommandAction(Project project, int sshId, Consumer action) { 28 | super(text, text, MyIcons.Actions.Add); 29 | this.sshId = sshId; 30 | this.project = project; 31 | this.action = action; 32 | } 33 | 34 | @Override 35 | public void actionPerformed(@NotNull AnActionEvent e) { 36 | Command tmp = new Command(sshId); 37 | boolean exitOk = new AddCommandDialog(project, tmp).showAndGet(); 38 | if (exitOk && action != null) { 39 | List list = ConfigHelper.getCommandsBySshId(sshId); 40 | Command newCmd = list.get(list.size() - 1); 41 | action.accept(newCmd); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ClassHotReloadAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.progress.ProgressIndicator; 6 | import com.intellij.openapi.progress.ProgressManager; 7 | import com.intellij.openapi.progress.Task; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.ui.Messages; 10 | import org.jetbrains.annotations.NotNull; 11 | import tech.lin2j.idea.plugin.exception.IllegalFileTypeException; 12 | import tech.lin2j.idea.plugin.ui.dialog.ClassRetransformDialog; 13 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 14 | 15 | import javax.swing.SwingUtilities; 16 | 17 | /** 18 | * @author linjinjia 19 | * @date 2024/10/20 15:31 20 | */ 21 | public class ClassHotReloadAction extends AnAction { 22 | 23 | public ClassHotReloadAction() { 24 | super(MessagesBundle.getText("dialog.retransform.frame")); 25 | } 26 | 27 | @Override 28 | public void actionPerformed(@NotNull AnActionEvent e) { 29 | try { 30 | Project project = e.getProject(); 31 | assert project != null; 32 | ClassRetransformDialog dialog = new ClassRetransformDialog(project, e); 33 | dialog.setData(); 34 | dialog.show(); 35 | } catch (IllegalFileTypeException err) { 36 | Messages.showErrorDialog("Class reload only supports Java files", "File Type Error"); 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/CleanConfigAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import icons.MyIcons; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.event.ApplicationContext; 7 | import tech.lin2j.idea.plugin.model.ConfigHelper; 8 | import tech.lin2j.idea.plugin.model.event.TableRefreshEvent; 9 | import tech.lin2j.idea.plugin.ui.dialog.InputConfirmDialog; 10 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 11 | 12 | /** 13 | * 14 | * @author linjinjia 15 | * @date 2024/7/28 18:21 16 | */ 17 | public class CleanConfigAction extends NewUpdateThreadAction { 18 | 19 | private static final String text = MessagesBundle.getText("action.dashboard.clean.text"); 20 | 21 | public CleanConfigAction() { 22 | super(text, text, MyIcons.Actions.Clean); 23 | } 24 | 25 | @Override 26 | public void actionPerformed(@NotNull AnActionEvent e) { 27 | String title = MessagesBundle.getText("dialog.clean.title"); 28 | String msg = MessagesBundle.getText("dialog.clean.tip"); 29 | String okText = MessagesBundle.getText("dialog.clean.ok-text"); 30 | String confirm = "Clean All Configuration"; 31 | 32 | boolean isOk = new InputConfirmDialog(null, title, msg, confirm, okText).showAndGet(); 33 | if (isOk) { 34 | ConfigHelper.cleanConfig(); 35 | ApplicationContext.getApplicationContext().publishEvent(new TableRefreshEvent(true)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/CommandDialogAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import tech.lin2j.idea.plugin.event.ApplicationContext; 5 | import tech.lin2j.idea.plugin.ui.dialog.SelectCommandDialog; 6 | 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/5/5 12:26 13 | */ 14 | public class CommandDialogAction implements ActionListener { 15 | 16 | private final int sshId; 17 | private final Project project; 18 | 19 | public CommandDialogAction(int sshId, Project project) { 20 | this.sshId = sshId; 21 | this.project = project; 22 | } 23 | 24 | @Override 25 | public void actionPerformed(ActionEvent e) { 26 | SelectCommandDialog ui = new SelectCommandDialog(project, sshId); 27 | ApplicationContext.getApplicationContext().addApplicationListener(ui); 28 | ui.showAndGet(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/CopyCommandAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.google.gson.Gson; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.ide.CopyPasteManager; 6 | import com.intellij.util.ui.TextTransferable; 7 | import icons.MyIcons; 8 | import org.jetbrains.annotations.NotNull; 9 | import tech.lin2j.idea.plugin.model.Command; 10 | 11 | import java.util.function.Supplier; 12 | 13 | /** 14 | * @author linjinjia 15 | * @date 2024/6/9 16:09 16 | */ 17 | public class CopyCommandAction extends NewUpdateThreadAction { 18 | 19 | private final Supplier provider; 20 | 21 | public CopyCommandAction(Command command) { 22 | this(() -> command); 23 | } 24 | 25 | public CopyCommandAction(Supplier provider) { 26 | super("Copy Command", "Copy command", MyIcons.Actions.Copy); 27 | this.provider = provider; 28 | 29 | } 30 | 31 | @Override 32 | public void actionPerformed(@NotNull AnActionEvent e) { 33 | if (provider.get() == null) { 34 | return; 35 | } 36 | Gson gson = new Gson(); 37 | String json = gson.toJson(provider.get()); 38 | CopyPasteManager.getInstance().setContents(new TextTransferable(json)); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/CopyUploadProfileAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.google.gson.Gson; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.ide.CopyPasteManager; 6 | import com.intellij.util.ui.TextTransferable; 7 | import icons.MyIcons; 8 | import org.jetbrains.annotations.NotNull; 9 | import tech.lin2j.idea.plugin.model.UploadProfile; 10 | 11 | import java.util.function.Supplier; 12 | 13 | /** 14 | * @author linjinjia 15 | * @date 2024/6/9 16:09 16 | */ 17 | public class CopyUploadProfileAction extends NewUpdateThreadAction { 18 | 19 | private final Supplier provider; 20 | 21 | public CopyUploadProfileAction(UploadProfile profile) { 22 | this(() -> profile); 23 | } 24 | 25 | public CopyUploadProfileAction(Supplier provider) { 26 | super("Copy Profile", "Copy profile", MyIcons.Actions.Copy); 27 | this.provider = provider; 28 | 29 | } 30 | 31 | @Override 32 | public void actionPerformed(@NotNull AnActionEvent e) { 33 | if (provider.get() == null) { 34 | return; 35 | } 36 | Gson gson = new Gson(); 37 | String json = gson.toJson(provider.get()); 38 | CopyPasteManager.getInstance().setContents(new TextTransferable(json)); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/EnterKeyAdapter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import java.awt.event.KeyAdapter; 4 | import java.awt.event.KeyEvent; 5 | 6 | /** 7 | * 8 | * @author linjinjia 9 | * @date 2024/8/7 21:09 10 | */ 11 | public abstract class EnterKeyAdapter extends KeyAdapter { 12 | 13 | @Override 14 | public void keyPressed(KeyEvent e) { 15 | if (e.getKeyCode() != KeyEvent.VK_ENTER) { 16 | return; 17 | } 18 | doAction(e); 19 | } 20 | 21 | protected abstract void doAction(KeyEvent e); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ExportAndImportAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.ActionGroup; 4 | import com.intellij.openapi.actionSystem.AnAction; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import icons.MyIcons; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/7/20 22:56 14 | */ 15 | public class ExportAndImportAction extends ActionGroup { 16 | 17 | private static final String text = MessagesBundle.getText("action.dashboard.export-import.text"); 18 | 19 | 20 | public ExportAndImportAction() { 21 | super(text, text, MyIcons.Actions.ExportAndImport); 22 | setPopup(true); 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public AnAction[] getChildren(@Nullable AnActionEvent e) { 28 | return new AnAction[]{ 29 | new ConfigImportAction(), 30 | new ConfigExportAction(), 31 | new CleanConfigAction(), 32 | }; 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/GithubAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import icons.MyIcons; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.uitl.WebBrowseUtil; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2024/4/25 22:43 11 | */ 12 | public class GithubAction extends NewUpdateThreadAction { 13 | public GithubAction() { 14 | super("Github", "Plugin github repository", MyIcons.Actions.Github); 15 | } 16 | 17 | @Override 18 | public void actionPerformed(@NotNull AnActionEvent e) { 19 | WebBrowseUtil.browse("https://github.com/lin2j/easy-deploy"); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/HomePageAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import icons.MyIcons; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 7 | import tech.lin2j.idea.plugin.uitl.WebBrowseUtil; 8 | 9 | /** 10 | * @author linjinjia 11 | * @date 2024/4/25 22:43 12 | */ 13 | public class HomePageAction extends NewUpdateThreadAction { 14 | private static final String text = MessagesBundle.getText("action.dashboard.home-page.text"); 15 | 16 | public HomePageAction() { 17 | super(text, "Plugin Home page", MyIcons.EasyDeploy); 18 | } 19 | 20 | @Override 21 | public void actionPerformed(@NotNull AnActionEvent e) { 22 | WebBrowseUtil.browse("https://lin2j.tech/md/easy-deploy/brief.html"); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/NewUpdateThreadAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.actionSystem.ActionUpdateThread; 4 | import com.intellij.openapi.actionSystem.AnAction; 5 | import com.intellij.openapi.util.NlsActions; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | import java.util.function.Supplier; 11 | 12 | /** 13 | * @author linjinjia 14 | * @date 2024/8/18 18:21 15 | */ 16 | public abstract class NewUpdateThreadAction extends AnAction { 17 | 18 | public NewUpdateThreadAction() { 19 | } 20 | 21 | public NewUpdateThreadAction(@Nullable Icon icon) { 22 | super(icon); 23 | } 24 | 25 | public NewUpdateThreadAction(@Nullable @NlsActions.ActionText String text) { 26 | super(text); 27 | } 28 | 29 | public NewUpdateThreadAction(@NotNull Supplier<@NlsActions.ActionText String> dynamicText) { 30 | super(dynamicText); 31 | } 32 | 33 | public NewUpdateThreadAction(@Nullable @NlsActions.ActionText String text, @Nullable @NlsActions.ActionDescription String description, @Nullable Icon icon) { 34 | super(text, description, icon); 35 | } 36 | 37 | public NewUpdateThreadAction(@NotNull @NlsActions.ActionText Supplier text, @Nullable @NlsActions.ActionDescription Supplier description, @Nullable Supplier icon) { 38 | super(text, description, icon); 39 | } 40 | 41 | public NewUpdateThreadAction(@NotNull @NlsActions.ActionText Supplier text, @NotNull @NlsActions.ActionDescription Supplier description) { 42 | super(text, description); 43 | } 44 | 45 | public NewUpdateThreadAction(@NotNull Supplier<@NlsActions.ActionText String> dynamicText, @Nullable Icon icon) { 46 | super(dynamicText, icon); 47 | } 48 | 49 | public NewUpdateThreadAction(@NotNull Supplier<@NlsActions.ActionText String> dynamicText, @NotNull Supplier<@NlsActions.ActionDescription String> dynamicDescription, @Nullable Icon icon) { 50 | super(dynamicText, dynamicDescription, icon); 51 | } 52 | 53 | @Override 54 | public @NotNull ActionUpdateThread getActionUpdateThread() { 55 | return ActionUpdateThread.BGT; 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/PasteCommandAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonSyntaxException; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import com.intellij.openapi.ide.CopyPasteManager; 7 | import com.intellij.openapi.ui.Messages; 8 | import com.intellij.openapi.util.text.StringUtil; 9 | import icons.MyIcons; 10 | import org.apache.commons.lang.StringUtils; 11 | import org.jetbrains.annotations.NotNull; 12 | import tech.lin2j.idea.plugin.model.Command; 13 | 14 | import javax.swing.SwingUtilities; 15 | import java.awt.datatransfer.DataFlavor; 16 | import java.util.function.Consumer; 17 | 18 | /** 19 | * @author linjinjia 20 | * @date 2024/6/9 16:12 21 | */ 22 | public class PasteCommandAction extends NewUpdateThreadAction { 23 | 24 | private final Consumer consumer; 25 | 26 | public PasteCommandAction(Consumer consumer) { 27 | super("Paste Command", "Paste command", MyIcons.Actions.Paste); 28 | this.consumer = consumer; 29 | } 30 | 31 | @Override 32 | public void actionPerformed(@NotNull AnActionEvent e) { 33 | try { 34 | String json = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor); 35 | 36 | if (StringUtil.isEmpty(json)) { 37 | return; 38 | } 39 | Gson gson = new Gson(); 40 | Command cmd = gson.fromJson(json, Command.class); 41 | if (cmd == null) { 42 | return; 43 | } 44 | consumer.accept(cmd); 45 | } catch (JsonSyntaxException err) { 46 | SwingUtilities.invokeLater(() -> Messages.showErrorDialog("Json parse exception", "Parse Error")); 47 | } 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/PasteUploadProfileAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonSyntaxException; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import com.intellij.openapi.ide.CopyPasteManager; 7 | import com.intellij.openapi.ui.Messages; 8 | import com.intellij.openapi.util.text.StringUtil; 9 | import icons.MyIcons; 10 | import org.jetbrains.annotations.NotNull; 11 | import tech.lin2j.idea.plugin.model.UploadProfile; 12 | 13 | import javax.swing.SwingUtilities; 14 | import java.awt.datatransfer.DataFlavor; 15 | import java.util.function.Consumer; 16 | 17 | /** 18 | * @author linjinjia 19 | * @date 2024/6/9 16:12 20 | */ 21 | public class PasteUploadProfileAction extends NewUpdateThreadAction { 22 | 23 | private final Consumer consumer; 24 | 25 | public PasteUploadProfileAction(Consumer consumer) { 26 | super("Paste Profile", "Paste profile", MyIcons.Actions.Paste); 27 | this.consumer = consumer; 28 | } 29 | 30 | @Override 31 | public void actionPerformed(@NotNull AnActionEvent e) { 32 | try { 33 | String json = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor); 34 | if (StringUtil.isEmpty(json)) { 35 | return; 36 | } 37 | Gson gson = new Gson(); 38 | UploadProfile up = gson.fromJson(json, UploadProfile.class); 39 | if (up == null) { 40 | return; 41 | } 42 | up.setCommandId(null); 43 | consumer.accept(up); 44 | } catch (JsonSyntaxException err) { 45 | SwingUtilities.invokeLater(() -> { 46 | Messages.showErrorDialog("Json parse exception", "Parse Error"); 47 | }); 48 | } 49 | 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ServerSearchKeyAdapter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.util.text.StringUtil; 4 | import com.intellij.ui.SearchTextField; 5 | import org.apache.commons.collections.CollectionUtils; 6 | import tech.lin2j.idea.plugin.model.ConfigHelper; 7 | import tech.lin2j.idea.plugin.ssh.SshServer; 8 | 9 | import java.awt.event.KeyAdapter; 10 | import java.awt.event.KeyEvent; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.function.Consumer; 14 | 15 | /** 16 | * keyboard listener 17 | * 18 | * @author linjinjia 2024/5/16 23:11 19 | */ 20 | public class ServerSearchKeyAdapter extends KeyAdapter { 21 | 22 | private final SearchTextField searchInput; 23 | private final Consumer> action; 24 | 25 | public ServerSearchKeyAdapter(SearchTextField searchInput, Consumer> action) { 26 | this.searchInput = searchInput; 27 | this.action = action; 28 | } 29 | 30 | @Override 31 | public void keyPressed(KeyEvent e) { 32 | search(e); 33 | } 34 | 35 | @Override 36 | public void keyReleased(KeyEvent e) { 37 | search(e); 38 | } 39 | 40 | 41 | private void search(KeyEvent e) { 42 | List searchResult = new ArrayList<>(); 43 | List serverInConfig = ConfigHelper.sshServers(); 44 | if (CollectionUtils.isEmpty(serverInConfig)) { 45 | return; 46 | } 47 | 48 | String keyword = searchInput.getText(); 49 | if (StringUtil.isEmpty(keyword)) { 50 | action.accept(serverInConfig); 51 | return; 52 | } 53 | 54 | for (SshServer server : serverInConfig) { 55 | if (server.getIp().contains(keyword)) { 56 | searchResult.add(server); 57 | continue; 58 | } 59 | if (server.getUsername().contains(keyword)) { 60 | searchResult.add(server); 61 | continue; 62 | } 63 | String desc = server.getDescription(); 64 | if (StringUtil.isNotEmpty(desc) && desc.contains(keyword)) { 65 | searchResult.add(server); 66 | } 67 | } 68 | 69 | action.accept(searchResult); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/TestConnectionAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.application.ApplicationManager; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.ProgressManager; 6 | import com.intellij.openapi.progress.Task; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.ui.Messages; 9 | import org.jetbrains.annotations.NotNull; 10 | import tech.lin2j.idea.plugin.service.ISshService; 11 | import tech.lin2j.idea.plugin.service.impl.PluginNotificationService; 12 | import tech.lin2j.idea.plugin.service.impl.SshjSshService; 13 | import tech.lin2j.idea.plugin.ssh.SshServer; 14 | import tech.lin2j.idea.plugin.ssh.SshStatus; 15 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 16 | 17 | import java.awt.event.ActionEvent; 18 | import java.awt.event.ActionListener; 19 | 20 | /** 21 | * 22 | * @author linjinjia 23 | * @date 2024/11/28 22:27 24 | */ 25 | public class TestConnectionAction implements ActionListener { 26 | private final SshServer sshServer; 27 | private final Project project; 28 | private final ISshService sshService; 29 | private final PluginNotificationService notificationService; 30 | 31 | public TestConnectionAction(Project project, SshServer server) { 32 | this.sshServer = server; 33 | this.project = project; 34 | sshService = ApplicationManager.getApplication().getService(ISshService.class); 35 | notificationService = ApplicationManager.getApplication().getService(PluginNotificationService.class); 36 | } 37 | 38 | @Override 39 | public void actionPerformed(ActionEvent e) { 40 | String title = String.format("Testing %s:%s", sshServer.getIp(), sshServer.getPort()); 41 | ProgressManager.getInstance().run(new Task.Backgroundable(project, title) { 42 | @Override 43 | public void run(@NotNull ProgressIndicator indicator) { 44 | SshStatus status = sshService.isValid(sshServer); 45 | 46 | String title = MessagesBundle.getText("dialog.panel.host.test-connect.title"); 47 | String tip = MessagesBundle.getText("dialog.panel.host.test-connect.tip"); 48 | String msg = status.isSuccess() ? tip : status.getMessage(); 49 | notificationService.showNotification(project, title, msg); 50 | } 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/UploadDialogAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import tech.lin2j.idea.plugin.event.ApplicationContext; 5 | import tech.lin2j.idea.plugin.model.ConfigHelper; 6 | import tech.lin2j.idea.plugin.ui.dialog.UploadProfileDialog; 7 | 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/5/5 12:26 14 | */ 15 | public class UploadDialogAction implements ActionListener { 16 | 17 | private final int sshId; 18 | private final Project project; 19 | 20 | public UploadDialogAction(int sshId, Project project) { 21 | this.sshId = sshId; 22 | this.project = project; 23 | } 24 | 25 | @Override 26 | public void actionPerformed(ActionEvent e) { 27 | UploadProfileDialog dialog = new UploadProfileDialog(project, ConfigHelper.getSshServerById(sshId)); 28 | ApplicationContext.getApplicationContext().addApplicationListener(dialog); 29 | dialog.showAndGet(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/ChangePermissionAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.apache.commons.collections.CollectionUtils; 6 | import org.jetbrains.annotations.NotNull; 7 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 8 | import tech.lin2j.idea.plugin.file.RemoteTableFile; 9 | import tech.lin2j.idea.plugin.file.TableFile; 10 | import tech.lin2j.idea.plugin.ui.dialog.ChangePermissionsDialog; 11 | import tech.lin2j.idea.plugin.ui.ftp.container.RemoteFileTableContainer; 12 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author linjinjia 18 | * @date 2024/4/4 17:24 19 | */ 20 | public class ChangePermissionAction extends NewUpdateThreadAction { 21 | private static final String text = MessagesBundle.getText("action.ftp.popup.permission.text"); 22 | 23 | private final RemoteFileTableContainer container; 24 | 25 | public ChangePermissionAction(RemoteFileTableContainer container) { 26 | super(text, "Change permission of file and directory", AllIcons.Actions.ChangeView); 27 | this.container = container; 28 | } 29 | 30 | @Override 31 | public void actionPerformed(@NotNull AnActionEvent e) { 32 | List fileList = container.getSelectedFiles(); 33 | if (CollectionUtils.isNotEmpty(fileList)) { 34 | RemoteTableFile file = (RemoteTableFile) fileList.get(0); 35 | boolean refresh = new ChangePermissionsDialog(file, container.getFTPClient()).showAndGet(); 36 | if (refresh) { 37 | container.refreshFileList(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/CopyFileNameAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.openapi.ide.CopyPasteManager; 4 | import com.intellij.util.ui.TextTransferable; 5 | import tech.lin2j.idea.plugin.file.TableFile; 6 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 7 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 8 | 9 | /** 10 | * 11 | * @author linjinjia 12 | * @date 2024/5/24 23:28 13 | */ 14 | public class CopyFileNameAction extends FileAction { 15 | private static final String text = MessagesBundle.getText("action.ftp.popup.copy.filename.text"); 16 | 17 | public CopyFileNameAction(FileTableContainer container) { 18 | super(text, container); 19 | } 20 | 21 | @Override 22 | protected void handle(TableFile file) { 23 | String data = file.getName(); 24 | CopyPasteManager.getInstance().setContents(new TextTransferable(data)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/CopyFilePathAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.openapi.ide.CopyPasteManager; 4 | import com.intellij.util.ui.TextTransferable; 5 | import tech.lin2j.idea.plugin.file.TableFile; 6 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 7 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 8 | 9 | /** 10 | * 11 | * @author linjinjia 12 | * @date 2024/5/24 21:42 13 | */ 14 | public class CopyFilePathAction extends FileAction { 15 | private static final String text = MessagesBundle.getText("action.ftp.popup.copy.path.text"); 16 | 17 | public CopyFilePathAction(FileTableContainer container) { 18 | super(text, container); 19 | } 20 | 21 | 22 | @Override 23 | protected void handle(TableFile file) { 24 | String path = file.getFilePath(); 25 | CopyPasteManager.getInstance().setContents(new TextTransferable(path)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/CreateNewFolderAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.ui.Messages; 6 | import com.intellij.openapi.util.text.StringUtil; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 11 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 12 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 13 | 14 | import java.io.IOException; 15 | 16 | /** 17 | * @author linjinjia 18 | * @date 2024/4/4 17:09 19 | */ 20 | public class CreateNewFolderAction extends NewUpdateThreadAction { 21 | 22 | public static final Logger log = LoggerFactory.getLogger(CreateNewFolderAction.class); 23 | 24 | private static final String text = MessagesBundle.getText("action.ftp.new-folder.text"); 25 | private static final String desc = MessagesBundle.getText("action.ftp.new-folder.description"); 26 | 27 | private final FileTableContainer container; 28 | 29 | 30 | public CreateNewFolderAction(FileTableContainer container) { 31 | super(text, desc, AllIcons.Actions.NewFolder); 32 | this.container = container; 33 | } 34 | 35 | @Override 36 | public void actionPerformed(@NotNull AnActionEvent e) { 37 | String folderName = Messages.showInputDialog("Folder Name", "Create Folder", AllIcons.Actions.NewFolder); 38 | if (StringUtil.isEmpty(folderName)) { 39 | return; 40 | } 41 | if (!folderName.startsWith("/")) { 42 | folderName = "/" + folderName; 43 | } 44 | String path = container.getPath() + folderName; 45 | String err = null; 46 | boolean success = false; 47 | try { 48 | success = container.createNewFolder(path); 49 | if (success) { 50 | container.refreshFileList(); 51 | } 52 | } catch (IOException ex) { 53 | log.error(ex.getMessage(), e); 54 | err = ex.getMessage(); 55 | } 56 | if (!success) { 57 | Messages.showErrorDialog("create directory failed: " + err , "Create Folder Error"); 58 | } 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/DeleteFileAndDirAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.apache.commons.collections.CollectionUtils; 6 | import org.jetbrains.annotations.NotNull; 7 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 8 | import tech.lin2j.idea.plugin.file.TableFile; 9 | import tech.lin2j.idea.plugin.ui.dialog.FilesDeleteConfirmDialog; 10 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 11 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @author linjinjia 17 | * @date 2024/4/4 17:11 18 | */ 19 | public class DeleteFileAndDirAction extends NewUpdateThreadAction { 20 | private static final String text = MessagesBundle.getText("action.ftp.delete.text"); 21 | private static final String desc = MessagesBundle.getText("action.ftp.delete.description"); 22 | 23 | private final FileTableContainer container; 24 | 25 | public DeleteFileAndDirAction(FileTableContainer container) { 26 | super(text, desc, AllIcons.Actions.Cancel); 27 | this.container = container; 28 | } 29 | 30 | public DeleteFileAndDirAction(int count, FileTableContainer container) { 31 | this(container); 32 | if (count > 1) { 33 | String text = "Delete (" + count + " Selected)"; 34 | getTemplatePresentation().setText(text); 35 | } 36 | } 37 | 38 | @Override 39 | public void actionPerformed(@NotNull AnActionEvent e) { 40 | List selectedFiles = container.getSelectedFiles(); 41 | if (CollectionUtils.isEmpty(selectedFiles)) { 42 | return; 43 | } 44 | 45 | boolean confirm = new FilesDeleteConfirmDialog(selectedFiles, null).showAndGet(); 46 | if (!confirm) { 47 | return; 48 | } 49 | 50 | for (TableFile selectedFile : selectedFiles) { 51 | container.deleteFileAndDir(selectedFile); 52 | } 53 | 54 | container.refreshFileList(); 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/DownloadFileAndDirAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.enums.TransferEventType; 8 | import tech.lin2j.idea.plugin.event.ApplicationContext; 9 | import tech.lin2j.idea.plugin.model.event.FileTransferEvent; 10 | import tech.lin2j.idea.plugin.ui.ftp.container.RemoteFileTableContainer; 11 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 12 | 13 | /** 14 | * @author linjinjia 15 | * @date 2024/4/4 17:24 16 | */ 17 | public class DownloadFileAndDirAction extends NewUpdateThreadAction { 18 | private static final String text = MessagesBundle.getText("action.ftp.download.text"); 19 | private static final String desc = MessagesBundle.getText("action.ftp.download.description"); 20 | 21 | private final RemoteFileTableContainer container; 22 | 23 | public DownloadFileAndDirAction(RemoteFileTableContainer container) { 24 | super(text, desc, AllIcons.Actions.Download); 25 | this.container = container; 26 | } 27 | 28 | public DownloadFileAndDirAction(int count, RemoteFileTableContainer container) { 29 | this(container); 30 | if (count > 1) { 31 | String text = "Download (" + count + " Selected)"; 32 | getTemplatePresentation().setText(text); 33 | } 34 | } 35 | 36 | 37 | @Override 38 | public void actionPerformed(@NotNull AnActionEvent e) { 39 | FileTransferEvent event = new FileTransferEvent(container, false, TransferEventType.START); 40 | ApplicationContext.getApplicationContext().publishEvent(event); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/FileAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import org.apache.commons.collections.CollectionUtils; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.file.TableFile; 8 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 14 | * 15 | * @author linjinjia 16 | * @date 2024/5/24 21:38 17 | */ 18 | public abstract class FileAction extends NewUpdateThreadAction { 19 | 20 | public FileTableContainer container; 21 | 22 | protected FileAction(String text, FileTableContainer container) { 23 | super(text); 24 | this.container = container; 25 | } 26 | 27 | @Override 28 | public void actionPerformed(@NotNull AnActionEvent e) { 29 | List files = container.getSelectedFiles(); 30 | if (CollectionUtils.isEmpty(files)) { 31 | return; 32 | } 33 | handle(files.get(0)); 34 | } 35 | 36 | protected abstract void handle(TableFile file); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/FilePropertiesAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import tech.lin2j.idea.plugin.file.TableFile; 5 | import tech.lin2j.idea.plugin.ui.dialog.FilePropertiesDialog; 6 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 7 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 8 | 9 | /** 10 | * 11 | * @author linjinjia 12 | * @date 2024/5/24 21:43 13 | */ 14 | public class FilePropertiesAction extends FileAction { 15 | private static final String text = MessagesBundle.getText("action.ftp.popup.properties.text"); 16 | 17 | public FilePropertiesAction(FileTableContainer container) { 18 | super(text, container); 19 | getTemplatePresentation().setIcon(AllIcons.Actions.Properties); 20 | } 21 | 22 | @Override 23 | protected void handle(TableFile file) { 24 | new FilePropertiesDialog(file).show(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/GoToDesktopAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import org.jetbrains.annotations.NotNull; 7 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 8 | import tech.lin2j.idea.plugin.ui.ftp.container.LocalFileTableContainer; 9 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/4 16:20 14 | */ 15 | public class GoToDesktopAction extends NewUpdateThreadAction { 16 | private static final String text = MessagesBundle.getText("action.ftp.desktop.text"); 17 | private static final String desc = MessagesBundle.getText("action.ftp.desktop.description"); 18 | 19 | private final LocalFileTableContainer container; 20 | 21 | public GoToDesktopAction(LocalFileTableContainer container) { 22 | super(text, desc, AllIcons.Nodes.Desktop); 23 | this.container = container; 24 | } 25 | 26 | @Override 27 | public void actionPerformed(@NotNull AnActionEvent e) { 28 | VirtualFile desktop = container.getDesktopDirectory(); 29 | if (desktop != null) { 30 | container.setPath(desktop.getPath()); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/GoToParentFolderAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 8 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/4/4 16:40 13 | */ 14 | public class GoToParentFolderAction extends NewUpdateThreadAction { 15 | private static final String text = MessagesBundle.getText("action.ftp.parent.text"); 16 | private static final String desc = MessagesBundle.getText("action.ftp.parent.description"); 17 | 18 | 19 | private final FileTableContainer container; 20 | 21 | public GoToParentFolderAction(FileTableContainer container) { 22 | super(text, desc, AllIcons.Actions.Rollback); 23 | this.container = container; 24 | } 25 | 26 | @Override 27 | public void actionPerformed(@NotNull AnActionEvent e) { 28 | container.setPath(container.getParentPath()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/HomeDirectoryAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.util.text.StringUtil; 6 | import org.jetbrains.annotations.NotNull; 7 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 8 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 9 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/4 16:19 14 | */ 15 | public class HomeDirectoryAction extends NewUpdateThreadAction { 16 | private static final String text = MessagesBundle.getText("action.ftp.home.text"); 17 | private static final String desc = MessagesBundle.getText("action.ftp.home.description"); 18 | 19 | private final FileTableContainer container; 20 | 21 | public HomeDirectoryAction(FileTableContainer container) { 22 | super(text, desc, AllIcons.Nodes.HomeFolder); 23 | this.container = container; 24 | } 25 | 26 | @Override 27 | public void actionPerformed(@NotNull AnActionEvent e) { 28 | if (StringUtil.isEmpty(container.getHomePath())) { 29 | return; 30 | } 31 | container.setPath(container.getHomePath()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/OpenFilePathAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.ui.Messages; 5 | import com.intellij.openapi.util.SystemInfo; 6 | import org.jetbrains.annotations.NotNull; 7 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 8 | import tech.lin2j.idea.plugin.file.TableFile; 9 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 10 | import tech.lin2j.idea.plugin.uitl.FileUtil; 11 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 12 | 13 | import javax.swing.SwingUtilities; 14 | import java.io.IOException; 15 | import java.util.List; 16 | 17 | /** 18 | * 19 | * @author linjinjia 20 | * @date 2024/7/15 22:37 21 | */ 22 | public class OpenFilePathAction extends NewUpdateThreadAction { 23 | 24 | private static final String winText = MessagesBundle.getText("action.ftp.popup.open-in-win.text"); 25 | private static final String macText = MessagesBundle.getText("action.ftp.popup.open-in-mac.text"); 26 | private static final String text = SystemInfo.isMac ? macText : winText; 27 | private static final String desc = MessagesBundle.getText("action.ftp.popup.open-in.desc"); 28 | private static final String errorTitle = MessagesBundle.getText("action.ftp.popup.open-in.error.title"); 29 | private static final String errorTip = MessagesBundle.getText("action.ftp.popup.open-in.error.tip"); 30 | 31 | private final FileTableContainer tableContainer; 32 | 33 | public OpenFilePathAction(FileTableContainer tableContainer) { 34 | super(text, desc, null); 35 | this.tableContainer = tableContainer; 36 | } 37 | 38 | @Override 39 | public void actionPerformed(@NotNull AnActionEvent e) { 40 | String targetPath = tableContainer.getPath(); 41 | try { 42 | List files = tableContainer.getSelectedFiles(); 43 | if (files != null && files.size() > 0 && files.get(0).isDirectory()) { 44 | targetPath = files.get(0).getFilePath(); 45 | } 46 | FileUtil.openDir(targetPath); 47 | } catch (IOException ex) { 48 | SwingUtilities.invokeLater(() -> Messages.showErrorDialog(errorTip + ex.getMessage(), errorTitle)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/OpenPathInTerminalAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.project.Project; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.action.OpenTerminalAction; 8 | import tech.lin2j.idea.plugin.file.TableFile; 9 | import tech.lin2j.idea.plugin.ui.ftp.container.RemoteFileTableContainer; 10 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @author linjinjia 16 | * @date 2024/7/10 22:20 17 | */ 18 | public class OpenPathInTerminalAction extends NewUpdateThreadAction { 19 | 20 | private static final String text = MessagesBundle.getText("action.ftp.popup.open-in-ftp.text"); 21 | private static final String desc = MessagesBundle.getText("action.ftp.popup.open-in-ftp.desc"); 22 | 23 | private final RemoteFileTableContainer tableContainer; 24 | 25 | public OpenPathInTerminalAction(RemoteFileTableContainer tableContainer) { 26 | super(text, desc, null); 27 | this.tableContainer = tableContainer; 28 | } 29 | 30 | @Override 31 | public void actionPerformed(@NotNull AnActionEvent e) { 32 | String workingDirectory = tableContainer.getPath(); 33 | List files = tableContainer.getSelectedFiles(); 34 | if (files != null && files.size() > 0 && files.get(0).isDirectory()) { 35 | workingDirectory = files.get(0).getFilePath(); 36 | } 37 | Integer sshId = tableContainer.getSshId(); 38 | Project project = tableContainer.getProject(); 39 | 40 | new OpenTerminalAction(sshId, project, workingDirectory).actionPerformed(null); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/ProjectPathAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.ui.ftp.container.LocalFileTableContainer; 8 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/4/25 22:47 13 | */ 14 | public class ProjectPathAction extends NewUpdateThreadAction { 15 | private static final String text = MessagesBundle.getText("action.ftp.project.text"); 16 | private static final String desc = MessagesBundle.getText("action.ftp.project.description"); 17 | 18 | public LocalFileTableContainer container; 19 | 20 | public ProjectPathAction(LocalFileTableContainer container) { 21 | super(text, desc, AllIcons.Actions.ProjectDirectory); 22 | this.container = container; 23 | } 24 | 25 | @Override 26 | public void actionPerformed(@NotNull AnActionEvent e) { 27 | container.setPath(container.getProject().getBasePath()); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/RefreshFolderAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 8 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/4/4 17:13 13 | */ 14 | public class RefreshFolderAction extends NewUpdateThreadAction { 15 | private static final String text = MessagesBundle.getText("action.ftp.refresh.text"); 16 | private static final String desc = MessagesBundle.getText("action.ftp.refresh.description"); 17 | 18 | private final FileTableContainer container; 19 | 20 | public RefreshFolderAction(FileTableContainer container) { 21 | super(text, desc, AllIcons.Actions.Refresh); 22 | this.container = container; 23 | } 24 | 25 | @Override 26 | public void actionPerformed(@NotNull AnActionEvent e) { 27 | container.refreshFileList(); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/RowDoubleClickAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.ui.DoubleClickListener; 4 | import tech.lin2j.idea.plugin.enums.SFTPAction; 5 | import tech.lin2j.idea.plugin.enums.TransferEventType; 6 | import tech.lin2j.idea.plugin.event.ApplicationContext; 7 | import tech.lin2j.idea.plugin.file.TableFile; 8 | import tech.lin2j.idea.plugin.model.ConfigHelper; 9 | import tech.lin2j.idea.plugin.model.PluginSetting; 10 | import tech.lin2j.idea.plugin.model.event.FileTransferEvent; 11 | import tech.lin2j.idea.plugin.ui.dialog.FilePropertiesDialog; 12 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 13 | 14 | import java.awt.event.MouseEvent; 15 | 16 | /** 17 | * @author linjinjia 18 | * @date 2024/4/6 14:03 19 | */ 20 | public class RowDoubleClickAction extends DoubleClickListener { 21 | 22 | private final PluginSetting setting = ConfigHelper.pluginSetting(); 23 | 24 | private final FileTableContainer container; 25 | 26 | public RowDoubleClickAction(FileTableContainer container) { 27 | this.container = container; 28 | } 29 | 30 | @Override 31 | protected boolean onDoubleClick(MouseEvent e) { 32 | int selected = container.getTable().getSelectedRow(); 33 | if (selected == -1) { 34 | return false; 35 | } 36 | TableFile tf = container.getFileList().get(selected); 37 | if (!tf.isDirectory()) { 38 | SFTPAction action = setting.getDoubleClickAction(); 39 | if (action == SFTPAction.Properties) { 40 | new FilePropertiesDialog(tf).show(); 41 | } else if (action == SFTPAction.Transfer) { 42 | boolean isUpload = container.isLocal(); 43 | FileTransferEvent event = new FileTransferEvent(container, isUpload, TransferEventType.START); 44 | ApplicationContext.getApplicationContext().publishEvent(event); 45 | } 46 | return true; 47 | } 48 | 49 | container.setPath(tf.getFilePath()); 50 | return true; 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/ShowHiddenFileAndDirAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.openapi.actionSystem.ActionUpdateThread; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.ToggleAction; 6 | import icons.MyIcons; 7 | import org.jetbrains.annotations.NotNull; 8 | import tech.lin2j.idea.plugin.ui.ftp.container.FileTableContainer; 9 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/4 17:14 14 | */ 15 | public class ShowHiddenFileAndDirAction extends ToggleAction { 16 | private static final String text = MessagesBundle.getText("action.ftp.hidden.text"); 17 | private static final String desc = MessagesBundle.getText("action.ftp.hidden.description"); 18 | 19 | private final FileTableContainer container; 20 | 21 | public ShowHiddenFileAndDirAction(FileTableContainer container) { 22 | super(text, desc, MyIcons.Actions.showHidden); 23 | this.container = container; 24 | } 25 | 26 | @Override 27 | public boolean isSelected(@NotNull AnActionEvent e) { 28 | return !container.showHiddenFileAndDir(); 29 | } 30 | 31 | @Override 32 | public void setSelected(@NotNull AnActionEvent e, boolean state) { 33 | container.reversedHiddenFlag(); 34 | container.refreshFileList(); 35 | } 36 | 37 | @Override 38 | public void update(@NotNull AnActionEvent e) { 39 | super.update(e); 40 | } 41 | 42 | @Override 43 | public @NotNull ActionUpdateThread getActionUpdateThread() { 44 | return ActionUpdateThread.BGT; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/action/ftp/UploadFileAndDirAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.action.ftp; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.action.NewUpdateThreadAction; 7 | import tech.lin2j.idea.plugin.enums.TransferEventType; 8 | import tech.lin2j.idea.plugin.event.ApplicationContext; 9 | import tech.lin2j.idea.plugin.model.event.FileTransferEvent; 10 | import tech.lin2j.idea.plugin.ui.ftp.container.LocalFileTableContainer; 11 | import tech.lin2j.idea.plugin.uitl.MessagesBundle; 12 | 13 | /** 14 | * @author linjinjia 15 | * @date 2024/4/4 17:12 16 | */ 17 | public class UploadFileAndDirAction extends NewUpdateThreadAction { 18 | private static final String text = MessagesBundle.getText("action.ftp.upload.text"); 19 | private static final String desc = MessagesBundle.getText("action.ftp.upload.description"); 20 | 21 | private final LocalFileTableContainer localContainer; 22 | 23 | public UploadFileAndDirAction(LocalFileTableContainer localContainer) { 24 | super(text, desc, AllIcons.Actions.Upload); 25 | this.localContainer = localContainer; 26 | } 27 | 28 | public UploadFileAndDirAction(int count, LocalFileTableContainer localContainer) { 29 | this(localContainer); 30 | if (count > 1) { 31 | String text = "Upload (" + count + " Selected)"; 32 | getTemplatePresentation().setText(text); 33 | } 34 | } 35 | 36 | @Override 37 | public void actionPerformed(@NotNull AnActionEvent e) { 38 | FileTransferEvent event = new FileTransferEvent(localContainer, true, TransferEventType.START); 39 | ApplicationContext.getApplicationContext().publishEvent(event); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/AuthType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2022/12/3 13:23 6 | */ 7 | public enum AuthType { 8 | 9 | /** 10 | * Using a password for authentication 11 | */ 12 | PASSWORD(1, "password"), 13 | 14 | /** 15 | * Using a private key for authentication 16 | */ 17 | PEM_PRIVATE_KEY(2, "private key"); 18 | 19 | private final Integer code; 20 | private final String desc; 21 | 22 | AuthType(Integer code, String desc) { 23 | this.code = code; 24 | this.desc = desc; 25 | } 26 | 27 | public Integer getCode() { 28 | return code; 29 | } 30 | 31 | public String getDesc() { 32 | return desc; 33 | } 34 | 35 | /** 36 | * @param code code of authenticate type 37 | * @return true if the code represents 38 | * authenticate with password 39 | */ 40 | public static boolean needPassword(Integer code) { 41 | // the code parameter may be null 42 | // because server info stored in the 43 | // configuration has no authType value 44 | return code == null || PASSWORD.getCode().equals(code); 45 | } 46 | 47 | /** 48 | * @param code code of authenticate type 49 | * @return true if the code represents 50 | * authenticate with pem private key 51 | */ 52 | public static boolean needPemPrivateKey(Integer code) { 53 | return PEM_PRIVATE_KEY.getCode().equals(code); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return code.toString(); 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/Constant.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | import tech.lin2j.idea.plugin.model.UploadProfile; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2024/7/21 16:07 8 | */ 9 | public interface Constant { 10 | 11 | String EASY_DEPLOY = "EasyDeploy"; 12 | 13 | String UPDATE_CHECKER_PROPERTY = "easy-deploy.statistics.timestamp"; 14 | 15 | String STR_FALSE = "0"; 16 | 17 | String STR_TRUE = "1"; 18 | 19 | /** 20 | * default top inset of form item 21 | */ 22 | int DEFAULT_TOP_INSET = 20; 23 | 24 | /** 25 | * The prefix of run tab title 26 | */ 27 | String RUN_TAB_PREFIX = "ED@"; 28 | 29 | /** 30 | * Separator of multiple local file paths 31 | */ 32 | String LOCAL_FILE_SEPARATOR = "\n"; 33 | 34 | /** 35 | * Path and identifier separation in {@link UploadProfile} 36 | */ 37 | String LOCAL_FILE_INFO_SEPARATOR = "::"; 38 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/I18nType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2024/6/29 21:25 6 | */ 7 | public enum I18nType { 8 | 9 | English(0, "English"), 10 | Chinese(1, "简体中文"), 11 | ; 12 | 13 | private final Integer type; 14 | private final String text; 15 | 16 | I18nType(Integer type, String text) { 17 | this.type = type; 18 | this.text = text; 19 | } 20 | 21 | public static I18nType getByType(int type) { 22 | for (I18nType value : values()) { 23 | if (value.getType().equals(type)) { 24 | return value; 25 | } 26 | } 27 | return English; 28 | } 29 | 30 | public Integer getType() { 31 | return type; 32 | } 33 | 34 | public String getText() { 35 | return text; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return text; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/SFTPAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * @author linjinjia 8 | * @date 2024/5/25 10:12 9 | */ 10 | public enum SFTPAction { 11 | 12 | NONE, Transfer, Properties; 13 | 14 | public static List asList() { 15 | return Arrays.asList(SFTPAction.values()); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/TransferEventType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2024/4/13 16:25 6 | */ 7 | public enum TransferEventType { 8 | 9 | START, 10 | END 11 | 12 | ; 13 | 14 | public boolean isEnd() { 15 | return this == END; 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/TransferMode.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | public enum TransferMode { 4 | 5 | SFTP(0, "SFTP"), 6 | SCP(1, "SCP"), 7 | ; 8 | 9 | private final int type; 10 | private final String text; 11 | 12 | TransferMode(int type, String text) { 13 | this.type = type; 14 | this.text = text; 15 | } 16 | 17 | public static TransferMode getByType(int type) { 18 | for (TransferMode value : values()) { 19 | if (value.getType().equals(type)) { 20 | return value; 21 | } 22 | } 23 | return SFTP; 24 | } 25 | 26 | public Integer getType() { 27 | return type; 28 | } 29 | 30 | public String getText() { 31 | return text; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return text; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/enums/TransferState.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.enums; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2024/4/16 22:23 6 | */ 7 | public enum TransferState { 8 | 9 | UPLOADED("Uploaded", null), 10 | DOWNLOADED("Downloaded", null), 11 | UPLOADING("Uploading", UPLOADED), 12 | DOWNLOADING("Downloading", DOWNLOADED), 13 | 14 | FAILED("Failed", null), 15 | ; 16 | 17 | private final String desc; 18 | private final TransferState nextState; 19 | 20 | TransferState(String desc, TransferState nextState) { 21 | this.desc = desc; 22 | this.nextState = nextState; 23 | } 24 | 25 | public TransferState nextState() { 26 | if (nextState == null) { 27 | return this; 28 | } 29 | return nextState; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return desc; 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/event/ApplicationContext.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.event; 2 | 3 | import com.intellij.openapi.diagnostic.Logger; 4 | 5 | import java.util.Set; 6 | import java.util.concurrent.CopyOnWriteArraySet; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2022/4/27 10:30 11 | */ 12 | public class ApplicationContext implements ApplicationPublisher { 13 | 14 | private static final Logger log = Logger.getInstance(ApplicationContext.class); 15 | 16 | private static final ApplicationContext APPLICATION_CONTEXT = new ApplicationContext(); 17 | 18 | private final Set> listeners = new CopyOnWriteArraySet<>(); 19 | 20 | public void addApplicationListener(ApplicationListener listener) { 21 | listeners.add(listener); 22 | } 23 | 24 | public void removeApplicationListener(ApplicationListener listener) { 25 | listeners.remove(listener); 26 | } 27 | 28 | 29 | @SuppressWarnings({"rawtypes", "unchecked"}) 30 | @Override 31 | public void publishEvent(Object event) { 32 | ApplicationEvent applicationEvent; 33 | if (event instanceof ApplicationEvent) { 34 | applicationEvent = (ApplicationEvent) event; 35 | } else { 36 | if (log.isDebugEnabled()) { 37 | log.debug("event is not ApplicationEvent"); 38 | } 39 | return; 40 | } 41 | for (final ApplicationListener listener : listeners) { 42 | try { 43 | listener.onApplicationEvent(applicationEvent); 44 | } catch (ClassCastException e) { 45 | if (log.isDebugEnabled()) { 46 | log.debug("Non-matching event type for listener: " + listener, e); 47 | } 48 | } 49 | } 50 | } 51 | 52 | public static ApplicationContext getApplicationContext() { 53 | return APPLICATION_CONTEXT; 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/event/ApplicationEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.event; 2 | 3 | 4 | import java.util.EventObject; 5 | 6 | /** 7 | * @author linjinjia 8 | * @date 2022/4/27 10:21 9 | */ 10 | public class ApplicationEvent extends EventObject { 11 | 12 | public ApplicationEvent(Object source) { 13 | super(source); 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/event/ApplicationListener.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.event; 2 | 3 | import java.util.EventListener; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2022/4/27 10:22 8 | */ 9 | @FunctionalInterface 10 | public interface ApplicationListener extends EventListener { 11 | void onApplicationEvent(E event); 12 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/event/ApplicationPublisher.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.event; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2022/4/27 10:24 6 | */ 7 | @FunctionalInterface 8 | public interface ApplicationPublisher { 9 | 10 | default void publishEvent(ApplicationEvent event) { 11 | publishEvent((Object) event); 12 | } 13 | 14 | void publishEvent(Object event); 15 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/event/listener/UploadProfileSelectedListener.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.event.listener; 2 | 3 | import tech.lin2j.idea.plugin.event.ApplicationListener; 4 | import tech.lin2j.idea.plugin.model.ConfigHelper; 5 | import tech.lin2j.idea.plugin.model.UploadProfile; 6 | import tech.lin2j.idea.plugin.model.event.UploadProfileSelectedEvent; 7 | 8 | import java.util.Objects; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2022/5/24 17:54 13 | */ 14 | public class UploadProfileSelectedListener implements ApplicationListener { 15 | @Override 16 | public void onApplicationEvent(UploadProfileSelectedEvent event) { 17 | UploadProfile profile = (UploadProfile) event.getSource(); 18 | ConfigHelper.getUploadProfileBySshId(profile.getSshId()).forEach(s -> { 19 | if (!Objects.equals(profile, s)) { 20 | s.setSelected(false); 21 | } 22 | }); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/exception/IllegalFileTypeException.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.exception; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2024/11/16 23:01 6 | */ 7 | public class IllegalFileTypeException extends IllegalArgumentException { 8 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/factory/CustomTtyConnectorFactory.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.factory; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import tech.lin2j.idea.plugin.ssh.CustomTtyConnector; 6 | import tech.lin2j.idea.plugin.ssh.SshConnectionManager; 7 | import tech.lin2j.idea.plugin.ssh.SshServer; 8 | import tech.lin2j.idea.plugin.ssh.exception.RemoteSdkException; 9 | import tech.lin2j.idea.plugin.ssh.sshj.SshjConnection; 10 | import tech.lin2j.idea.plugin.ssh.sshj.SshjTtyConnector; 11 | 12 | import java.io.IOException; 13 | 14 | /** 15 | * @author linjinjia 16 | * @date 2022/6/25 11:29 17 | */ 18 | public class CustomTtyConnectorFactory { 19 | 20 | public static final Logger LOG = LoggerFactory.getLogger(CustomTtyConnectorFactory.class); 21 | 22 | /** 23 | * return a tty connector 24 | * @param type implementation of ssh2, {@link CustomTtyConnector} 25 | * @param server server information 26 | * @return tty connector 27 | */ 28 | public static CustomTtyConnector getCustomTtyConnector(String type, 29 | SshServer server, 30 | String workingDirectory) throws RemoteSdkException { 31 | if (CustomTtyConnector.SSHJ.equals(type)) { 32 | try { 33 | SshjConnection connection = SshConnectionManager.makeSshjConnection(server); 34 | return new SshjTtyConnector(connection, workingDirectory); 35 | } catch (IOException e) { 36 | LOG.error("Error connecting server: {}", e.getMessage()); 37 | throw new RemoteSdkException("Error connecting server: " + e.getMessage(), e); 38 | } 39 | } 40 | throw new IllegalArgumentException(type); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/factory/DeployConsoleToolWindowFactory.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.factory; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.wm.ToolWindow; 5 | import com.intellij.openapi.wm.ToolWindowFactory; 6 | import com.intellij.openapi.wm.ex.ToolWindowManagerListener; 7 | import com.intellij.ui.content.Content; 8 | import com.intellij.ui.content.ContentFactory; 9 | import org.jetbrains.annotations.NotNull; 10 | import tech.lin2j.idea.plugin.event.ApplicationContext; 11 | import tech.lin2j.idea.plugin.event.listener.UploadProfileSelectedListener; 12 | import tech.lin2j.idea.plugin.ui.module.ConsoleLogView; 13 | import tech.lin2j.idea.plugin.ui.module.DashboardView; 14 | 15 | /** 16 | * @author linjinjia 17 | * @date 2022/4/24 16:07 18 | */ 19 | public class DeployConsoleToolWindowFactory implements ToolWindowFactory { 20 | 21 | @Override 22 | public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { 23 | ContentFactory contentFactory = ContentFactory.getInstance(); 24 | // deploy tab 25 | DashboardView dashboardView = new DashboardView(project); 26 | Content deploy = contentFactory.createContent(dashboardView, "Dashboard", false); 27 | toolWindow.getContentManager().addContent(deploy); 28 | // messages tab 29 | ConsoleLogView commandExecuteView = new ConsoleLogView(project); 30 | commandExecuteView.attachProject(); 31 | Content messages = contentFactory.createContent(commandExecuteView, "Console", false); 32 | toolWindow.getContentManager().addContent(messages); 33 | 34 | // make sure every time you click on the tool window is the console 35 | project.getMessageBus().connect().subscribe(ToolWindowManagerListener.TOPIC, new ToolWindowManagerListener() { 36 | @Override 37 | public void stateChanged() { 38 | boolean messagesSelected = toolWindow.getContentManager().isSelected(messages); 39 | if (!toolWindow.isVisible() && messagesSelected) { 40 | toolWindow.getContentManager().setSelectedContent(deploy); 41 | } 42 | } 43 | }); 44 | 45 | ApplicationContext.getApplicationContext().addApplicationListener(dashboardView.getConsoleUi()); 46 | ApplicationContext.getApplicationContext().addApplicationListener(new UploadProfileSelectedListener()); 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/ConsoleTransferListener.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file; 2 | 3 | import com.intellij.openapi.util.text.StringUtil; 4 | import net.schmizz.sshj.common.StreamCopier; 5 | import net.schmizz.sshj.xfer.TransferListener; 6 | import tech.lin2j.idea.plugin.ssh.CommandLog; 7 | import tech.lin2j.idea.plugin.uitl.FileTransferSpeed; 8 | 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/13 16:09 14 | */ 15 | public class ConsoleTransferListener implements TransferListener { 16 | private final String relPath; 17 | private final CommandLog console; 18 | private final FileTransferSpeed fileTransferSpeed = new FileTransferSpeed(); 19 | 20 | public ConsoleTransferListener(String relPath, CommandLog console) { 21 | if (!relPath.endsWith("/")) { 22 | relPath += "/"; 23 | } 24 | this.relPath = relPath; 25 | this.console = console; 26 | } 27 | 28 | @Override 29 | public TransferListener directory(String name) { 30 | return new ConsoleTransferListener(relPath + name + "/", console); 31 | } 32 | 33 | @Override 34 | public StreamCopier.Listener file(final String name, final long size) { 35 | String path = relPath + name; 36 | console.info("Transfer file: " + path + ", Size: " + StringUtil.formatFileSize(size) + "\n"); 37 | return transferred -> { 38 | String speed = fileTransferSpeed.accept(transferred); 39 | 40 | double fileProgress = 0; 41 | if (size > 0) { 42 | fileProgress = transferred / (double) size; 43 | } 44 | boolean fileCompleted = Math.abs(1 - fileProgress) < 1e-6; 45 | printProgress((int) (fileProgress * 100), fileCompleted, speed); 46 | 47 | }; 48 | } 49 | 50 | private void printProgress(int complete, boolean completed, String speed) { 51 | StringBuilder sb = new StringBuilder("["); 52 | Stream.generate(() -> '#').limit(complete).forEach(sb::append); 53 | Stream.generate(() -> '_').limit(100 - complete).forEach(sb::append); 54 | sb.append("] "); 55 | if (completed) { 56 | sb.append("complete, speed: ").append(speed).append("\n"); 57 | } else { 58 | sb.append(complete).append("% , speed: ").append(speed); 59 | } 60 | console.print("\r"); 61 | console.print(sb.toString()); 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/DirectoryInfo.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2024/4/18 06:37 6 | */ 7 | public class DirectoryInfo { 8 | 9 | private long size; 10 | private int files; 11 | private boolean isDirectory; 12 | 13 | public long getSize() { 14 | return size; 15 | } 16 | 17 | public void setSize(long size) { 18 | this.size = size; 19 | } 20 | 21 | public int getFiles() { 22 | return files; 23 | } 24 | 25 | public void setFiles(int files) { 26 | this.files = files; 27 | } 28 | 29 | public boolean isDirectory() { 30 | return isDirectory; 31 | } 32 | 33 | public void setDirectory(boolean directory) { 34 | isDirectory = directory; 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/TableFile.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import javax.swing.Icon; 6 | 7 | /** 8 | * @author linjinjia 9 | * @date 2024/4/6 10:08 10 | */ 11 | public interface TableFile extends Comparable { 12 | 13 | Icon getIcon(); 14 | 15 | String getName(); 16 | 17 | String getSize(); 18 | 19 | String getType(); 20 | 21 | String getCreated(); 22 | 23 | boolean readOnly(); 24 | 25 | String getModified(); 26 | 27 | boolean isDirectory(); 28 | 29 | default boolean isHidden() { 30 | return getName().startsWith(".") || getName().startsWith("$"); 31 | } 32 | 33 | String getParent(); 34 | 35 | String getFilePath(); 36 | 37 | @Override 38 | default int compareTo(@NotNull TableFile f2) { 39 | if (this.isDirectory() && !f2.isDirectory()) { 40 | return -1; 41 | } 42 | if (!this.isDirectory() && f2.isDirectory()) { 43 | return 1; 44 | } 45 | return this.getName().compareTo(f2.getName()); 46 | } 47 | 48 | default String getAccess() { 49 | return ""; 50 | } 51 | 52 | default String getOwner() { 53 | return ""; 54 | } 55 | 56 | default String getGroup() { 57 | return ""; 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/ConfigFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.fileTypes.FileType; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 15:19 14 | */ 15 | public class ConfigFileType implements FileType { 16 | 17 | public static final ConfigFileType INSTANCE = new ConfigFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "Config"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "Config"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "cfg"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return AllIcons.FileTypes.Config; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/DmgFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 13:23 14 | */ 15 | public class DmgFileType implements FileType { 16 | 17 | public static final DmgFileType INSTANCE = new DmgFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "Disk Image"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "Disk Image"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "dmg"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return MyIcons.FileType.Dmg; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/EbookFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import icons.MyIcons; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.Icon; 11 | 12 | /** 13 | * @author linjinjia 14 | * @date 2024/4/21 15:19 15 | */ 16 | public class EbookFileType implements FileType { 17 | private final String ext; 18 | 19 | public EbookFileType(String ext) { 20 | this.ext = StringUtil.toUpperCase(ext); 21 | } 22 | 23 | @NotNull 24 | @Override 25 | public String getName() { 26 | return ext; 27 | } 28 | 29 | @NotNull 30 | @Override 31 | public String getDescription() { 32 | return ext; 33 | } 34 | 35 | @NotNull 36 | @Override 37 | public String getDefaultExtension() { 38 | return "epub"; 39 | } 40 | 41 | @Nullable 42 | @Override 43 | public Icon getIcon() { 44 | return MyIcons.FileType.EBook; 45 | } 46 | 47 | @Override 48 | public boolean isBinary() { 49 | return false; 50 | } 51 | 52 | @Override 53 | public boolean isReadOnly() { 54 | return false; 55 | } 56 | 57 | @Nullable 58 | @Override 59 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 60 | return null; 61 | } 62 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/ExcelFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 15:19 14 | */ 15 | public class ExcelFileType implements FileType { 16 | 17 | public static final ExcelFileType INSTANCE = new ExcelFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "Excel"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "Excel"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "xlsx"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return MyIcons.FileType.Excel; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/LogFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 15:19 14 | */ 15 | public class LogFileType implements FileType { 16 | 17 | public static final LogFileType INSTANCE = new LogFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "Log"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "Log"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "log"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return MyIcons.FileType.Log; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/PdfFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 15:19 14 | */ 15 | public class PdfFileType implements FileType { 16 | 17 | public static final PdfFileType INSTANCE = new PdfFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "PDF"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "PDF"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "pdf"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return MyIcons.FileType.PDF; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/PptFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 15:19 14 | */ 15 | public class PptFileType implements FileType { 16 | 17 | public static final PptFileType INSTANCE = new PptFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "PPT"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "PPT"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "ppt"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return MyIcons.FileType.PPT; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/SFTPFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NonNls; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.Icon; 11 | 12 | /** 13 | * @author linjinjia 14 | * @date 2024/3/31 02:24 15 | */ 16 | public class SFTPFileType implements FileType { 17 | @Override 18 | public @NonNls @NotNull String getName() { 19 | return "FTP Console"; 20 | } 21 | 22 | @Override 23 | public @NotNull String getDescription() { 24 | return "A-FTP console"; 25 | } 26 | 27 | @Override 28 | public @NotNull String getDefaultExtension() { 29 | return ""; 30 | } 31 | 32 | @Override 33 | public @Nullable Icon getIcon() { 34 | return MyIcons.SFTP; 35 | } 36 | 37 | @Override 38 | public boolean isBinary() { 39 | return false; 40 | } 41 | 42 | @Override 43 | public boolean isReadOnly() { 44 | return true; 45 | } 46 | 47 | @Override 48 | public @NonNls @Nullable String getCharset(@NotNull VirtualFile file, byte @NotNull [] content) { 49 | return null; 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/SpecifiedArchiveFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 11:45 14 | */ 15 | public class SpecifiedArchiveFileType implements FileType { 16 | 17 | private final FileType origin; 18 | private final String ext; 19 | 20 | public SpecifiedArchiveFileType(FileType origin, String ext) { 21 | this.origin = origin; 22 | this.ext = StringUtil.toUpperCase(ext); 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getName() { 28 | return ext + " " + origin.getName(); 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDescription() { 34 | return getName(); 35 | } 36 | 37 | @NotNull 38 | @Override 39 | public String getDefaultExtension() { 40 | return ext; 41 | } 42 | 43 | @Nullable 44 | @Override 45 | public Icon getIcon() { 46 | return origin.getIcon(); 47 | } 48 | 49 | @Override 50 | public boolean isBinary() { 51 | return origin.isBinary(); 52 | } 53 | 54 | @Override 55 | public boolean isReadOnly() { 56 | return origin.isReadOnly(); 57 | } 58 | 59 | @Nullable 60 | @Override 61 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 62 | return null; 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/VideoFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import icons.MyIcons; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.Icon; 11 | 12 | /** 13 | * @author linjinjia 14 | * @date 2024/4/21 13:31 15 | */ 16 | public class VideoFileType implements FileType { 17 | 18 | private final String ext; 19 | 20 | public VideoFileType(String ext) { 21 | this.ext = StringUtil.toUpperCase(ext); 22 | } 23 | 24 | @NotNull 25 | @Override 26 | public String getName() { 27 | return ext; 28 | } 29 | 30 | @NotNull 31 | @Override 32 | public String getDescription() { 33 | return ext + " Video"; 34 | } 35 | 36 | @NotNull 37 | @Override 38 | public String getDefaultExtension() { 39 | return ext; 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public Icon getIcon() { 45 | return MyIcons.FileType.Video; 46 | } 47 | 48 | @Override 49 | public boolean isBinary() { 50 | return false; 51 | } 52 | 53 | @Override 54 | public boolean isReadOnly() { 55 | return false; 56 | } 57 | 58 | @Nullable 59 | @Override 60 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 61 | return null; 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/fileTypes/WordFileType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileType; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import icons.MyIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/21 15:19 14 | */ 15 | public class WordFileType implements FileType { 16 | 17 | public static final WordFileType INSTANCE = new WordFileType(); 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "Word"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "Word"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "docx"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return MyIcons.FileType.Word; 41 | } 42 | 43 | @Override 44 | public boolean isBinary() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isReadOnly() { 50 | return false; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) { 56 | return null; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/filter/ConsoleFileFilter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.filter; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import tech.lin2j.idea.plugin.ssh.CommandLog; 5 | 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | /** 10 | * 11 | * @author linjinjia 12 | * @date 2024/11/27 22:23 13 | */ 14 | public class ConsoleFileFilter implements ListableFileFilter { 15 | private final CommandLog commandLog; 16 | private final LinkedList filters = new LinkedList<>(); 17 | 18 | public ConsoleFileFilter(CommandLog commandLog) { 19 | this.commandLog = commandLog; 20 | } 21 | 22 | public ConsoleFileFilter(@NotNull FileFilter fileFilter, @NotNull CommandLog commandLog) { 23 | this.commandLog = commandLog; 24 | filters.add(fileFilter); 25 | } 26 | 27 | @Override 28 | public boolean accept(String filename) { 29 | for (FileFilter filter : filters) { 30 | if (!filter.accept(filename)) { 31 | return false; 32 | } 33 | } 34 | return true; 35 | } 36 | 37 | @Override 38 | public void accept(String filename, FileAction action) throws Exception { 39 | boolean accept = accept(filename); 40 | action.execute(accept); 41 | } 42 | 43 | @Override 44 | public void addFilter(FileFilter filter) { 45 | filters.add(filter); 46 | } 47 | 48 | @Override 49 | public void removeLast() { 50 | filters.removeLast(); 51 | } 52 | 53 | @Override 54 | public void remove(FileFilter filter) { 55 | filters.remove(filter); 56 | } 57 | 58 | @Override 59 | public List getFilters() { 60 | return filters; 61 | } 62 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/filter/ExtExcludeFilter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.filter; 2 | 3 | import com.intellij.openapi.util.text.StringUtil; 4 | import tech.lin2j.idea.plugin.ssh.CommandLog; 5 | 6 | import java.util.Arrays; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2022/12/9 23:54 14 | */ 15 | public class ExtExcludeFilter implements FileFilter { 16 | private final String extensions; 17 | private final Set extensionSet; 18 | private final CommandLog commandLog;; 19 | 20 | public ExtExcludeFilter(String extensions, CommandLog commandLog) { 21 | this.commandLog = commandLog; 22 | if (StringUtil.isEmpty(extensions)) { 23 | this.extensions = ""; 24 | this.extensionSet = new HashSet<>(); 25 | return; 26 | } 27 | this.extensions = extensions; 28 | extensionSet = Arrays.stream(extensions.split(";")) 29 | .map(s -> s.replaceAll("\\*?\\.?", "")) 30 | .collect(Collectors.toSet()); 31 | } 32 | 33 | @Override 34 | public boolean accept(String f) { 35 | if (StringUtil.isEmpty(extensions)) { 36 | return true; 37 | } 38 | 39 | int dot = f.lastIndexOf('.'); 40 | if (dot == -1) { 41 | return true; 42 | } 43 | String suffix = f.substring(dot + 1); 44 | boolean contains = extensionSet.contains(suffix); 45 | if (contains) { 46 | commandLog.info("[" + f + "] excluded by '" + extensions + "'"); 47 | } 48 | return !contains; 49 | } 50 | 51 | public String getExtensions() { 52 | return extensions; 53 | } 54 | 55 | public Set getExtensionSet() { 56 | return extensionSet; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/filter/FileAction.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.filter; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2022/12/11 20:47 8 | */ 9 | @FunctionalInterface 10 | public interface FileAction { 11 | 12 | /** 13 | * Performs this operation on the given argument. 14 | * 15 | * @param t the input argument 16 | * @throws IOException IOException 17 | */ 18 | void execute(T t) throws Exception; 19 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/filter/FileFilter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.filter; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * FileFilter is an interface used by scp for filtering 7 | * the set of files uploaded to ssh server 8 | * 9 | * @author linjinjia 10 | * @date 2022/12/9 22:54 11 | */ 12 | public interface FileFilter { 13 | 14 | /** 15 | * Whether the given file is accepted by this filter. 16 | * 17 | * @param filename the name of a file to test 18 | * @return true if the file is to be accepted 19 | */ 20 | boolean accept(String filename); 21 | 22 | /** 23 | * Test whether the file needs to be filtered, 24 | * and then perform a file operation 25 | * 26 | * @param filename the name of a file to test 27 | * @param action execute a {@link FileAction} 28 | * @throws IOException IOException 29 | */ 30 | default void accept(String filename, FileAction action) throws Exception { 31 | boolean result = accept(filename); 32 | action.execute(result); 33 | } 34 | 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/filter/ListableFileFilter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.filter; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2024/11/30 13:40 8 | */ 9 | public interface ListableFileFilter extends FileFilter { 10 | 11 | void addFilter(FileFilter filter); 12 | 13 | void removeLast(); 14 | 15 | void remove(FileFilter filter); 16 | 17 | List getFilters(); 18 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/file/filter/RegexFileFilter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file.filter; 2 | 3 | import com.intellij.util.PathUtil; 4 | import tech.lin2j.idea.plugin.ssh.CommandLog; 5 | 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2024/11/30 13:21 11 | */ 12 | public class RegexFileFilter implements FileFilter { 13 | private final Pattern pattern; 14 | private final String regex; 15 | private final CommandLog commandLog; 16 | 17 | public RegexFileFilter(String regex, CommandLog commandLog) { 18 | this.regex = regex; 19 | this.pattern = Pattern.compile(regex); 20 | this.commandLog = commandLog; 21 | } 22 | 23 | @Override 24 | public boolean accept(String filename) { 25 | String name = PathUtil.getFileName(filename); 26 | boolean matches = pattern.matcher(name).matches(); 27 | if (matches) { 28 | commandLog.info("[" + filename + "] matches pattern '" + regex + "'"); 29 | } 30 | return matches; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/ConfigImportExport.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | import tech.lin2j.idea.plugin.ssh.SshServer; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author linjinjia 9 | * @date 2024/7/17 20:52 10 | */ 11 | public class ConfigImportExport { 12 | 13 | private ExportOptions options; 14 | 15 | private String version; 16 | 17 | private List serverTags; 18 | 19 | private List hostInfos; 20 | 21 | public ExportOptions getOptions() { 22 | return options; 23 | } 24 | 25 | public void setOptions(ExportOptions options) { 26 | this.options = options; 27 | } 28 | 29 | public String getVersion() { 30 | return version; 31 | } 32 | 33 | public void setVersion(String version) { 34 | this.version = version; 35 | } 36 | 37 | public List getServerTags() { 38 | return serverTags; 39 | } 40 | 41 | public void setServerTags(List serverTags) { 42 | this.serverTags = serverTags; 43 | } 44 | 45 | public List getHostInfos() { 46 | return hostInfos; 47 | } 48 | 49 | public void setHostInfos(List hostInfos) { 50 | this.hostInfos = hostInfos; 51 | } 52 | 53 | public static class HostInfo { 54 | private SshServer server; 55 | private List commands; 56 | private List uploadProfiles; 57 | 58 | public SshServer getServer() { 59 | return server; 60 | } 61 | 62 | public void setServer(SshServer server) { 63 | this.server = server; 64 | } 65 | 66 | public List getCommands() { 67 | return commands; 68 | } 69 | 70 | public void setCommands(List commands) { 71 | this.commands = commands; 72 | } 73 | 74 | public List getUploadProfiles() { 75 | return uploadProfiles; 76 | } 77 | 78 | public void setUploadProfiles(List uploadProfiles) { 79 | this.uploadProfiles = uploadProfiles; 80 | } 81 | 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/EDPluginUpdateChecker.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | import com.intellij.ide.plugins.StandalonePluginUpdateChecker; 4 | import com.intellij.notification.NotificationGroup; 5 | import com.intellij.openapi.components.Service; 6 | import icons.MyIcons; 7 | import tech.lin2j.idea.plugin.enums.Constant; 8 | import tech.lin2j.idea.plugin.uitl.EasyDeployPluginUtil; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/12/1 11:17 13 | */ 14 | @Service(Service.Level.APP) 15 | public final class EDPluginUpdateChecker extends StandalonePluginUpdateChecker { 16 | 17 | public EDPluginUpdateChecker() { 18 | super(EasyDeployPluginUtil.PLUGIN_ID, 19 | Constant.UPDATE_CHECKER_PROPERTY, 20 | NotificationGroup.findRegisteredGroup(Constant.EASY_DEPLOY), 21 | MyIcons.EasyDeploy); 22 | } 23 | 24 | @Override 25 | public boolean skipUpdateCheck() { 26 | return !EasyDeployPluginUtil.isEnabled(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/ExportOptions.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2024/7/17 20:57 8 | */ 9 | public class ExportOptions implements Cloneable { 10 | 11 | private boolean command; 12 | 13 | private boolean uploadProfile; 14 | 15 | private boolean serverTags; 16 | 17 | /** 18 | * always export server info 19 | */ 20 | public boolean isServer() { 21 | return true; 22 | } 23 | 24 | public boolean isCommand() { 25 | return command; 26 | } 27 | 28 | public void setCommand(boolean command) { 29 | this.command = command; 30 | } 31 | 32 | public boolean isUploadProfile() { 33 | return uploadProfile; 34 | } 35 | 36 | public void setUploadProfile(boolean uploadProfile) { 37 | this.uploadProfile = uploadProfile; 38 | } 39 | 40 | public boolean isServerTags() { 41 | return serverTags; 42 | } 43 | 44 | public void setServerTags(boolean serverTags) { 45 | this.serverTags = serverTags; 46 | } 47 | 48 | @Override 49 | public ExportOptions clone() { 50 | try { 51 | return (ExportOptions) super.clone(); 52 | } catch (CloneNotSupportedException e) { 53 | ExportOptions newOne = new ExportOptions(); 54 | newOne.setServerTags(serverTags); 55 | newOne.setCommand(command); 56 | newOne.setUploadProfile(uploadProfile); 57 | return newOne; 58 | } 59 | } 60 | 61 | @Override 62 | public boolean equals(Object o) { 63 | if (this == o) return true; 64 | if (o == null || getClass() != o.getClass()) return false; 65 | ExportOptions options = (ExportOptions) o; 66 | return command == options.command 67 | && uploadProfile == options.uploadProfile 68 | && serverTags == options.serverTags; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return Objects.hash(command, uploadProfile, serverTags); 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/HotReloadPersistence.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent; 4 | import com.intellij.openapi.components.Service; 5 | import com.intellij.openapi.components.State; 6 | import com.intellij.openapi.components.Storage; 7 | import com.intellij.util.xmlb.XmlSerializerUtil; 8 | import org.apache.commons.lang3.RandomUtils; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.Random; 13 | 14 | /** 15 | * @author linjinjia 16 | * @date 2024/11/7 22:28 17 | */ 18 | @State( 19 | name = "EasyDeployHotReload", 20 | storages = {@Storage("workspace.xml")} 21 | ) 22 | @Service(Service.Level.PROJECT) 23 | public final class HotReloadPersistence implements PersistentStateComponent { 24 | 25 | private Integer sshId; 26 | 27 | private Integer pid; 28 | 29 | private Integer httpPort; 30 | 31 | public Integer getSshId() { 32 | return sshId; 33 | } 34 | 35 | public void setSshId(Integer sshId) { 36 | this.sshId = sshId; 37 | } 38 | 39 | public Integer getPid() { 40 | return pid; 41 | } 42 | 43 | public void setPid(Integer pid) { 44 | this.pid = pid; 45 | } 46 | 47 | public Integer getHttpPort() { 48 | return httpPort; 49 | } 50 | 51 | public void setHttpPort(Integer httpPort) { 52 | this.httpPort = httpPort; 53 | } 54 | 55 | @Override 56 | public @Nullable HotReloadPersistence getState() { 57 | return this; 58 | } 59 | 60 | @Override 61 | public void loadState(@NotNull HotReloadPersistence hotReloadPersistence) { 62 | XmlSerializerUtil.copyBean(hotReloadPersistence, this); 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/NoneCommand.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2022/5/7 09:19 6 | */ 7 | public class NoneCommand extends Command { 8 | 9 | public static final NoneCommand INSTANCE = new NoneCommand(); 10 | 11 | public NoneCommand() { 12 | setTitle("None"); 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "None"; 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/PluginConfigInitializer.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | import com.intellij.ide.AppLifecycleListener; 4 | import com.intellij.openapi.diagnostic.Logger; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 11 | * @author linjinjia 12 | * @date 2024/8/9 21:40 13 | */ 14 | public class PluginConfigInitializer implements AppLifecycleListener { 15 | private static final Logger log = Logger.getInstance(PluginConfigInitializer.class); 16 | 17 | @Override 18 | public void appFrameCreated(@NotNull List commandLineArgs) { 19 | try { 20 | ConfigHelper.ensureConfigLoadInMemory(); 21 | } catch (Exception e) { 22 | log.error("Easy-Deploy plugin load configuration failed: " + e.getMessage(), e); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/SeparatorCommand.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2022/5/7 09:19 6 | */ 7 | public class SeparatorCommand extends Command { 8 | 9 | public static final SeparatorCommand INSTANCE = new SeparatorCommand(); 10 | 11 | public SeparatorCommand() { 12 | setTitle("---------------- Sharable ----------------"); 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "Sharable Separator"; 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/UniqueModel.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model; 2 | /** 3 | * 4 | * @author linjinjia 5 | * @date 2024/8/11 22:18 6 | */ 7 | public interface UniqueModel { 8 | 9 | String getUid(); 10 | 11 | void setUid(String uid); 12 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/event/CommandAddEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model.event; 2 | 3 | import tech.lin2j.idea.plugin.event.ApplicationEvent; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2022/4/29 10:06 8 | */ 9 | public class CommandAddEvent extends ApplicationEvent { 10 | public CommandAddEvent(Object source) { 11 | super(source); 12 | } 13 | 14 | public CommandAddEvent() { 15 | super(new Object()); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/event/FileTransferEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model.event; 2 | 3 | import tech.lin2j.idea.plugin.enums.TransferEventType; 4 | import tech.lin2j.idea.plugin.event.ApplicationEvent; 5 | 6 | /** 7 | * @author linjinjia 8 | * @date 2024/4/4 12:23 9 | */ 10 | public class FileTransferEvent extends ApplicationEvent { 11 | 12 | private final TransferEventType state; 13 | 14 | private final boolean isUpload; 15 | 16 | public FileTransferEvent(Object source, boolean isUpload, TransferEventType state) { 17 | super(source); 18 | this.isUpload = isUpload; 19 | this.state = state; 20 | } 21 | 22 | public FileTransferEvent(boolean isUpload, TransferEventType state) { 23 | super(new Object()); 24 | this.isUpload = isUpload; 25 | this.state = state; 26 | } 27 | 28 | public TransferEventType getState() { 29 | return state; 30 | } 31 | 32 | public boolean isUpload() { 33 | return isUpload; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/event/TableRefreshEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model.event; 2 | 3 | import tech.lin2j.idea.plugin.event.ApplicationEvent; 4 | import tech.lin2j.idea.plugin.ssh.SshServer; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2022/4/27 10:28 11 | */ 12 | public class TableRefreshEvent extends ApplicationEvent { 13 | 14 | private boolean tagRefresh; 15 | 16 | List sshServers; 17 | 18 | public TableRefreshEvent(List sshServers) { 19 | super(new Object()); 20 | this.sshServers = sshServers; 21 | } 22 | 23 | public TableRefreshEvent() { 24 | super(new Object()); 25 | } 26 | 27 | public TableRefreshEvent(boolean tagRefresh) { 28 | super(new Object()); 29 | this.tagRefresh = tagRefresh; 30 | } 31 | 32 | public List getSshServers() { 33 | return sshServers; 34 | } 35 | 36 | public boolean isTagRefresh() { 37 | return tagRefresh; 38 | } 39 | 40 | public void setTagRefresh(boolean tagRefresh) { 41 | this.tagRefresh = tagRefresh; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/event/UploadProfileAddEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model.event; 2 | 3 | import tech.lin2j.idea.plugin.event.ApplicationEvent; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2022/4/29 10:06 8 | */ 9 | public class UploadProfileAddEvent extends ApplicationEvent { 10 | public UploadProfileAddEvent(Object source) { 11 | super(source); 12 | } 13 | 14 | public UploadProfileAddEvent() { 15 | super(new Object()); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/event/UploadProfileExecuteEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model.event; 2 | 3 | import tech.lin2j.idea.plugin.event.ApplicationEvent; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2022/7/25 17:15 8 | */ 9 | public class UploadProfileExecuteEvent extends ApplicationEvent { 10 | 11 | private Boolean success; 12 | 13 | private String uploadResult; 14 | 15 | private Boolean needExecCommand; 16 | 17 | public UploadProfileExecuteEvent() { 18 | super(new Object()); 19 | } 20 | 21 | public String getUploadResult() { 22 | return uploadResult; 23 | } 24 | 25 | public void setUploadResult(String uploadResult) { 26 | this.uploadResult = uploadResult; 27 | } 28 | 29 | public Boolean isSuccess() { 30 | return success; 31 | } 32 | 33 | public void setSuccess(Boolean success) { 34 | this.success = success; 35 | } 36 | 37 | public Boolean getNeedExecCommand() { 38 | return needExecCommand; 39 | } 40 | 41 | public void setNeedExecCommand(Boolean needExecCommand) { 42 | this.needExecCommand = needExecCommand; 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/model/event/UploadProfileSelectedEvent.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.model.event; 2 | 3 | import tech.lin2j.idea.plugin.event.ApplicationEvent; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2022/4/29 10:06 8 | */ 9 | public class UploadProfileSelectedEvent extends ApplicationEvent { 10 | public UploadProfileSelectedEvent(Object source) { 11 | super(source); 12 | } 13 | 14 | public UploadProfileSelectedEvent() { 15 | super(new Object()); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/runner/ContentManagerAdapter.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.runner; 2 | 3 | import com.intellij.ui.content.ContentManagerEvent; 4 | import com.intellij.ui.content.ContentManagerListener; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * @author linjinjia 9 | * @date 2024/7/28 21:48 10 | */ 11 | public class ContentManagerAdapter implements ContentManagerListener { 12 | @Override 13 | public void contentAdded(@NotNull ContentManagerEvent contentManagerEvent) { 14 | 15 | } 16 | 17 | @Override 18 | public void contentRemoved(@NotNull ContentManagerEvent contentManagerEvent) { 19 | 20 | } 21 | 22 | @Override 23 | public void contentRemoveQuery(@NotNull ContentManagerEvent contentManagerEvent) { 24 | 25 | } 26 | 27 | @Override 28 | public void selectionChanged(@NotNull ContentManagerEvent contentManagerEvent) { 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/runner/DeployConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.runner; 2 | 3 | import com.intellij.execution.configurations.ConfigurationFactory; 4 | import com.intellij.execution.configurations.ConfigurationType; 5 | import com.intellij.execution.configurations.RunConfiguration; 6 | import com.intellij.openapi.components.BaseState; 7 | import com.intellij.openapi.project.Project; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/24 21:57 14 | */ 15 | public class DeployConfigurationFactory extends ConfigurationFactory { 16 | 17 | protected DeployConfigurationFactory(ConfigurationType type) { 18 | super(type); 19 | } 20 | 21 | @Override 22 | public @NotNull String getId() { 23 | return DeployRunConfigurationType.ID; 24 | } 25 | 26 | @NotNull 27 | @Override 28 | public RunConfiguration createTemplateConfiguration( 29 | @NotNull Project project) { 30 | return new DeployRunConfiguration(project, this, "Easy Deploy"); 31 | } 32 | 33 | @Nullable 34 | @Override 35 | public Class getOptionsClass() { 36 | return DeployRunConfigurationOptions.class; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/runner/DeployRunConfigurationOptions.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.runner; 2 | 3 | import com.intellij.execution.configurations.RunConfigurationOptions; 4 | import com.intellij.openapi.components.StoredProperty; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2024/4/24 21:57 11 | */ 12 | public class DeployRunConfigurationOptions extends RunConfigurationOptions { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/runner/DeployRunConfigurationType.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.runner; 2 | 3 | import com.intellij.execution.configurations.ConfigurationTypeBase; 4 | import com.intellij.openapi.util.NotNullLazyValue; 5 | import icons.MyIcons; 6 | 7 | /** 8 | * @author linjinjia 9 | * @date 2024/4/24 21:57 10 | */ 11 | public class DeployRunConfigurationType extends ConfigurationTypeBase { 12 | static final String ID = "EasyDeployRunConfiguration"; 13 | 14 | DeployRunConfigurationType() { 15 | super(ID, "Easy Deploy", "Deploy service to remote server", 16 | NotNullLazyValue.createValue(() -> MyIcons.EasyDeploy)); 17 | addFactory(new DeployConfigurationFactory(this)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/runner/process/UploadProcessHandler.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.runner.process; 2 | 3 | import com.intellij.execution.ExecutionResult; 4 | import com.intellij.execution.process.ProcessHandler; 5 | import com.intellij.execution.ui.ConsoleView; 6 | import org.jetbrains.annotations.Nullable; 7 | import tech.lin2j.idea.plugin.enums.Constant; 8 | 9 | import java.io.OutputStream; 10 | 11 | /** 12 | * 13 | * @see com.intellij.execution.process.NopProcessHandler 14 | * @author linjinjia 15 | * @date 2024/7/28 20:42 16 | */ 17 | public class UploadProcessHandler extends ProcessHandler { 18 | 19 | private String name; 20 | private ConsoleView console; 21 | private ExecutionResult executionResult; 22 | 23 | public UploadProcessHandler() { 24 | super(); 25 | } 26 | 27 | @Override 28 | protected void destroyProcessImpl() { 29 | notifyProcessTerminated(0); 30 | } 31 | 32 | @Override 33 | protected void detachProcessImpl() { 34 | notifyProcessDetached(); 35 | } 36 | 37 | @Override 38 | public boolean detachIsDefault() { 39 | return false; 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public OutputStream getProcessInput() { 45 | return null; 46 | } 47 | 48 | @Override 49 | public void notifyProcessTerminated(int exitCode) { 50 | super.notifyProcessTerminated(exitCode); 51 | } 52 | 53 | @Override 54 | protected void notifyProcessDetached() { 55 | super.notifyProcessDetached(); 56 | } 57 | 58 | public ConsoleView getConsole() { 59 | return console; 60 | } 61 | 62 | public void setConsole(ConsoleView console) { 63 | this.console = console; 64 | } 65 | 66 | public ExecutionResult getExecutionResult() { 67 | return executionResult; 68 | } 69 | 70 | public void setExecutionResult(ExecutionResult executionResult) { 71 | this.executionResult = executionResult; 72 | } 73 | 74 | public String getName() { 75 | return name; 76 | } 77 | 78 | public void setName(String name) { 79 | this.name = Constant.RUN_TAB_PREFIX + name; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/service/ISshService.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.service; 2 | 3 | import net.schmizz.sshj.xfer.TransferListener; 4 | import tech.lin2j.idea.plugin.file.filter.FileFilter; 5 | import tech.lin2j.idea.plugin.ssh.CommandLog; 6 | import tech.lin2j.idea.plugin.ssh.SshServer; 7 | import tech.lin2j.idea.plugin.ssh.SshStatus; 8 | import tech.lin2j.idea.plugin.ssh.sshj.SshjConnection; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2023/12/21 22:20 13 | */ 14 | public interface ISshService { 15 | 16 | /** 17 | * test whether the server information is available 18 | * 19 | * @param sshServer server information 20 | * @return execution result 21 | */ 22 | SshStatus isValid(SshServer sshServer); 23 | 24 | /** 25 | * block if the command is not finished, 26 | * so do not execute command like "tail -f" 27 | * because it will block the thread 28 | * 29 | * @param sshServer server information 30 | * @param command command 31 | * @return execution result 32 | */ 33 | SshStatus execute(SshServer sshServer, String command); 34 | 35 | void executeAsync(CommandLog commandLog, SshServer sshServer, String command); 36 | 37 | void executeAsync(CommandLog commandLog, SshjConnection connection, String command); 38 | 39 | SshStatus upload(FileFilter filter, SshServer server, String localFile, 40 | String remoteDir, TransferListener listener); 41 | 42 | boolean upload(FileFilter filter, SshjConnection connection, 43 | String localFile, String remoteDir, 44 | CommandLog commandLog, boolean createRemoteDir); 45 | 46 | /** 47 | * get file from remote server 48 | * 49 | * @param sshServer server information 50 | * @param remoteFile remote file absolute path 51 | * @param localFile local file absolute path 52 | * @return download result 53 | */ 54 | SshStatus download(SshServer sshServer, String remoteFile, String localFile); 55 | 56 | /** 57 | * test whether the remote target directory is existed. 58 | * 59 | * @param server ssh server information 60 | * @param remoteTargetDir remote target directory 61 | * @return return true if the remote target directory is existed, or return false 62 | */ 63 | SshStatus isDirExist(SshServer server, String remoteTargetDir); 64 | 65 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/service/impl/PluginNotificationService.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.service.impl; 2 | 3 | import com.intellij.notification.Notification; 4 | import com.intellij.notification.NotificationGroup; 5 | import com.intellij.notification.NotificationGroupManager; 6 | import com.intellij.notification.NotificationType; 7 | import com.intellij.openapi.actionSystem.AnAction; 8 | import com.intellij.openapi.components.Service; 9 | import com.intellij.openapi.project.Project; 10 | import tech.lin2j.idea.plugin.enums.Constant; 11 | 12 | /** 13 | * @author linjinjia 14 | * @date 2024/11/17 19:31 15 | */ 16 | @Service 17 | public final class PluginNotificationService { 18 | 19 | private final NotificationGroup notificationGroup; 20 | 21 | public PluginNotificationService() { 22 | notificationGroup = NotificationGroupManager.getInstance().getNotificationGroup(Constant.EASY_DEPLOY); 23 | } 24 | 25 | public void showNotification(Project project, String title, String message) { 26 | Notification notification = notificationGroup.createNotification(title, message, NotificationType.INFORMATION); 27 | notification.setTitle(title); 28 | notification.setContent(message); 29 | notification.notify(project); 30 | } 31 | 32 | public void showNotification(Project project, String title, String message, AnAction action) { 33 | Notification notification = notificationGroup.createNotification(title, message, NotificationType.INFORMATION); 34 | notification.setTitle(title); 35 | notification.setContent(message); 36 | notification.addAction(action); 37 | notification.notify(project); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/ClosableCloudTerminalProcess.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import org.jetbrains.plugins.terminal.cloud.CloudTerminalProcess; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2024/5/16 23:40 8 | */ 9 | public class ClosableCloudTerminalProcess extends CloudTerminalProcess { 10 | 11 | private final CustomTtyConnector connector; 12 | 13 | public ClosableCloudTerminalProcess(CustomTtyConnector connector) { 14 | super(connector.getOutputStream(), connector.getInputStream()); 15 | this.connector = connector; 16 | } 17 | 18 | @Override 19 | public void destroy() { 20 | super.destroy(); 21 | if (connector != null) { 22 | connector.close(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/CommandLog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import com.intellij.execution.ui.ConsoleView; 4 | import com.intellij.execution.ui.ConsoleViewContentType; 5 | import com.intellij.openapi.util.Key; 6 | 7 | /** 8 | * 9 | * @author linjinjia 10 | * @date 2024/11/28 22:14 11 | */ 12 | public interface CommandLog { 13 | Key COMMAND_LOG_KEY = Key.create("ProjectCommandLog"); 14 | 15 | ConsoleView getConsole(); 16 | 17 | void print(String msg, ConsoleViewContentType contentType); 18 | 19 | default void print(String msg) { 20 | print(msg, ConsoleViewContentType.NORMAL_OUTPUT); 21 | } 22 | 23 | default void info(String msg) { 24 | print("[INFO] ", ConsoleViewContentType.LOG_INFO_OUTPUT); 25 | if (msg != null && !msg.endsWith("\n")) { 26 | msg += "\n"; 27 | } 28 | print(msg, ConsoleViewContentType.NORMAL_OUTPUT); 29 | } 30 | 31 | default void println(String msg) { 32 | print(msg + "\n", ConsoleViewContentType.NORMAL_OUTPUT); 33 | } 34 | 35 | default void error(String msg) { 36 | print("[ERROR] ", ConsoleViewContentType.LOG_ERROR_OUTPUT); 37 | if (msg != null && !msg.endsWith("\n")) { 38 | msg += "\n"; 39 | } 40 | print(msg, ConsoleViewContentType.ERROR_OUTPUT); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/ConsoleCommandLog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import com.intellij.execution.ui.ConsoleView; 4 | import com.intellij.execution.ui.ConsoleViewContentType; 5 | 6 | public class ConsoleCommandLog implements CommandLog { 7 | private final ConsoleView console; 8 | 9 | public ConsoleCommandLog(ConsoleView console) { 10 | this.console = console; 11 | } 12 | 13 | @Override 14 | public ConsoleView getConsole() { 15 | return console; 16 | } 17 | 18 | @Override 19 | public void print(String msg, ConsoleViewContentType contentType) { 20 | console.print(msg, contentType); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/CustomTtyConnector.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import com.jediterm.terminal.TtyConnector; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.awt.Dimension; 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2022/6/24 21:41 13 | */ 14 | public interface CustomTtyConnector extends TtyConnector { 15 | 16 | /** 17 | * JSch, implementation of SSH2 18 | */ 19 | @Deprecated 20 | String JSCH = "JSch"; 21 | 22 | /** 23 | * SSHJ, implementation of SSH2 24 | */ 25 | String SSHJ = "SSHJ"; 26 | 27 | InputStream getInputStream(); 28 | 29 | OutputStream getOutputStream(); 30 | 31 | void setName(String title); 32 | 33 | void resize(@NotNull Dimension termSize); 34 | 35 | void resizeImmediately(); 36 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/JavaProcess.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import com.intellij.openapi.util.text.StringUtil; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Objects; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2024/11/7 21:48 11 | */ 12 | public class JavaProcess implements Comparable { 13 | 14 | private final int pid; 15 | private final String name; 16 | private final String process; 17 | 18 | public JavaProcess(String process) { 19 | Objects.requireNonNull(process); 20 | 21 | this.process = StringUtil.trim(process); 22 | 23 | String[] ss = process.split(" "); 24 | pid = Integer.parseInt(ss[0]); 25 | name = StringUtil.trim(ss[1]); 26 | } 27 | 28 | public int getPid() { 29 | return pid; 30 | } 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return process; 39 | } 40 | 41 | @Override 42 | public int compareTo(@NotNull JavaProcess o) { 43 | return this.name.compareTo(o.name); 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/SshConnection.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | 4 | import java.io.IOException; 5 | import java.util.concurrent.FutureTask; 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | /** 9 | * @author linjinjia 10 | * @date 2022/6/24 20:46 11 | */ 12 | public interface SshConnection { 13 | 14 | /** 15 | * Return whether the SSH connection has been successfully established. 16 | * @return true if established, false otherwise 17 | */ 18 | boolean isConnected(); 19 | 20 | /** 21 | * upload file from local to remote server 22 | * @param local the absolute path of local file 23 | * @param dest the absolute path of remote destination 24 | */ 25 | void upload(String local, String dest) throws IOException; 26 | 27 | /** 28 | * download file from remote server 29 | * @param remote the absolute path of remote file 30 | * @param dest the absolute path that the file will be stored 31 | */ 32 | void download(String remote, String dest) throws IOException; 33 | 34 | void scpUpload(String local, String dest) throws IOException; 35 | 36 | void scpDownload(String remote, String dest) throws IOException; 37 | 38 | /** 39 | * execute command
40 | * note that command like 'tail -f' will block the thread 41 | * @param cmd command 42 | * @return the execution result of the command, some commands 43 | * return results while others indicate errors, requiring the 44 | * caller to discern 45 | */ 46 | SshStatus execute(String cmd) throws IOException; 47 | 48 | FutureTask executeAsync(CommandLog commandLog, String cmd, 49 | AtomicBoolean cancel, boolean closeAfterFinished); 50 | 51 | /** 52 | * Create a directory, automatically creating parent directories 53 | * if they do not exist. 54 | * 55 | * @param dir directory path 56 | * @throws IOException IOException 57 | */ 58 | void mkdirs(String dir) throws IOException; 59 | 60 | /** 61 | * close the ssh connection 62 | */ 63 | void close(); 64 | 65 | /** 66 | * return true when the connection has closed, otherwise return false; 67 | * @return turn only if the connection has closed, otherwise return false 68 | */ 69 | boolean isClosed(); 70 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/SshProcess.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | 6 | /** 7 | * @author linjinjia 8 | * @date 2022/6/25 00:36 9 | */ 10 | public class SshProcess extends Process { 11 | 12 | private final CustomTtyConnector ttyConnector; 13 | 14 | public SshProcess(CustomTtyConnector customTtyConnector) { 15 | this.ttyConnector = customTtyConnector; 16 | } 17 | 18 | @Override 19 | public OutputStream getOutputStream() { 20 | return ttyConnector.getOutputStream(); 21 | } 22 | 23 | @Override 24 | public InputStream getInputStream() { 25 | return ttyConnector.getInputStream(); 26 | } 27 | 28 | @Override 29 | public InputStream getErrorStream() { 30 | return ttyConnector.getInputStream(); 31 | } 32 | 33 | @Override 34 | public int waitFor() throws InterruptedException { 35 | while(isAlive()) { 36 | this.wait(); 37 | } 38 | return exitValue(); 39 | } 40 | 41 | @Override 42 | public int exitValue() { 43 | if (ttyConnector.isConnected()) { 44 | throw new IllegalThreadStateException(); 45 | } 46 | return 0; 47 | } 48 | 49 | @Override 50 | public void destroy() { 51 | try { 52 | ttyConnector.close(); 53 | } catch (Exception e) { 54 | // 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/SshStatus.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2022/4/25 21:13 6 | */ 7 | public class SshStatus { 8 | 9 | private boolean success; 10 | 11 | private String message; 12 | 13 | private Object data; 14 | 15 | public SshStatus(boolean success, String message) { 16 | this.success = success; 17 | this.message = message; 18 | } 19 | 20 | public SshStatus(boolean success, String message, Object data) { 21 | this.success = success; 22 | this.message = message; 23 | this.data = data; 24 | } 25 | 26 | public boolean isSuccess() { 27 | return success; 28 | } 29 | 30 | public void setSuccess(boolean success) { 31 | this.success = success; 32 | } 33 | 34 | public String getMessage() { 35 | return message; 36 | } 37 | 38 | public void setMessage(String message) { 39 | this.message = message; 40 | } 41 | 42 | public Object getData() { 43 | return data; 44 | } 45 | 46 | public void setData(Object data) { 47 | this.data = data; 48 | } 49 | 50 | 51 | @Override 52 | public String toString() { 53 | return "SshStatus{" + 54 | "success=" + success + 55 | ", message='" + message + '\'' + 56 | '}'; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/SshUploadTask.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh; 2 | 3 | import com.intellij.execution.ui.ConsoleView; 4 | import tech.lin2j.idea.plugin.model.ConfigHelper; 5 | import tech.lin2j.idea.plugin.model.DeployProfile; 6 | import tech.lin2j.idea.plugin.model.UploadProfile; 7 | import tech.lin2j.idea.plugin.uitl.CommandUtil; 8 | 9 | import java.util.Objects; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/5/2 17:11 14 | */ 15 | public class SshUploadTask implements Runnable { 16 | private final int sshId; 17 | private final int profileId; 18 | private final ConsoleView console; 19 | 20 | private UploadProfile profile; 21 | private SshServer server; 22 | private String taskName; 23 | 24 | public SshUploadTask(ConsoleView console, DeployProfile deployProfile) { 25 | this.sshId = deployProfile.getSshId(); 26 | this.profileId = deployProfile.getProfileId(); 27 | this.console = console; 28 | this.server = getServer(); 29 | this.profile = getProfile(); 30 | 31 | this.taskName = String.format("%s - %s", server.getIp(), profile.getName()); 32 | } 33 | 34 | public SshUploadTask(ConsoleView console, int sshId, int profileId) { 35 | this.console = console; 36 | this.sshId = sshId; 37 | this.profileId = profileId; 38 | } 39 | 40 | @Override 41 | public void run() { 42 | UploadProfile profile = getProfile(); 43 | SshServer server = getServer(); 44 | ConsoleCommandLog commandLog = new ConsoleCommandLog(console); 45 | CommandUtil.executeUpload(profile, server, commandLog); 46 | } 47 | 48 | public UploadProfile getProfile() { 49 | if (profile == null) { 50 | profile = ConfigHelper.getOneUploadProfileById(sshId, profileId); 51 | } 52 | Objects.requireNonNull(profile); 53 | return profile; 54 | } 55 | 56 | public SshServer getServer() { 57 | if (server == null) { 58 | server = ConfigHelper.getSshServerById(sshId); 59 | } 60 | Objects.requireNonNull(server); 61 | return server; 62 | } 63 | 64 | public String getTaskName() { 65 | return taskName; 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ssh/exception/RemoteSdkException.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ssh.exception; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2022/6/26 14:09 6 | */ 7 | public class RemoteSdkException extends RuntimeException{ 8 | 9 | public RemoteSdkException(String msg, Throwable e) { 10 | super(msg, e); 11 | } 12 | 13 | public RemoteSdkException(String msg) { 14 | super(msg); 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/component/ArrowLabel.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.component; 2 | 3 | import com.intellij.ui.components.JBLabel; 4 | 5 | import java.awt.Dimension; 6 | import java.awt.Graphics; 7 | import java.awt.Graphics2D; 8 | import java.awt.RenderingHints; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/5/19 11:30 13 | */ 14 | public class ArrowLabel extends JBLabel { 15 | private final boolean curved; 16 | private final boolean leftToRight; 17 | 18 | public ArrowLabel(boolean curved, boolean leftToRight) { 19 | this.curved = curved; 20 | this.leftToRight = leftToRight; 21 | } 22 | 23 | @Override 24 | protected void paintComponent(Graphics g) { 25 | super.paintComponent(g); 26 | Graphics2D g2d = (Graphics2D) g.create(); 27 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 28 | int midY = getHeight() / 2; 29 | int startX = leftToRight ? 0 : getWidth(); 30 | int endX = leftToRight ? getWidth() : 0; 31 | 32 | if (curved) { 33 | startX = endX = getWidth() / 2; 34 | int startY = 0; 35 | int endY = getHeight(); 36 | g2d.drawLine(startX, startY, endX, endY); 37 | g2d.drawLine(endX, endY, endX - 5, endY - 5); 38 | g2d.drawLine(endX, endY, endX + 5, endY - 5); 39 | } else { 40 | g2d.drawLine(startX, midY, endX, midY); 41 | g2d.drawLine(endX, midY, endX - (leftToRight ? 5 : -5), midY - 5); 42 | g2d.drawLine(endX, midY, endX - (leftToRight ? 5 : -5), midY + 5); 43 | } 44 | g2d.dispose(); 45 | } 46 | 47 | @Override 48 | public Dimension getPreferredSize() { 49 | return new Dimension(30, 30); 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/component/HostChainItem.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.component; 2 | 3 | import tech.lin2j.idea.plugin.ssh.SshServer; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2024/5/19 11:42 8 | */ 9 | public class HostChainItem { 10 | 11 | private SshServer server; 12 | 13 | /** 14 | * the dependencies of some of host from a cycle 15 | */ 16 | private Boolean cycle; 17 | 18 | public HostChainItem(SshServer server, Boolean cycle) { 19 | this.server = server; 20 | this.cycle = cycle; 21 | } 22 | 23 | public SshServer getServer() { 24 | return server; 25 | } 26 | 27 | public Boolean isCycle() { 28 | return cycle; 29 | } 30 | 31 | public void setServer(SshServer server) { 32 | this.server = server; 33 | } 34 | 35 | public void setCycle(Boolean cycle) { 36 | this.cycle = cycle; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/component/ManualProxyPanel.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.component; 2 | 3 | public class ManualProxyPanel { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/dialog/ImportConfigPreviewDialog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.dialog; 2 | 3 | //import com.intellij.json.JsonFileType; 4 | import com.intellij.lang.Language; 5 | import com.intellij.openapi.fileTypes.PlainTextFileType; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.DialogWrapper; 8 | import com.intellij.ui.AdditionalPageAtBottomEditorCustomization; 9 | import com.intellij.ui.EditorCustomization; 10 | import com.intellij.ui.EditorTextField; 11 | import com.intellij.ui.EditorTextFieldProvider; 12 | import com.intellij.ui.SoftWrapsEditorCustomization; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import javax.swing.JComponent; 16 | import java.awt.Dimension; 17 | import java.util.HashSet; 18 | import java.util.Set; 19 | 20 | /** 21 | * @author linjinjia 22 | * @date 2024/7/19 23:32 23 | */ 24 | public class ImportConfigPreviewDialog extends DialogWrapper { 25 | private final Project project; 26 | private final String content; 27 | private EditorTextField editor; 28 | 29 | public ImportConfigPreviewDialog(@Nullable Project project, String content) { 30 | super(project); 31 | this.project = project; 32 | this.content = content; 33 | 34 | initEditor(); 35 | 36 | setTitle("Import Configuration Preview"); 37 | setOKButtonText("Import"); 38 | init(); 39 | } 40 | 41 | @Nullable 42 | @Override 43 | public JComponent createCenterPanel() { 44 | return editor; 45 | } 46 | 47 | private void initEditor() { 48 | Set features = new HashSet<>(); 49 | features.add(SoftWrapsEditorCustomization.ENABLED); 50 | features.add(AdditionalPageAtBottomEditorCustomization.DISABLED); 51 | features.add(editor -> editor.setBackgroundColor(null)); 52 | features.add((editor -> editor.getSettings().setLineNumbersShown(true))); 53 | 54 | // Language json = JsonFileType.INSTANCE.getLanguage(); 55 | Language text = PlainTextFileType.INSTANCE.getLanguage(); 56 | editor = EditorTextFieldProvider.getInstance().getEditorField(text, project, features); 57 | 58 | // Global editor color scheme is set by EditorTextField logic. 59 | // We also need to use font from it and not from the current LaF. 60 | editor.setFontInheritedFromLAF(false); 61 | editor.setPreferredSize(new Dimension(650, 750)); 62 | editor.setText(content); 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/dialog/PasswordInputDialog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.dialog; 2 | 3 | import com.intellij.openapi.ui.DialogWrapper; 4 | import com.intellij.util.ui.FormBuilder; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import javax.swing.JComponent; 8 | import javax.swing.JPanel; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/5/5 01:11 13 | */ 14 | public class PasswordInputDialog extends DialogWrapper { 15 | 16 | private final JPanel root; 17 | 18 | protected PasswordInputDialog(StringBuilder password) { 19 | super(true); 20 | 21 | 22 | root = FormBuilder.createFormBuilder() 23 | .getPanel(); 24 | 25 | init(); 26 | } 27 | 28 | @Nullable 29 | @Override 30 | protected JComponent createCenterPanel() { 31 | return root; 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/dialog/PluginSettingsDialog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.dialog; 2 | 3 | import com.intellij.ide.actions.ShowSettingsUtilImpl; 4 | import com.intellij.openapi.options.Configurable; 5 | import com.intellij.openapi.options.ConfigurableGroup; 6 | import com.intellij.openapi.project.Project; 7 | import org.jetbrains.annotations.NotNull; 8 | import tech.lin2j.idea.plugin.ui.settings.GeneralConfigurable; 9 | import tech.lin2j.idea.plugin.ui.settings.SFTPConfigurable; 10 | import tech.lin2j.idea.plugin.ui.settings.ServerTagConfigurable; 11 | 12 | import java.util.Collections; 13 | 14 | /** 15 | * @author linjinjia 16 | * @date 2024/4/21 18:42 17 | */ 18 | public class PluginSettingsDialog { 19 | public static Configurable[] createNewConfigurable(Project project) { 20 | return new Configurable[]{ 21 | new GeneralConfigurable(), 22 | new ServerTagConfigurable(), 23 | new SFTPConfigurable() 24 | }; 25 | } 26 | 27 | public static void show(Project project) { 28 | show(project, createNewConfigurable(project), 0); 29 | } 30 | 31 | public static void show(Project project, Configurable[] configurable, int toSelect) { 32 | CoolConfigurableGroup coolConfigurableGroup = new CoolConfigurableGroup(configurable); 33 | // SwingUtilities.invokeLater(() -> { 34 | ShowSettingsUtilImpl.getDialog( 35 | project, 36 | Collections.singletonList(coolConfigurableGroup), 37 | configurable[toSelect] 38 | ).show(); 39 | // }); 40 | } 41 | 42 | 43 | static class CoolConfigurableGroup implements ConfigurableGroup { 44 | private final Configurable[] configurables; 45 | 46 | public CoolConfigurableGroup(Configurable[] configurables) { 47 | this.configurables = configurables; 48 | } 49 | 50 | @Override 51 | public String getDisplayName() { 52 | return "Easy Deploy"; 53 | } 54 | 55 | @Override 56 | public Configurable @NotNull [] getConfigurables() { 57 | return configurables; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/dialog/SelectServerDialog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.dialog; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.ui.ComboBox; 5 | import com.intellij.openapi.ui.DialogWrapper; 6 | import com.intellij.ui.CollectionComboBoxModel; 7 | import com.intellij.util.ui.FormBuilder; 8 | import org.jetbrains.annotations.Nullable; 9 | import tech.lin2j.idea.plugin.model.ConfigHelper; 10 | import tech.lin2j.idea.plugin.model.HotReloadPersistence; 11 | import tech.lin2j.idea.plugin.ssh.SshServer; 12 | 13 | import javax.swing.JComponent; 14 | 15 | /** 16 | * @author linjinjia 17 | * @date 2024/11/23 10:47 18 | */ 19 | public class SelectServerDialog extends DialogWrapper { 20 | 21 | private final Project project; 22 | private final ComboBox sshServers; 23 | 24 | public SelectServerDialog(@Nullable Project project) { 25 | super(project); 26 | this.project = project; 27 | 28 | sshServers = new ComboBox<>(); 29 | 30 | setTitle("Select Server"); 31 | setSize(200, 0); 32 | init(); 33 | } 34 | 35 | @Override 36 | protected @Nullable JComponent createCenterPanel() { 37 | sshServers.setModel(new CollectionComboBoxModel<>(ConfigHelper.sshServers())); 38 | return FormBuilder.createFormBuilder() 39 | .addComponent(sshServers) 40 | .getPanel(); 41 | } 42 | 43 | @Override 44 | protected void doOKAction() { 45 | SshServer selectedValue = (SshServer) sshServers.getSelectedItem(); 46 | if (selectedValue != null) { 47 | HotReloadPersistence state = project.getService(HotReloadPersistence.class).getState(); 48 | state.setSshId(selectedValue.getId()); 49 | } 50 | super.doOKAction(); 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/dialog/TransferConfirmDialog.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.dialog; 2 | 3 | import javax.swing.JPanel; 4 | 5 | /** 6 | * @author linjinjia 7 | * @date 2024/4/18 06:31 8 | */ 9 | public class TransferConfirmDialog { 10 | private JPanel root; 11 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/editor/SFTPEditorProvider.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.editor; 2 | 3 | import com.intellij.openapi.fileEditor.FileEditor; 4 | import com.intellij.openapi.fileEditor.FileEditorPolicy; 5 | import com.intellij.openapi.fileEditor.FileEditorProvider; 6 | import com.intellij.openapi.fileEditor.FileEditorState; 7 | import com.intellij.openapi.project.DumbAware; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.vfs.VirtualFile; 10 | import org.jdom.Element; 11 | import org.jetbrains.annotations.NonNls; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | /** 15 | * @author linjinjia 16 | * @date 2024/4/22 21:56 17 | */ 18 | public class SFTPEditorProvider implements FileEditorProvider, DumbAware { 19 | @Override 20 | public boolean accept(@NotNull Project project, @NotNull VirtualFile virtualFile) { 21 | return virtualFile instanceof SFTPVirtualFile; 22 | } 23 | 24 | @Override 25 | public @NotNull FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile virtualFile) { 26 | return new SFTPEditor(virtualFile); 27 | } 28 | 29 | @Override 30 | public void disposeEditor(@NotNull FileEditor editor) { 31 | FileEditorProvider.super.disposeEditor(editor); 32 | } 33 | 34 | @Override 35 | public @NotNull FileEditorState readState(@NotNull Element sourceElement, @NotNull Project project, @NotNull VirtualFile file) { 36 | return FileEditorProvider.super.readState(sourceElement, project, file); 37 | } 38 | 39 | @Override 40 | public void writeState(@NotNull FileEditorState state, @NotNull Project project, @NotNull Element targetElement) { 41 | FileEditorProvider.super.writeState(state, project, targetElement); 42 | } 43 | 44 | @Override 45 | public @NotNull 46 | @NonNls String getEditorTypeId() { 47 | return "Redis Console"; 48 | } 49 | 50 | @Override 51 | public @NotNull FileEditorPolicy getPolicy() { 52 | return FileEditorPolicy.HIDE_DEFAULT_EDITOR; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/ftp/container/FileTableContainer.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.ftp.container; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.ui.table.JBTable; 5 | import net.schmizz.sshj.sftp.SFTPClient; 6 | import tech.lin2j.idea.plugin.file.TableFile; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/6 21:11 14 | */ 15 | public interface FileTableContainer { 16 | 17 | default boolean isLocal() { 18 | return true; 19 | } 20 | 21 | JBTable getTable(); 22 | 23 | List getFileList(); 24 | 25 | List getSelectedFiles(); 26 | 27 | void setPath(String path); 28 | 29 | String getPath(); 30 | 31 | String getHomePath(); 32 | 33 | String getParentPath(); 34 | 35 | void deleteFileAndDir(TableFile tf); 36 | 37 | boolean createNewFolder(String path) throws IOException; 38 | 39 | boolean showHiddenFileAndDir(); 40 | 41 | void reversedHiddenFlag(); 42 | 43 | void refreshFileList(); 44 | 45 | Project getProject(); 46 | 47 | default SFTPClient getFTPClient() { 48 | throw new UnsupportedOperationException(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/module/DashboardView.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.module; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.ui.SimpleToolWindowPanel; 5 | import com.intellij.ui.JBSplitter; 6 | 7 | /** 8 | * @author linjinjia 9 | * @date 2022/4/24 17:01 10 | */ 11 | public class DashboardView extends SimpleToolWindowPanel { 12 | 13 | private final Project project; 14 | private final tech.lin2j.idea.plugin.ui.DashboardView consoleUi; 15 | 16 | public DashboardView(Project project) { 17 | super(false, true); 18 | this.project = project; 19 | this.consoleUi = new tech.lin2j.idea.plugin.ui.DashboardView(project); 20 | 21 | JBSplitter splitter = new JBSplitter(false); 22 | splitter.setSplitterProportionKey("main.splitter.key"); 23 | splitter.setFirstComponent(consoleUi); 24 | splitter.setProportion(0.3f); 25 | setContent(splitter); 26 | } 27 | 28 | public Project getProject() { 29 | return project; 30 | } 31 | 32 | public tech.lin2j.idea.plugin.ui.DashboardView getConsoleUi() { 33 | return consoleUi; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/render/CommandColoredListCellRenderer.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.render; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.ui.ColoredListCellRenderer; 6 | import com.intellij.ui.SimpleTextAttributes; 7 | import org.jetbrains.annotations.NotNull; 8 | import tech.lin2j.idea.plugin.model.Command; 9 | import tech.lin2j.idea.plugin.model.ConfigHelper; 10 | import tech.lin2j.idea.plugin.model.SeparatorCommand; 11 | import tech.lin2j.idea.plugin.ssh.SshServer; 12 | 13 | import javax.swing.JList; 14 | import java.util.Objects; 15 | 16 | /** 17 | * @author linjinjia 18 | * @date 2024/4/27 11:08 19 | */ 20 | public class CommandColoredListCellRenderer extends ColoredListCellRenderer { 21 | 22 | public static final String TEXT_PADDING = " "; 23 | 24 | private final Integer sshId; 25 | 26 | public CommandColoredListCellRenderer(Integer sshId) { 27 | this.sshId = sshId; 28 | } 29 | 30 | @Override 31 | protected void customizeCellRenderer(@NotNull JList list, Command value, 32 | int index, boolean selected, boolean hasFocus) { 33 | if (value instanceof SeparatorCommand) { 34 | append(value.getTitle(), SimpleTextAttributes.GRAY_ATTRIBUTES); 35 | return; 36 | } 37 | setIcon(AllIcons.Debugger.Console); 38 | if (StringUtil.isNotEmpty(value.getTitle())) { 39 | append(value.getTitle()); 40 | append(TEXT_PADDING); 41 | } 42 | // server info 43 | if (!Objects.equals(sshId, value.getSshId()) && value.getSharable()) { 44 | SshServer server = ConfigHelper.getSshServerById(value.getSshId()); 45 | if (server != null) { 46 | append("Shared by [" + server.getIp() + "]", SimpleTextAttributes.GRAY_ATTRIBUTES); 47 | append(TEXT_PADDING); 48 | } 49 | } 50 | append(Objects.toString(value), SimpleTextAttributes.GRAY_ATTRIBUTES); 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/render/UploadProfileColoredListCellRenderer.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.render; 2 | 3 | import com.intellij.ui.ColoredListCellRenderer; 4 | import icons.MyIcons; 5 | import org.jetbrains.annotations.NotNull; 6 | import tech.lin2j.idea.plugin.model.UploadProfile; 7 | 8 | import javax.swing.JList; 9 | 10 | /** 11 | * @author linjinjia 12 | * @date 2024/4/27 11:08 13 | */ 14 | public class UploadProfileColoredListCellRenderer extends ColoredListCellRenderer { 15 | 16 | @Override 17 | protected void customizeCellRenderer(@NotNull JList list, UploadProfile value, 18 | int index, boolean selected, boolean hasFocus) { 19 | setIcon(MyIcons.UploadProfile); 20 | append(value.getName()); 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/table/ActionCellEditor.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.table; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import tech.lin2j.idea.plugin.ui.component.HostActionPanel; 5 | 6 | import javax.swing.AbstractCellEditor; 7 | import javax.swing.JTable; 8 | import javax.swing.table.TableCellEditor; 9 | import java.awt.Component; 10 | import java.util.EventObject; 11 | import java.util.Objects; 12 | 13 | /** 14 | * @author linjinjia 15 | * @date 2024/5/5 17:00 16 | */ 17 | public class ActionCellEditor extends AbstractCellEditor implements TableCellEditor { 18 | private final Project project; 19 | 20 | private HostActionPanel actionPane; 21 | 22 | public ActionCellEditor(Project project) { 23 | this.project = project; 24 | } 25 | 26 | @Override 27 | public Component getTableCellEditorComponent(JTable table, Object value, 28 | boolean isSelected, int row, int column) { 29 | int sshId = Integer.parseInt(Objects.toString(value)); 30 | actionPane = new HostActionPanel(sshId, project); 31 | return actionPane; 32 | } 33 | 34 | @Override 35 | public Object getCellEditorValue() { 36 | return actionPane.getState(); 37 | } 38 | 39 | @Override 40 | public boolean isCellEditable(EventObject anEvent) { 41 | return true; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/table/ActionCellRenderer.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.table; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import tech.lin2j.idea.plugin.ui.component.HostActionPanel; 5 | 6 | import javax.swing.JTable; 7 | import javax.swing.table.DefaultTableCellRenderer; 8 | import java.awt.Component; 9 | import java.util.Objects; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/5/5 17:00 14 | */ 15 | public class ActionCellRenderer extends DefaultTableCellRenderer { 16 | 17 | private final Project project; 18 | 19 | public ActionCellRenderer(Project project) { 20 | this.project = project; 21 | } 22 | 23 | @Override 24 | public Component getTableCellRendererComponent(JTable table, Object value, 25 | boolean isSelected, boolean hasFocus, int row, int column) { 26 | Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 27 | int sshId = Integer.parseInt(Objects.toString(value)); 28 | HostActionPanel actionPane = new HostActionPanel(sshId, project); 29 | actionPane.setForeground(c.getForeground()); 30 | actionPane.setBackground(c.getBackground()); 31 | return actionPane; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/table/FileNameCellRenderer.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.table; 2 | 3 | import com.intellij.util.ui.table.IconTableCellRenderer; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | import tech.lin2j.idea.plugin.file.TableFile; 7 | 8 | import javax.swing.Icon; 9 | import javax.swing.JLabel; 10 | import javax.swing.JTable; 11 | import java.awt.Component; 12 | 13 | /** 14 | * @author linjinjia 15 | * @date 2024/4/6 13:51 16 | */ 17 | public class FileNameCellRenderer extends IconTableCellRenderer { 18 | 19 | @Override 20 | public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focus, int row, int column) { 21 | Component component = super.getTableCellRendererComponent(table, value, selected, focus, row, column); 22 | ((JLabel) component).setText(((TableFile)value).getName()); 23 | return component; 24 | } 25 | 26 | @Nullable 27 | @Override 28 | protected Icon getIcon(@NotNull TableFile value, JTable table, int row) { 29 | return value.getIcon(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/ui/table/ProgressCell.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.ui.table; 2 | 3 | import com.intellij.openapi.progress.util.ColorProgressBar; 4 | import com.intellij.ui.table.JBTable; 5 | import tech.lin2j.idea.plugin.file.DirectoryInfo; 6 | 7 | import javax.swing.table.TableModel; 8 | 9 | /** 10 | * @author linjinjia 11 | * @date 2024/4/15 22:23 12 | */ 13 | public class ProgressCell { 14 | private final JBTable table; 15 | private final ColorProgressBar colorProgressBar; 16 | private DirectoryInfo directoryInfo; 17 | private int row; 18 | private long transferred; 19 | 20 | public ProgressCell(JBTable table, int row, ColorProgressBar colorProgressBar) { 21 | this.table = table; 22 | this.row = row; 23 | this.colorProgressBar = colorProgressBar; 24 | } 25 | 26 | public JBTable getTable() { 27 | return table; 28 | } 29 | 30 | public int getRow() { 31 | return row; 32 | } 33 | 34 | public void setRow(int row) { 35 | this.row = row; 36 | } 37 | 38 | public ColorProgressBar getColorProgressBar() { 39 | return colorProgressBar; 40 | } 41 | 42 | public boolean isDirectoryRow() { 43 | return directoryInfo.isDirectory(); 44 | } 45 | 46 | public long getDirectorySize() { 47 | return directoryInfo.getSize(); 48 | } 49 | 50 | public TableModel getTableModel() { 51 | return table.getModel(); 52 | } 53 | 54 | public void setDirectoryInfo(DirectoryInfo directoryInfo) { 55 | this.directoryInfo = directoryInfo; 56 | } 57 | 58 | public long getTransferred() { 59 | return transferred; 60 | } 61 | 62 | public void addTransferred(long transferred) { 63 | this.transferred += transferred; 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/uitl/EasyDeployPluginUtil.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.uitl; 2 | 3 | import com.intellij.ide.plugins.PluginManagerCore; 4 | import com.intellij.openapi.extensions.PluginId; 5 | import com.intellij.ui.components.JBLabel; 6 | import com.intellij.util.IconUtil; 7 | import icons.MyIcons; 8 | 9 | import javax.swing.Icon; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/5/26 15:14 14 | */ 15 | public class EasyDeployPluginUtil { 16 | 17 | public static final PluginId PLUGIN_ID = PluginId.getId("tech.lin2j.simple-deployment"); 18 | public static final String version = PluginManagerCore.getPlugin(PLUGIN_ID).getVersion(); 19 | 20 | public static String version() { 21 | return version; 22 | } 23 | 24 | public static boolean isEnabled() { 25 | return PluginManagerCore.getPlugin(PLUGIN_ID).isEnabled(); 26 | } 27 | 28 | public static JBLabel versionLabel() { 29 | return new JBLabel("Version: " + EasyDeployPluginUtil.version()); 30 | } 31 | 32 | public static JBLabel pluginIconLabel() { 33 | JBLabel label = new JBLabel(); 34 | Icon icon = IconUtil.scale(MyIcons.EasyDeploy, label,4f); 35 | label.setIcon(icon); 36 | return label; 37 | } 38 | 39 | 40 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/uitl/FTPUtil.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.uitl; 2 | 3 | import net.schmizz.sshj.sftp.FileMode; 4 | import net.schmizz.sshj.sftp.RemoteResourceInfo; 5 | import net.schmizz.sshj.sftp.SFTPClient; 6 | import tech.lin2j.idea.plugin.file.DirectoryInfo; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | /** 12 | * @author linjinjia 13 | * @date 2024/4/14 14:54 14 | */ 15 | public class FTPUtil { 16 | 17 | /** 18 | * Calculates the size of a directory on a remote FTP server recursively. 19 | * 20 | * @param ftpClient The FTP client connected to the server. 21 | * @param remoteDir The remote directory whose size needs to be calculated. 22 | * @return The total size of the remote directory and its contents, in bytes. 23 | * @throws IOException If an I/O error occurs while accessing the FTP server. 24 | */ 25 | public static DirectoryInfo calcDirectorySize(SFTPClient ftpClient, String remoteDir) throws IOException { 26 | DirectoryInfo di = new DirectoryInfo(); 27 | FileMode.Type type = ftpClient.type(remoteDir); 28 | if (type != FileMode.Type.DIRECTORY) { 29 | di.setDirectory(false); 30 | di.setSize(ftpClient.stat(remoteDir).getSize()); 31 | di.setFiles(1); 32 | return di; 33 | } 34 | di.setDirectory(true); 35 | List files = ftpClient.ls(remoteDir); 36 | if (files != null) { 37 | for (RemoteResourceInfo file : files) { 38 | DirectoryInfo subDi = calcDirectorySize(ftpClient, remoteDir + "/" + file.getName()); 39 | di.setFiles(di.getFiles() + subDi.getFiles()); 40 | di.setSize(di.getSize() + subDi.getSize()); 41 | } 42 | } 43 | return di; 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/uitl/FileTransferSpeed.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.uitl; 2 | 3 | /** 4 | * @author linjinjia 5 | * @date 2024/11/24 20:49 6 | */ 7 | public class FileTransferSpeed { 8 | private static final int UPDATE_INTERVAL = 750; 9 | private long lastTransferred; 10 | private long lastUpdateTime; 11 | private String speed = "-- B/s"; 12 | 13 | public FileTransferSpeed() { 14 | lastUpdateTime = System.currentTimeMillis(); 15 | lastTransferred = 0; 16 | } 17 | 18 | public String accept(long transferred) { 19 | long currentTime = System.currentTimeMillis(); 20 | 21 | if (currentTime - lastUpdateTime >= UPDATE_INTERVAL) { 22 | long deltaBytes = transferred - lastTransferred; 23 | long elapsedTime = currentTime - lastUpdateTime; 24 | 25 | double speed = deltaBytes / (elapsedTime / 1000.0); // B/s 26 | this.speed = formatSpeed(speed); 27 | 28 | lastUpdateTime = currentTime; 29 | lastTransferred = transferred; 30 | } 31 | 32 | return speed; 33 | } 34 | 35 | private String formatSpeed(double speed) { 36 | final String[] units = {"B/s", "KB/s", "MB/s", "GB/s", "TB/s"}; 37 | int unitIndex = 0; 38 | 39 | while (speed >= 1024 && unitIndex < units.length - 1) { 40 | speed /= 1024; 41 | unitIndex++; 42 | } 43 | 44 | // 如果速度为 0 或非常小,直接返回 "0 B/s" 45 | if (speed < 1e-6) { 46 | return "-- B/s"; 47 | } 48 | 49 | return String.format("%.2f %s", speed, units[unitIndex]); 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/tech/lin2j/idea/plugin/uitl/MessagesBundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 XIN LIN HOU 3 | * ResourceBundleUtils.java is part of Cool Request 4 | * 5 | * License: GPL-3.0+ 6 | * 7 | * Cool Request is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Cool Request is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Cool Request. If not, see . 19 | */ 20 | 21 | package tech.lin2j.idea.plugin.uitl; 22 | 23 | 24 | import tech.lin2j.idea.plugin.model.ConfigHelper; 25 | 26 | import java.util.Locale; 27 | import java.util.ResourceBundle; 28 | 29 | /** 30 | * i18n 31 | * 32 | * @author linjinjia 2024/5/4 16:13 33 | */ 34 | public class MessagesBundle { 35 | 36 | public static String getText(String key) { 37 | int languageValue = ConfigHelper.language(); 38 | if (languageValue == -1) return getText(key, Locale.ENGLISH); 39 | if (languageValue == 0) return getText(key, Locale.ENGLISH); 40 | if (languageValue == 1) return getText(key, Locale.CHINESE); 41 | return getText(key, Locale.getDefault()); 42 | } 43 | 44 | private static String getText(String key, Locale locale) { 45 | ResourceBundle bundle = ResourceBundle.getBundle("messages", locale); 46 | return bundle.getString(key); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/arthas.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lin2j/easy-deploy/b9fc0ec2029ef5149418180c6d737ffd8feadec8/src/main/resources/arthas.tar.gz -------------------------------------------------------------------------------- /src/main/resources/icons/actions/copy.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | 9 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/export_import.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/home-page.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/host.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my-add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_clean.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_connect.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_export.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_import.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_settings.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_share.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/my_upload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/paste.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/showHiddens.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/showHiddens_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/deploy.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/deploy_dark.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/easy-deploy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/c.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/c_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/cpp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/cpp_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/dmg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/ebook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/excel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/pdf.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/ppt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/video.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | 9 | -------------------------------------------------------------------------------- /src/main/resources/icons/fileTypes/word.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/filter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/icons/message_blue.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | 9 | -------------------------------------------------------------------------------- /src/main/resources/icons/sftp.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/tag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/tag_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/transferToolWindow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/icons/transferToolWindow_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/java/tech/lin2j/idea/plugin/file/FilterTest.java: -------------------------------------------------------------------------------- 1 | package tech.lin2j.idea.plugin.file; 2 | 3 | import com.intellij.execution.ui.ConsoleView; 4 | import com.intellij.execution.ui.ConsoleViewContentType; 5 | import org.junit.Test; 6 | import tech.lin2j.idea.plugin.file.filter.ExtExcludeFilter; 7 | import tech.lin2j.idea.plugin.ssh.CommandLog; 8 | 9 | /** 10 | * @author linjinjia 11 | * @date 2022/12/11 00:00 12 | */ 13 | public class FilterTest { 14 | 15 | @Test 16 | public void testExtensionFilter() { 17 | String extensions = "*.iml;.log;****.bat"; 18 | ExtExcludeFilter fileFilter = new ExtExcludeFilter(extensions, new TestCommandLog()); 19 | String[] suffix = {"bat", "log", "iml"}; 20 | for (String s : suffix) { 21 | assert fileFilter.getExtensionSet().contains(s); 22 | } 23 | assert !fileFilter.accept("abc.iml"); 24 | assert fileFilter.accept("abc.txt"); 25 | assert fileFilter.accept("abc."); 26 | } 27 | 28 | private class TestCommandLog implements CommandLog { 29 | 30 | @Override 31 | public ConsoleView getConsole() { 32 | return null; 33 | } 34 | 35 | @Override 36 | public void print(String msg, ConsoleViewContentType contentType) { 37 | 38 | } 39 | } 40 | } --------------------------------------------------------------------------------