├── .gitattributes ├── .gitignore ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── QuickSwitchAction.java └── resources └── META-INF └── plugin.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle/ 3 | 4 | *.iws 5 | *.iml 6 | 7 | out/ 8 | build/ 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-cli-quick-switch-plugin 2 | 3 | IntelliJ Plugin for switching amongst Angular CLI component files efficiently (e.g. ts -> html -> css) by just using one shortcut (**Alt+S**). 4 | 5 | For example let's say we have a structure like this 6 | 7 | foo/ 8 | bar.info 9 | foo.component.css 10 | foo.component.html 11 | **foo.component.ts** 12 | foo.md 13 | 14 | By pressing the assigned shortcut repeatedly, the IDE will cycle amongst the files as follows: 15 | 16 | foo.component.ts -> foo.component.html -> foo.component.css -> foo.component.ts -> ... 17 | 18 | 19 | Whilst cycling, unknown filenames (like bar.info) and extensions (like foo.md) will be skipped on purpose. 20 | 21 | Explicitly whitelisted extensions are: 22 | - js, ts 23 | - html, php, haml, jade, pug, slim 24 | - css, sass, scss, less, styl 25 | 26 | Note: 27 | For switching between your code and test/spec files, you can simply use the built in default shortcut from IntelliJ (**Ctrl+Shift+T**) 28 | 29 | 30 | 31 | Further information: 32 | 33 | If the default shortcut **Alt + S** does not fit your needs, you can of course easily adjust it in the keymap settings by replacing it for **QuickSwitch**. 34 | 35 | Due to the nature of this plugin, it will of course also **work with other projects**, that have not been generated by Angular CLI - or are 36 | not even Angular projects at all - as long as your project structure follows similar patterns. -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * This is a general purpose Gradle build. 5 | * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds 6 | */ 7 | 8 | plugins { 9 | id 'java' 10 | id 'idea' 11 | id 'org.jetbrains.intellij' version '0.4.21' 12 | } 13 | 14 | group 'patrick.kelleter' 15 | version '1.3.1' 16 | 17 | apply plugin: 'java' 18 | 19 | java { 20 | sourceCompatibility = JavaVersion.VERSION_11 21 | } 22 | 23 | repositories { 24 | mavenCentral() 25 | } 26 | 27 | dependencies { 28 | testCompileOnly 'junit:junit:4.12' 29 | } 30 | 31 | intellij { 32 | updateSinceUntilBuild false 33 | } 34 | patchPluginXml { 35 | changeNotes """ 36 | - Added support for php, haml, jade, pug, slim, less, styl files.
- Updated docs
""" 37 | } 38 | 39 | task wrapper(type: Wrapper) { 40 | gradleVersion = '6.5' 41 | } 42 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pkelleter/angular-cli-quick-switch-plugin/ecf71027d608fd52b4121b44509f844537636d31/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 03 13:15:19 CEST 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin or MSYS, switch paths to Windows format before running java 114 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | JAVACMD=`cygpath --unix "$JAVACMD"` 119 | 120 | # We build the pattern for arguments to be converted via cygpath 121 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 122 | SEP="" 123 | for dir in $ROOTDIRSRAW ; do 124 | ROOTDIRS="$ROOTDIRS$SEP$dir" 125 | SEP="|" 126 | done 127 | OURCYGPATTERN="(^($ROOTDIRS))" 128 | # Add a user-defined pattern to the cygpath arguments 129 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 130 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 131 | fi 132 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 133 | i=0 134 | for arg in "$@" ; do 135 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 136 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 137 | 138 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 139 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 140 | else 141 | eval `echo args$i`="\"$arg\"" 142 | fi 143 | i=`expr $i + 1` 144 | done 145 | case $i in 146 | 0) set -- ;; 147 | 1) set -- "$args0" ;; 148 | 2) set -- "$args0" "$args1" ;; 149 | 3) set -- "$args0" "$args1" "$args2" ;; 150 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 151 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 152 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 153 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 154 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 155 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 156 | esac 157 | fi 158 | 159 | # Escape application args 160 | save () { 161 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 162 | echo " " 163 | } 164 | APP_ARGS=`save "$@"` 165 | 166 | # Collect all arguments for the java command, following the shell quoting and substitution rules 167 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 168 | 169 | exec "$JAVACMD" "$@" 170 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 17 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 18 | 19 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 20 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 21 | 22 | @rem Find java.exe 23 | if defined JAVA_HOME goto findJavaFromJavaHome 24 | 25 | set JAVA_EXE=java.exe 26 | %JAVA_EXE% -version >NUL 2>&1 27 | if "%ERRORLEVEL%" == "0" goto init 28 | 29 | echo. 30 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 31 | echo. 32 | echo Please set the JAVA_HOME variable in your environment to match the 33 | echo location of your Java installation. 34 | 35 | goto fail 36 | 37 | :findJavaFromJavaHome 38 | set JAVA_HOME=%JAVA_HOME:"=% 39 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 40 | 41 | if exist "%JAVA_EXE%" goto init 42 | 43 | echo. 44 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 45 | echo. 46 | echo Please set the JAVA_HOME variable in your environment to match the 47 | echo location of your Java installation. 48 | 49 | goto fail 50 | 51 | :init 52 | @rem Get command-line arguments, handling Windows variants 53 | 54 | if not "%OS%" == "Windows_NT" goto win9xME_args 55 | 56 | :win9xME_args 57 | @rem Slurp the command line arguments. 58 | set CMD_LINE_ARGS= 59 | set _SKIP=2 60 | 61 | :win9xME_args_slurp 62 | if "x%~1" == "x" goto execute 63 | 64 | set CMD_LINE_ARGS=%* 65 | 66 | :execute 67 | @rem Setup the command line 68 | 69 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 70 | 71 | 72 | @rem Execute Gradle 73 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 74 | 75 | :end 76 | @rem End local scope for the variables with windows NT shell 77 | if "%ERRORLEVEL%"=="0" goto mainEnd 78 | 79 | :fail 80 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 81 | rem the _cmd.exe /c_ return code! 82 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 83 | exit /b 1 84 | 85 | :mainEnd 86 | if "%OS%"=="Windows_NT" endlocal 87 | 88 | :omega 89 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'angular-cli-quick-switch-plugin' 11 | -------------------------------------------------------------------------------- /src/main/java/QuickSwitchAction.java: -------------------------------------------------------------------------------- 1 | import com.intellij.openapi.actionSystem.AnAction; 2 | import com.intellij.openapi.actionSystem.AnActionEvent; 3 | import com.intellij.openapi.fileEditor.FileEditorManager; 4 | import com.intellij.openapi.fileEditor.OpenFileDescriptor; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.vfs.LocalFileSystem; 7 | import com.intellij.openapi.vfs.VirtualFile; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | public class QuickSwitchAction extends AnAction { 13 | 14 | private AnActionEvent latestEvent; 15 | 16 | private List extensions = Arrays.asList( 17 | "ts", "js", 18 | "html", "php", "haml", "jade", "pug", "slim", 19 | "css", "sass", "scss", "less", "styl" 20 | ); 21 | 22 | public QuickSwitchAction() { 23 | super("QuickSwitch"); 24 | } 25 | 26 | @Override 27 | public void actionPerformed(AnActionEvent event) { 28 | this.latestEvent = event; 29 | 30 | VirtualFile currentFile = (VirtualFile) event.getDataContext().getData("virtualFile"); 31 | if (currentFile == null) return; 32 | 33 | String currentFilePath = currentFile.getCanonicalPath(); 34 | if (currentFilePath == null) return; 35 | 36 | String basePath = this.removeFilePathExtension(currentFilePath); 37 | String extension = this.getFilePathExtension(currentFilePath); 38 | if (basePath == null || extension == null) return; 39 | 40 | String newPath = this.cycleExtension(basePath, extension); 41 | this.switchFile(currentFilePath, newPath); 42 | } 43 | 44 | private String getFilePathExtension(String filePath) { 45 | int extensionPosition = filePath.lastIndexOf("."); 46 | if (extensionPosition == -1) return null; 47 | return filePath.substring(extensionPosition + 1); 48 | } 49 | 50 | private String removeFilePathExtension(String filePath) { 51 | int extensionPosition = filePath.lastIndexOf("."); 52 | if (extensionPosition == -1) return filePath; 53 | return filePath.substring(0, extensionPosition); 54 | } 55 | 56 | private String cycleExtension(String basePath, String currentExtension) { 57 | String currentPath = basePath + "." + currentExtension; 58 | int currentIndex = this.extensions.indexOf(currentExtension); 59 | if (currentIndex == -1) return currentPath; 60 | for (int i = 0; i < this.extensions.size(); i++) { 61 | int newIndex = ((currentIndex + 1 + i) % this.extensions.size()); 62 | String newExtension = this.extensions.get(newIndex); 63 | String newPath = basePath + "." + newExtension; 64 | VirtualFile newFile = this.getFileByPath(newPath); 65 | if (newFile != null && newFile.exists()) return newPath; 66 | } 67 | return currentPath; 68 | } 69 | 70 | private void switchFile(String currentFilePath, String newFilePath) { 71 | Project project = this.latestEvent.getProject(); 72 | if (project == null) return; 73 | VirtualFile currentFile = this.getFileByPath(currentFilePath); 74 | VirtualFile newFile = this.getFileByPath(newFilePath); 75 | if (!currentFile.exists() || !newFile.exists()) return; 76 | FileEditorManager.getInstance(project).closeFile(currentFile); 77 | new OpenFileDescriptor(project, newFile).navigate(true); 78 | } 79 | 80 | private VirtualFile getFileByPath(String path) { 81 | return LocalFileSystem.getInstance().findFileByPath(path); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | patrick.kelleter.angular-cli-quick-switch 3 | Angular CLI QuickSwitch 4 | Patrick Kelleter 5 | 6 | 9 | 10 | - Updated docs
12 | ]]> 13 |
14 | 15 | 16 | 17 | com.intellij.modules.lang 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 |
--------------------------------------------------------------------------------