diff --git a/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/ArtifactRepositoryManager.java b/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/ArtifactRepositoryManager.java index a6252cf8cc90..629538627bb5 100644 --- a/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/ArtifactRepositoryManager.java +++ b/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/ArtifactRepositoryManager.java @@ -115,11 +115,11 @@ public class ArtifactRepositoryManager { // setup session here session.setLocalRepositoryManager(ourSystem.newLocalRepositoryManager(session, new LocalRepository(localRepositoryPath))); + session.setProxySelector(new org.jetbrains.idea.maven.aether.JreProxySelector()); session.setReadOnly(); mySession = session; } - public void addRemoteRepository(final String id, final String url) { myRemoteRepositories.add(createRemoteRepository(id, url)); } diff --git a/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/JreProxySelector.java b/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/JreProxySelector.java new file mode 100644 index 000000000000..fd6e107ba296 --- /dev/null +++ b/aether-dependency-resolver/src/org/jetbrains/idea/maven/aether/JreProxySelector.java @@ -0,0 +1,127 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.idea.maven.aether; + +import org.eclipse.aether.repository.*; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; + +import java.net.*; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * This is a modified copy of the corresponding Aether class that adds support for https proxy types + */ +final class JreProxySelector implements ProxySelector { + + JreProxySelector() { + } + + public Proxy getProxy(RemoteRepository repository) { + try { + final java.net.ProxySelector systemSelector = java.net.ProxySelector.getDefault(); + if (systemSelector == null) { + return null; + } + final URI uri = new URI(repository.getUrl()).parseServerAuthority(); + final List selected = systemSelector.select(uri); + if (selected == null || selected.isEmpty()) { + return null; + } + for (java.net.Proxy proxy : selected) { + if (proxy.type() == java.net.Proxy.Type.HTTP && isValid(proxy.address())) { + final String proxyType = chooseProxyType(uri.getScheme()); + if (proxyType != null) { + final InetSocketAddress addr = (InetSocketAddress)proxy.address(); + return new Proxy(proxyType, addr.getHostName(), addr.getPort(), JreProxyAuthentication.INSTANCE); + } + } + } + } + catch (Throwable e) { + // URL invalid or not accepted by selector or no selector at all, simply use no proxy + } + return null; + } + + private static String chooseProxyType(final String protocol) { + if (Proxy.TYPE_HTTP.equals(protocol)) { + return Proxy.TYPE_HTTP; + } + if (Proxy.TYPE_HTTPS.equals(protocol)) { + return Proxy.TYPE_HTTPS; + } + return null; + } + + private static boolean isValid(SocketAddress address) { + if (address instanceof InetSocketAddress) { + /* + * NOTE: On some platforms with java.net.useSystemProxies=true, unconfigured proxies show up as proxy + * objects with empty host and port 0. + */ + final InetSocketAddress addr = (InetSocketAddress)address; + return addr.getPort() > 0 && addr.getHostName() != null && !addr.getHostName().isEmpty(); + } + return false; + } + + private static final class JreProxyAuthentication implements Authentication { + + public static final Authentication INSTANCE = new JreProxyAuthentication(); + + public void fill(AuthenticationContext context, String key, Map data) { + Proxy proxy = context.getProxy(); + if (proxy == null) { + return; + } + if (!AuthenticationContext.USERNAME.equals(key) && !AuthenticationContext.PASSWORD.equals(key)) { + return; + } + + try { + URL url; + String protocol = "http"; + try { + url = new URL(context.getRepository().getUrl()); + protocol = url.getProtocol(); + } + catch (Exception e) { + url = null; + } + + PasswordAuthentication auth = Authenticator.requestPasswordAuthentication( + proxy.getHost(), null, proxy.getPort(), protocol, "Credentials for proxy " + proxy, null, url, Authenticator.RequestorType.PROXY + ); + if (auth != null) { + context.put(AuthenticationContext.USERNAME, auth.getUserName()); + context.put(AuthenticationContext.PASSWORD, auth.getPassword()); + } + else { + context.put(AuthenticationContext.USERNAME, System.getProperty(protocol + ".proxyUser")); + context.put(AuthenticationContext.PASSWORD, System.getProperty(protocol + ".proxyPassword")); + } + } + catch (SecurityException e) { + // oh well, let's hope the proxy can do without auth + } + } + + public void digest(AuthenticationDigest digest) { + // we don't know anything about the JRE's current authenticator, assume the worst (i.e. interactive) + digest.update(UUID.randomUUID().toString()); + } + + @Override + public boolean equals(Object obj) { + return this == obj || (obj != null && getClass().equals(obj.getClass())); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + } +} + diff --git a/build/conf/nsis/customInstallActions.nsi b/build/conf/nsis/customInstallActions.nsi index 56277ba6e209..213a2c824d45 100644 --- a/build/conf/nsis/customInstallActions.nsi +++ b/build/conf/nsis/customInstallActions.nsi @@ -1,9 +1,14 @@ !define INSTALL_OPTION_ELEMENTS 5 +!define CUSTOM_SILENT_CONFIG 0 Function customPreInstallActions DetailPrint "There are no custom pre-install actions." FunctionEnd +Function customSilentConfigReader + DetailPrint "There are no custom silent install actions." +FunctionEnd + Function customInstallActions DetailPrint "There are no custom install actions." FunctionEnd diff --git a/build/conf/nsis/idea.nsi b/build/conf/nsis/idea.nsi index 082c0ad63ed7..819be149fb22 100644 --- a/build/conf/nsis/idea.nsi +++ b/build/conf/nsis/idea.nsi @@ -25,11 +25,26 @@ SetCompressor lzma ; http://nsis.sourceforge.net/Shortcuts_removal_fails_on_Windows_Vista RequestExecutionLevel user +;------------------------------------------------------------------------------ +; Variables +;------------------------------------------------------------------------------ +Var STARTMENU_FOLDER +Var config_path +Var system_path +Var productLauncher +Var baseRegKey +Var downloadJreX86 +Var productDir +Var control_fields +Var max_fields +Var silentMode + ;------------------------------------------------------------------------------ ; include "Modern User Interface" ;------------------------------------------------------------------------------ !include "MUI2.nsh" !include "FileFunc.nsh" +!include "TextFunc.nsh" !include UAC.nsh !include "InstallOptions.nsh" !include StrFunc.nsh @@ -53,19 +68,6 @@ ReserveFile "DeleteSettings.ini" !define MUI_HEADERIMAGE_BITMAP "${IMAGES_LOCATION}\${PRODUCT_HEADER_FILE}" !define MUI_WELCOMEFINISHPAGE_BITMAP "${IMAGES_LOCATION}\${PRODUCT_LOGO_FILE}" -;------------------------------------------------------------------------------ -; Variables -;------------------------------------------------------------------------------ - Var STARTMENU_FOLDER - Var config_path - Var system_path - Var productLauncher - Var baseRegKey - Var downloadJreX86 - Var productDir - Var control_fields - Var max_fields - ;------------------------------------------------------------------------------ ; on GUI initialization installer checks whether IDEA is already installed ;------------------------------------------------------------------------------ @@ -117,92 +119,95 @@ ReserveFile "DeleteSettings.ini" complete: FunctionEnd + Function ${un}SplitStr -Exch $0 ; str -Push $1 ; inQ -Push $3 ; idx -Push $4 ; tmp -StrCpy $1 0 -StrCpy $3 0 + Exch $0 ; str + Push $1 ; inQ + Push $3 ; idx + Push $4 ; tmp + StrCpy $1 0 + StrCpy $3 0 loop: - StrCpy $4 $0 1 $3 - ${If} $4 == '"' - ${If} $1 <> 0 - StrCpy $0 $0 "" 1 - IntOp $3 $3 - 1 - ${EndIf} - IntOp $1 $1 ! + StrCpy $4 $0 1 $3 + ${If} $4 == '"' + ${If} $1 <> 0 + StrCpy $0 $0 "" 1 + IntOp $3 $3 - 1 ${EndIf} - ${If} $4 == '' ; The end? - StrCpy $1 0 - StrCpy $4 ',' - ${EndIf} - ${If} $4 == ',' + IntOp $1 $1 ! + ${EndIf} + ${If} $4 == '' ; The end? + StrCpy $1 0 + StrCpy $4 ',' + ${EndIf} + ${If} $4 == ',' ${AndIf} $1 = 0 - StrCpy $4 $0 $3 - StrCpy $1 $4 "" -1 - ${IfThen} $1 == '"' ${|} StrCpy $4 $4 -1 ${|} - killspace: - IntOp $3 $3 + 1 - StrCpy $0 $0 "" $3 - StrCpy $1 $0 1 - StrCpy $3 0 - StrCmp $1 ',' killspace - Push $0 ; Remaining - Exch 4 - Pop $0 - StrCmp $4 "" 0 moreleft - Pop $4 - Pop $3 - Pop $1 - Return - moreleft: - Exch $4 - Exch 2 - Pop $1 + StrCpy $4 $0 $3 + StrCpy $1 $4 "" -1 + ${IfThen} $1 == '"' ${|} StrCpy $4 $4 -1 ${|} + killspace: + IntOp $3 $3 + 1 + StrCpy $0 $0 "" $3 + StrCpy $1 $0 1 + StrCpy $3 0 + StrCmp $1 ',' killspace + Push $0 ; Remaining + Exch 4 + Pop $0 + StrCmp $4 "" 0 moreleft + Pop $4 Pop $3 + Pop $1 Return - ${EndIf} - IntOp $3 $3 + 1 - Goto loop + moreleft: + Exch $4 + Exch 2 + Pop $1 + Pop $3 + Return + ${EndIf} + IntOp $3 $3 + 1 + Goto loop FunctionEnd + !macroend !insertmacro INST_UNINST_SWITCH "" !insertmacro INST_UNINST_SWITCH "un." + Function InstDirState - !define InstDirState `!insertmacro InstDirStateCall` + !define InstDirState `!insertmacro InstDirStateCall` - !macro InstDirStateCall _PATH _RESULT - Push `${_PATH}` - Call InstDirState - Pop ${_RESULT} - !macroend + !macro InstDirStateCall _PATH _RESULT + Push `${_PATH}` + Call InstDirState + Pop ${_RESULT} + !macroend - Exch $0 - Push $1 - ClearErrors + Exch $0 + Push $1 + ClearErrors - FindFirst $1 $0 '$0\*.*' - IfErrors 0 +3 - StrCpy $0 -1 - goto end - StrCmp $0 '.' 0 +4 - FindNext $1 $0 - StrCmp $0 '..' 0 +2 - FindNext $1 $0 - FindClose $1 - IfErrors 0 +3 - StrCpy $0 0 - goto end - StrCpy $0 1 - - end: - Pop $1 - Exch $0 + FindFirst $1 $0 '$0\*.*' + IfErrors 0 +3 + StrCpy $0 -1 + goto end + StrCmp $0 '.' 0 +4 + FindNext $1 $0 + StrCmp $0 '..' 0 +2 + FindNext $1 $0 + FindClose $1 + IfErrors 0 +3 + StrCpy $0 0 + goto end + StrCpy $0 1 +end: + Pop $1 + Exch $0 FunctionEnd + Function SplitFirstStrPart Exch $R0 Exch @@ -212,24 +217,24 @@ Function SplitFirstStrPart StrCpy $R3 $R1 StrLen $R1 $R0 IntOp $R1 $R1 + 1 - loop: - IntOp $R1 $R1 - 1 - StrCpy $R2 $R0 1 -$R1 - StrCmp $R1 0 exit0 - StrCmp $R2 $R3 exit1 loop - exit0: +loop: + IntOp $R1 $R1 - 1 + StrCpy $R2 $R0 1 -$R1 + StrCmp $R1 0 exit0 + StrCmp $R2 $R3 exit1 loop +exit0: StrCpy $R1 "" Goto exit2 - exit1: - IntOp $R1 $R1 - 1 - StrCmp $R1 0 0 +3 +exit1: + IntOp $R1 $R1 - 1 + StrCmp $R1 0 0 +3 StrCpy $R2 "" Goto +2 - StrCpy $R2 $R0 "" -$R1 - IntOp $R1 $R1 + 1 - StrCpy $R0 $R0 -$R1 - StrCpy $R1 $R2 - exit2: + StrCpy $R2 $R0 "" -$R1 + IntOp $R1 $R1 + 1 + StrCpy $R0 $R0 -$R1 + StrCpy $R1 $R2 +exit2: Pop $R3 Pop $R2 Exch $R1 ;rest @@ -237,29 +242,31 @@ Function SplitFirstStrPart Exch $R0 ;first FunctionEnd + Function VersionSplit - !define VersionSplit `!insertmacro VersionSplitCall` + !define VersionSplit `!insertmacro VersionSplitCall` - !macro VersionSplitCall _FULL _PRODUCT _BRANCH _BUILD - Push `${_FULL}` - Call VersionSplit - Pop ${_PRODUCT} - Pop ${_BRANCH} - Pop ${_BUILD} - !macroend + !macro VersionSplitCall _FULL _PRODUCT _BRANCH _BUILD + Push `${_FULL}` + Call VersionSplit + Pop ${_PRODUCT} + Pop ${_BRANCH} + Pop ${_BUILD} + !macroend - Pop $R0 - Push "-" - Push $R0 - Call SplitFirstStrPart - Pop $R0 - Pop $R1 - Push "." - Push $R1 - Call SplitFirstStrPart - Push $R0 + Pop $R0 + Push "-" + Push $R0 + Call SplitFirstStrPart + Pop $R0 + Pop $R1 + Push "." + Push $R1 + Call SplitFirstStrPart + Push $R0 FunctionEnd + Function OnDirectoryPageLeave ;check ; - if there are no files into $INSTDIR (recursively) @@ -281,18 +288,18 @@ Function instDirEmpty ClearErrors FindFirst $1 $2 "$9\*.*" IfErrors done 0 -nextElemement: +next_elemement: ;is the element a folder? - StrCmp $2 "." getNextElement - StrCmp $2 ".." getNextElement - IfFileExists "$9\$2\*.*" 0 nextFile + StrCmp $2 "." get_next_element + StrCmp $2 ".." get_next_element + IfFileExists "$9\$2\*.*" 0 next_file Push $9 StrCpy "$9" "$9\$2" Call instDirEmpty StrCmp $9 "not empty" done 0 Pop $9 - Goto getNextElement -nextFile: + Goto get_next_element +next_file: ;is it the file property? ${If} $2 != "idea.properties" ${AndIf} $2 != "${PRODUCT_EXE_FILE}.vmoptions" @@ -301,9 +308,9 @@ nextFile: StrCpy $9 "not empty" Goto done ${EndIf} -getNextElement: +get_next_element: FindNext $1 $2 - IfErrors 0 nextElemement + IfErrors 0 next_elemement done: FindClose $1 Pop $2 @@ -311,19 +318,6 @@ done: Pop $0 FunctionEnd -Function searchJava64 - StrCpy $0 "HKLM" - StrCpy $1 "Software\JavaSoft\Java Development Kit\${JAVA_REQUIREMENT}" - StrCpy $2 "JavaHome" - SetRegView 64 - call OMReadRegStr - SetRegView 32 - StrCpy $3 "$3\bin\java.exe" - IfFileExists $3 done no_java_64 -no_java_64: - StrCpy $3 "" -done: -FunctionEnd Function ConfirmDesktopShortcut !insertmacro MUI_HEADER_TEXT "$(installation_options)" "$(installation_options_prompt)" @@ -344,7 +338,7 @@ Function ConfirmDesktopShortcut ${EndIf} ; if jre x86 for the build is available then add checkbox to Installation Options dialog - StrCmp "${LINK_TO_JRE}" "null" customPreActions 0 + StrCmp "${LINK_TO_JRE}" "null" custom_pre_actions 0 inetc::head /SILENT /TOSTACK ${LINK_TO_JRE} "" /END Pop $0 ${If} $0 == "OK" @@ -358,7 +352,7 @@ Function ConfirmDesktopShortcut !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "State" $downloadJreX86 !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "Text" "Download and install JRE x86 by JetBrains" ${EndIf} -customPreActions: +custom_pre_actions: Call customPreInstallActions SetRegView 32 StrCmp "${ASSOCIATION}" "NoAssociation" skip_association @@ -378,6 +372,7 @@ done: !insertmacro INSTALLOPTIONS_DISPLAY "Desktop.ini" FunctionEnd + Function downloadJre !insertmacro INSTALLOPTIONS_READ $R0 "Desktop.ini" "Field 4" "State" ${If} $R0 == 1 @@ -385,10 +380,10 @@ Function downloadJre Pop $0 ${If} $0 == "OK" untgz::extract "-d" "$INSTDIR\jre32" "$TEMP\jre.tar.gz" - StrCmp $R0 "success" removeTempJre + StrCmp $R0 "success" remove_temp_jre DetailPrint "Failed to extract jre.tar.gz" MessageBox MB_OK|MB_ICONEXCLAMATION|MB_DEFBUTTON1 "Failed to extract $TEMP\jre.tar.gz" -removeTempJre: +remove_temp_jre: IfFileExists "$TEMP\jre.tar.gz" 0 done Delete "$TEMP\jre.tar.gz" ${Else} @@ -398,13 +393,11 @@ removeTempJre: done: FunctionEnd - ;------------------------------------------------------------------------------ ; configuration ;------------------------------------------------------------------------------ !insertmacro MUI_PAGE_WELCOME - Page custom uninstallOldVersionDialog !ifdef LICENSE_FILE @@ -458,51 +451,112 @@ LicenseLangString myLicenseData ${LANG_ENGLISH} "${LICENSE_FILE}.txt" LicenseLangString myLicenseData ${LANG_JAPANESE} "${LICENSE_FILE}.txt" !endif + Function .onInit SetRegView 32 + !insertmacro INSTALLOPTIONS_EXTRACT "Desktop.ini" + IfSilent silent_mode uac_elevate +silent_mode: + IntCmp ${CUSTOM_SILENT_CONFIG} 0 silent_config silent_config custom_silent_config +silent_config: + Call silentConfigReader + Goto set_reg_key +custom_silent_config: + Call customSilentConfigReader +set_reg_key: StrCpy $baseRegKey "HKCU" - IfSilent UAC_Done -UAC_Elevate: - !insertmacro UAC_RunElevated - StrCmp 1223 $0 UAC_ElevationAborted ; UAC dialog aborted by user? - continue install under user - StrCmp 0 $0 0 UAC_Err ; Error? - StrCmp 1 $1 0 UAC_Success ;Are we the real deal or just the wrapper? - Quit -UAC_Err: - Abort -UAC_ElevationAborted: - StrCpy $INSTDIR "$APPDATA\${MANUFACTURER}\${PRODUCT_WITH_VER}" - goto UAC_Done -UAC_Success: - StrCmp 1 $3 UAC_Admin ;Admin? - StrCmp 3 $1 0 UAC_ElevationAborted ;Try again? - goto UAC_Elevate -UAC_Admin: - ${If} ${RunningX64} - StrCpy $INSTDIR "$PROGRAMFILES64\${MANUFACTURER}\${PRODUCT_WITH_VER}" - ${Else} - StrCpy $INSTDIR "$PROGRAMFILES\${MANUFACTURER}\${PRODUCT_WITH_VER}" - ${EndIf} - SetShellVarContext all - StrCpy $baseRegKey "HKLM" -UAC_Done: + StrCmp $silentMode "admin" uac_elevate done +uac_elevate: + !insertmacro UAC_RunElevated + StrCmp 1223 $0 uac_elevation_aborted ; UAC dialog aborted by user? - continue install under user + StrCmp 0 $0 0 uac_err ; Error? + StrCmp 1 $1 0 uac_success ;Are we the real deal or just the wrapper? + Quit +uac_err: + Abort +uac_elevation_aborted: + IfSilent done set_install_dir +set_install_dir: + StrCpy $INSTDIR "$APPDATA\${MANUFACTURER}\${PRODUCT_WITH_VER}" + goto done +uac_success: + StrCmp 1 $3 uac_admin ;Admin? + StrCmp 3 $1 0 uac_elevation_aborted ;Try again? + goto uac_elevate +uac_admin: + IfSilent uac_all_users set_install_dir_admin_mode +set_install_dir_admin_mode: + ${If} ${RunningX64} + StrCpy $INSTDIR "$PROGRAMFILES64\${MANUFACTURER}\${PRODUCT_WITH_VER}" + ${Else} + StrCpy $INSTDIR "$PROGRAMFILES\${MANUFACTURER}\${PRODUCT_WITH_VER}" + ${EndIf} +uac_all_users: + SetShellVarContext all + StrCpy $baseRegKey "HKLM" +done: ; !insertmacro MUI_LANGDLL_DISPLAY FunctionEnd + +Function silentConfigReader + ${GetParameters} $R0 + ClearErrors + + ${GetOptions} $R0 /CONFIG= $R1 + IfErrors no_silent_config + + ${ConfigRead} "$R1" "mode=" $R0 + StrCpy $silentMode "user" + IfErrors launcher_32 + StrCpy $silentMode $R0 + +launcher_32: + ClearErrors + ${ConfigRead} "$R1" "launcher32=" $R3 + IfErrors launcher_64 + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 2" "State" $R3 + +launcher_64: + ClearErrors + ${ConfigRead} "$R1" "launcher64=" $R3 + IfErrors download_jre32 + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 3" "Type" "checkbox" + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 3" "State" $R3 + +download_jre32: + ClearErrors + ${ConfigRead} "$R1" "jre32=" $R3 + IfErrors associations + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "Type" "checkbox" + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "State" $R3 + +associations: + ClearErrors + StrCmp "${ASSOCIATION}" "NoAssociation" done + !insertmacro INSTALLOPTIONS_READ $R0 "Desktop.ini" "Settings" "NumFields" + push "${ASSOCIATION}" +loop: + call SplitStr + Pop $0 + StrCmp $0 "" update_settings + ClearErrors + ${ConfigRead} "$R1" "$0=" $R3 + IfErrors update_settings + IntOp $R0 $R0 + 1 + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field $R0" "State" $R3 + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field $R0" "Text" "$0" + goto loop + +update_settings: + !insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Settings" "NumFields" "$R0" +no_silent_config: +done: +FunctionEnd + Function checkVersion StrCpy $2 "" StrCpy $1 "Software\${MANUFACTURER}\${PRODUCT_REG_VER}" -; ${If} $0 == "HKLM" -; StrCpy $1 "Software\${MANUFACTURER}\${PRODUCT_REG_VER}" -; Push $0 -; call winVersion -; ${If} $0 == "1" -; StrCpy $1 "Software\Wow6432Node\${MANUFACTURER}\${PRODUCT_REG_VER}" -; ${Else} -; StrCpy $1 "Software\${MANUFACTURER}\${PRODUCT_REG_VER}" -; ${EndIf} -; Pop $0 -; ${EndIf} Call OMReadRegStr IfFileExists $3\bin\${PRODUCT_EXE_FILE} check_version Goto Done @@ -533,7 +587,7 @@ FunctionEnd Function uninstallOldVersion - ; uninstallation mode + ;uninstallation mode !insertmacro INSTALLOPTIONS_READ $9 "UninstallOldVersions.ini" "Field 2" "State" ${If} $9 == "1" ExecWait '"$3\bin\Uninstall.exe" /S' @@ -544,7 +598,7 @@ Function uninstallOldVersion goto complete uninstall: ;previous installation has been removed - ;customer decided to keep properties? + ;customer has decided to keep properties? IfFileExists $3\bin\idea.properties saveProperties fullRemove saveProperties: Delete "$3\bin\Uninstall.exe" @@ -563,12 +617,12 @@ StrCpy $6 "" loop: IntOp $7 $7 + 1 ${If} $8 >= $7 - !insertmacro INSTALLOPTIONS_READ $6 "UninstallOldVersions.ini" "Field $7" "Text" - ${If} $6 == $3 - ;found the same value in list of installations - StrCpy $6 "duplicated" - Goto finish - ${EndIf} + !insertmacro INSTALLOPTIONS_READ $6 "UninstallOldVersions.ini" "Field $7" "Text" + ${If} $6 == $3 + ;found the same value in list of installations + StrCpy $6 "duplicated" + Goto finish + ${EndIf} Goto loop ${EndIf} finish: @@ -609,6 +663,7 @@ ${If} $0 == "HKLM" StrCpy $4 0 Goto get_installation_info ${EndIf} + complete: !insertmacro INSTALLOPTIONS_WRITE "UninstallOldVersions.ini" "Settings" "NumFields" "$8" ${If} $8 > $control_fields @@ -710,7 +765,6 @@ continue_enum_versions_hkcu: Goto enum_versions_hkcu end_enum_versions_hkcu: - StrCpy $0 "0" # registry key index enum_versions_hklm: @@ -725,15 +779,14 @@ continue_enum_versions_hklm: Goto enum_versions_hklm end_enum_versions_hklm: - StrCmp $INSTDIR "" 0 skip_default_instdir ${If} ${RunningX64} StrCpy $INSTDIR "$PROGRAMFILES64\${MANUFACTURER}\${MUI_PRODUCT} ${MUI_VERSION_MAJOR}.${MUI_VERSION_MINOR}" ${Else} StrCpy $INSTDIR "$PROGRAMFILES\${MANUFACTURER}\${MUI_PRODUCT} ${MUI_VERSION_MAJOR}.${MUI_VERSION_MINOR}" ${EndIf} -skip_default_instdir: +skip_default_instdir: Pop $5 Pop $4 Pop $3 @@ -763,22 +816,60 @@ createRegistration: FunctionEnd Function ProductAssociation + push $0 + push $1 + push $2 + push $3 + StrCpy $2 "" + StrCmp $baseRegKey "HKLM" admin user +admin: + StrCpy $0 HKCR + StrCpy $R5 ${PRODUCT_PATHS_SELECTOR} + goto back_up +user: + StrCpy $0 HKCU + StrCpy $R4 "Software\Classes\$R4" + StrCpy $R5 "Software\Classes\${PRODUCT_PATHS_SELECTOR}" +back_up: ; back up old value of an association - ReadRegStr $1 HKCR $R4 "" - StrCmp $1 "" skip_backup - StrCmp $1 ${PRODUCT_PATHS_SELECTOR} skip_backup - WriteRegStr HKCR $R4 "backup_val" $1 + StrCpy $1 $R4 +call OMReadRegStr + StrCmp $3 "" skip_backup + StrCmp $3 ${PRODUCT_PATHS_SELECTOR} skip_backup + StrCpy $2 "backup_val" + Call OMWriteRegStr skip_backup: - WriteRegStr HKCR $R4 "" "${PRODUCT_PATHS_SELECTOR}" - ReadRegStr $0 HKCR ${PRODUCT_PATHS_SELECTOR} "" - StrCmp $0 "" 0 command_exists - WriteRegStr HKCR ${PRODUCT_PATHS_SELECTOR} "" "${PRODUCT_FULL_NAME}" - WriteRegStr HKCR "${PRODUCT_PATHS_SELECTOR}\shell" "" "open" - WriteRegStr HKCR "${PRODUCT_PATHS_SELECTOR}\DefaultIcon" "" "$productLauncher,0" + StrCpy $2 "" + StrCpy $3 ${PRODUCT_PATHS_SELECTOR} + Call OMWriteRegStr + StrCpy $1 ${PRODUCT_PATHS_SELECTOR} + StrCpy $2 "" + Call OMReadRegStr + StrCmp $3 "" 0 command_exists + StrCpy $2 "" + StrCpy $3 "${PRODUCT_FULL_NAME}" + Call OMWriteRegStr + StrCpy $1 "$R5\shell" + StrCpy $2 "" + StrCpy $3 "open" + Call OMWriteRegStr + StrCpy $1 "$R5\DefaultIcon" + StrCpy $2 "" + StrCpy $3 "$productLauncher,0" + Call OMWriteRegStr command_exists: - WriteRegStr HKCR "${PRODUCT_PATHS_SELECTOR}\DefaultIcon" "" " $productLauncher,0" - WriteRegStr HKCR "${PRODUCT_PATHS_SELECTOR}\shell\open\command" "" \ - '"$productLauncher" "%1"' + StrCpy $1 "$R5\DefaultIcon" + StrCpy $2 "" + StrCpy $3 " $productLauncher,0" + Call OMWriteRegStr + StrCpy $1 "$R5\shell\open\command" + StrCpy $2 "" + StrCpy $3 '"$productLauncher" "%1"' + Call OMWriteRegStr + pop $3 + pop $2 + pop $1 + pop $0 FunctionEnd ;------------------------------------------------------------------------------ @@ -786,20 +877,22 @@ FunctionEnd ;------------------------------------------------------------------------------ Section "IDEA Files" CopyIdeaFiles CreateDirectory $INSTDIR + Call customInstallActions + SetRegView 32 -; set up a launcher for associations + ;define launcher in accordingly to OS version ${If} ${RunningX64} StrCpy $productLauncher "$INSTDIR\bin\${PRODUCT_EXE_FILE_64}" ${Else} StrCpy $productLauncher "$INSTDIR\bin\${PRODUCT_EXE_FILE}" ${EndIf} + DetailPrint "productLauncher: $productLauncher" StrCmp "${LINK_TO_JRE}" "null" shortcuts 0 -; download and install JRE x86 + ;download and install JRE x86 Call downloadJre shortcuts: -; create shortcuts !insertmacro INSTALLOPTIONS_READ $R2 "Desktop.ini" "Field 2" "State" StrCmp $R2 1 "" exe_64 CreateShortCut "$DESKTOP\${PRODUCT_FULL_NAME_WITH_VER}.lnk" \ @@ -823,11 +916,7 @@ get_user_choice: next_association: IntOp $R2 $R2 + 1 IntCmp $R1 $R2 get_user_choice done get_user_choice - done: - Call customInstallActions - SetRegView 32 - ; registration application to be presented in Open With list call ProductRegistration !insertmacro MUI_STARTMENU_WRITE_BEGIN Application @@ -867,10 +956,9 @@ done: !undef Index skip_ipr: - ; readonly section SectionIn RO -!include "idea_win.nsh" + !include "idea_win.nsh" SetOutPath $INSTDIR\bin File "${PRODUCT_PROPERTIES_FILE}" @@ -1012,16 +1100,44 @@ UAC_Done: FunctionEnd -Function un.ReturnBackupRegValue +Function un.RestoreBackupRegValue ;replace Default str with the backup value (if there is the one) and then delete backup ; $1 - key (for example ".java") ; $2 - name (for example "backup_val") Push $0 - ReadRegStr $0 HKCR $1 $2 - StrCmp $0 "" "noBackup" - WriteRegStr HKCR $1 "" $0 - DeleteRegValue HKCR $1 $2 -noBackup: + Push $3 + + StrCmp $baseRegKey "HKLM" admin user +admin: + StrCpy $0 HKCR + goto read_backup_value +user: + StrCpy $0 HKCU + StrCpy $1 "Software\Classes\$1" + +read_backup_value: + call un.OMReadRegStr + StrCmp $3 "" no_backup restore_backup + +no_backup: + ;clean default value if it contains current product info + StrCpy $2 "" + call un.OMReadRegStr + StrCmp $4 $3 0 done + call un.OMDeleteRegValue + goto done + +restore_backup: + StrCmp $3 $4 remove_backup 0 + push $2 + StrCpy $2 "" + call un.OMWriteRegStr + pop $2 +remove_backup: + call un.OMDeleteRegValue + +done: + Pop $3 Pop $0 FunctionEnd @@ -1225,7 +1341,7 @@ skip_delete_settings: StrCmp $R9 "" registry StrCpy $5 "Software\${MANUFACTURER}" shortcuts: - ;the user has the admin rights + ;user has the admin rights IfFileExists "$DESKTOP\${PRODUCT_FULL_NAME_WITH_VER}.lnk" keep_current_user SetShellVarContext all keep_current_user: @@ -1244,13 +1360,17 @@ registry: StrCmp "${ASSOCIATION}" "NoAssociation" finish_uninstall push "${ASSOCIATION}" loop: + StrCpy $2 "backup_val" + StrCpy $4 "${PRODUCT_PATHS_SELECTOR}" call un.SplitStr Pop $0 StrCmp $0 "" finish_uninstall + + ;restore backup association(s) StrCpy $1 $0 - StrCpy $2 "backup_val" - Call un.ReturnBackupRegValue + Call un.RestoreBackupRegValue goto loop + finish_uninstall: StrCpy $0 $baseRegKey StrCpy $1 "$5\${PRODUCT_REG_VER}" @@ -1275,8 +1395,16 @@ finish: StrCpy $0 "HKCR" StrCpy $1 "Applications\${PRODUCT_EXE_FILE}" Call un.OMDeleteRegKey + StrCmp $baseRegKey "HKLM" admin user +admin: StrCpy $0 "HKCR" StrCpy $1 "${PRODUCT_PATHS_SELECTOR}" + goto delete_association +user: + StrCpy $0 "HKCU" + StrCpy $1 "Software\Classes\${PRODUCT_PATHS_SELECTOR}" +delete_association: + ; remove product information which was used for association(s) Call un.OMDeleteRegKey StrCpy $0 "${MUI_LANGDLL_REGISTRY_ROOT}" @@ -1287,6 +1415,7 @@ finish: StrCpy $1 "IntelliJIdeaProjectFile\DefaultIcon" StrCpy $2 "" call un.OMReadRegStr + StrCmp $3 "$productDir\${PRODUCT_EXE_FILE},0" remove_IntelliJIdeaProjectFile done remove_IntelliJIdeaProjectFile: StrCpy $1 "IntelliJIdeaProjectFile" diff --git a/build/conf/nsis/registry.nsi b/build/conf/nsis/registry.nsi index 99a47ce2715d..baff6702852a 100644 --- a/build/conf/nsis/registry.nsi +++ b/build/conf/nsis/registry.nsi @@ -81,8 +81,6 @@ Function ${un}OMReadRegStr hkcr: ReadRegStr $3 HKCR $1 $2 done: - IfErrors 0 +2 - DetailPrint "ERROR: $0, $1, $2" FunctionEnd ; ----------------------------------------------------------------------------- diff --git a/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java b/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java index 18eb9156ff98..49494e78e03e 100644 --- a/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java @@ -36,6 +36,7 @@ import com.intellij.openapi.project.VetoableProjectManagerListener; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindow; @@ -75,6 +76,8 @@ public class BuildContentManagerImpl implements BuildContentManager { public static final String Run = "Run"; public static final String Debug = "Debug"; private static final String[] ourPresetOrder = {Build, Sync, Run, Debug}; + private static final Key> CONTENT_CLOSE_LISTENERS = Key.create("CONTENT_CLOSE_LISTENERS"); + private Project myProject; private ToolWindow myToolWindow; private final List myPostponedRunnables = new ArrayList<>(); @@ -263,9 +266,16 @@ public class BuildContentManagerImpl implements BuildContentManager { return content; } - public void startBuildNotified(@NotNull Content content, @Nullable BuildProcessHandler processHandler) { + public void startBuildNotified(@NotNull BuildDescriptor buildDescriptor, + @NotNull Content content, + @Nullable BuildProcessHandler processHandler) { if (processHandler != null) { - new CloseListener(content, processHandler); + Map closeListenerMap = content.getUserData(CONTENT_CLOSE_LISTENERS); + if (closeListenerMap == null) { + closeListenerMap = ContainerUtil.newHashMap(); + content.putUserData(CONTENT_CLOSE_LISTENERS, closeListenerMap); + } + closeListenerMap.put(buildDescriptor.getId(), new CloseListener(content, processHandler)); } runWhenInitialized(() -> { Pair pair = liveContentsMap.computeIfAbsent(content, c -> Pair.pair(c.getIcon(), new AtomicInteger(0))); @@ -280,7 +290,17 @@ public class BuildContentManagerImpl implements BuildContentManager { }); } - public void finishBuildNotified(@NotNull Content content) { + public void finishBuildNotified(@NotNull BuildDescriptor buildDescriptor, @NotNull Content content) { + Map closeListenerMap = content.getUserData(CONTENT_CLOSE_LISTENERS); + if (closeListenerMap != null) { + CloseListener closeListener = closeListenerMap.remove(buildDescriptor.getId()); + if (closeListener != null) { + Disposer.dispose(closeListener); + if (closeListenerMap.isEmpty()) { + content.putUserData(CONTENT_CLOSE_LISTENERS, null); + } + } + } runWhenInitialized(() -> { Pair pair = liveContentsMap.get(content); if (pair != null && pair.second.decrementAndGet() == 0) { @@ -308,8 +328,10 @@ public class BuildContentManagerImpl implements BuildContentManager { } private class CloseListener extends ContentManagerAdapter implements VetoableProjectManagerListener, Disposable { + @Nullable private Content myContent; - private final BuildProcessHandler myProcessHandler; + @Nullable + private BuildProcessHandler myProcessHandler; private CloseListener(@NotNull final Content content, @NotNull BuildProcessHandler processHandler) { myContent = content; @@ -339,8 +361,11 @@ public class BuildContentManagerImpl implements BuildContentManager { contentManager.removeContentManagerListener(this); } ProjectManager.getInstance().removeProjectManagerListener(myProject, this); - content.release(); myContent = null; + if (myProcessHandler instanceof Disposable) { + Disposer.dispose((Disposable)myProcessHandler); + } + myProcessHandler = null; } @Override diff --git a/java/compiler/impl/src/com/intellij/build/MultipleBuildsView.java b/java/compiler/impl/src/com/intellij/build/MultipleBuildsView.java index 3fdd00025494..7390bd13e274 100644 --- a/java/compiler/impl/src/com/intellij/build/MultipleBuildsView.java +++ b/java/compiler/impl/src/com/intellij/build/MultipleBuildsView.java @@ -201,7 +201,7 @@ public class MultipleBuildsView implements BuildProgressListener, Disposable { boolean focusContent = contentDescriptor.isAutoFocusContent(); myBuildContentManager.setSelectedContent( myContent, focusContent, focusContent, activateToolWindow, contentDescriptor.getActivationCallback()); - Disposer.register(this, contentDescriptor); + Disposer.register(view, contentDescriptor); } else { myBuildContentManager.setSelectedContent(myContent, true, true, true, null); @@ -233,7 +233,7 @@ public class MultipleBuildsView implements BuildProgressListener, Disposable { } myViewManager.onBuildStart(buildInfo); myProgressWatcher.addBuild(buildInfo); - ((BuildContentManagerImpl)myBuildContentManager).startBuildNotified(buildInfo.content, startBuildEvent.getProcessHandler()); + ((BuildContentManagerImpl)myBuildContentManager).startBuildNotified(buildInfo, buildInfo.content, startBuildEvent.getProcessHandler()); } else { if (event instanceof FinishBuildEvent) { @@ -241,7 +241,7 @@ public class MultipleBuildsView implements BuildProgressListener, Disposable { buildInfo.message = event.getMessage(); buildInfo.result = ((FinishBuildEvent)event).getResult(); myProgressWatcher.stopBuild(buildInfo); - ((BuildContentManagerImpl)myBuildContentManager).finishBuildNotified(buildInfo.content); + ((BuildContentManagerImpl)myBuildContentManager).finishBuildNotified(buildInfo, buildInfo.content); myViewManager.onBuildFinish(buildInfo); } else { diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 592b07186e2c..1a958c85ad78 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -26,6 +26,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.impl.ExternalModuleListStorage; import com.intellij.openapi.project.ModuleListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; @@ -60,6 +61,8 @@ import org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerConfig import java.io.File; import java.util.*; +import static com.intellij.compiler.ExternalCompilerConfigurationStorageKt.*; +import static com.intellij.util.JdomKt.element; import static org.jetbrains.jps.model.java.impl.compiler.ResourcePatterns.normalizeWildcards; import static org.jetbrains.jps.model.java.impl.compiler.ResourcePatterns.optimize; import static org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerConfigurationSerializer.DEFAULT_WILDCARD_PATTERNS; @@ -153,7 +156,6 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements @Override public Element getState() { - Element state = new Element("state"); XmlSerializer.serializeInto(myState, state, new SkipDefaultValuesSerializationFilters() { @Override @@ -207,30 +209,17 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements state.addContent(annotationProcessingSettings); } - if (!StringUtil.isEmpty(myBytecodeTargetLevel) || !myModuleBytecodeTarget.isEmpty()) { - final Element bytecodeTarget = addChild(state, JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL); + List moduleNames = getFilteredModuleNameList(myProject, myModuleBytecodeTarget, false); + if (!StringUtil.isEmpty(myBytecodeTargetLevel) || !moduleNames.isEmpty()) { + final Element bytecodeTarget = element(state, JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL); if (!StringUtil.isEmpty(myBytecodeTargetLevel)) { bytecodeTarget.setAttribute(JpsJavaCompilerConfigurationSerializer.TARGET_ATTRIBUTE, myBytecodeTargetLevel); } - if (!myModuleBytecodeTarget.isEmpty()) { - final List moduleNames = new ArrayList<>(myModuleBytecodeTarget.keySet()); - Collections.sort(moduleNames, String.CASE_INSENSITIVE_ORDER); - for (String name : moduleNames) { - final Element moduleElement = addChild(bytecodeTarget, JpsJavaCompilerConfigurationSerializer.MODULE); - moduleElement.setAttribute(JpsJavaCompilerConfigurationSerializer.NAME, name); - final String value = myModuleBytecodeTarget.get(name); - moduleElement.setAttribute(JpsJavaCompilerConfigurationSerializer.TARGET_ATTRIBUTE, value != null ? value : ""); - } - } + writeBytecodeTarget(moduleNames, myModuleBytecodeTarget, bytecodeTarget); } return state; } - @Override - public void loadState(Element state) { - readExternal(state); - } - @Override public int getBuildProcessHeapSize(final int javacPreferredHeapSize) { final int heapSize = myState.BUILD_PROCESS_HEAP_SIZE; @@ -702,8 +691,8 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements return true; } - - public void readExternal(@NotNull Element parentNode) { + @Override + public void loadState(@NotNull Element parentNode) { myState = XmlSerializer.deserialize(parentNode, State.class); if (!myProject.isDefault()) { for (Element option : parentNode.getChildren("option")) { @@ -785,20 +774,16 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements myBytecodeTargetLevel = null; myModuleBytecodeTarget.clear(); - final Element bytecodeTargetElement = parentNode.getChild(JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL); + + Element bytecodeTargetElement = parentNode.getChild(JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL); if (bytecodeTargetElement != null) { myBytecodeTargetLevel = bytecodeTargetElement.getAttributeValue(JpsJavaCompilerConfigurationSerializer.TARGET_ATTRIBUTE); - for (Element elem : bytecodeTargetElement.getChildren(JpsJavaCompilerConfigurationSerializer.MODULE)) { - final String name = elem.getAttributeValue(JpsJavaCompilerConfigurationSerializer.NAME); - if (name == null) { - continue; - } - final String target = elem.getAttributeValue(JpsJavaCompilerConfigurationSerializer.TARGET_ATTRIBUTE); - if (target == null) { - continue; - } - myModuleBytecodeTarget.put(name, target); - } + readByteTargetLevel(parentNode); + } + + Map externalState = myProject.getComponent(ExternalCompilerConfigurationStorage.class).getLoadedState(); + if (externalState != null) { + myModuleBytecodeTarget.putAll(externalState); } } diff --git a/java/compiler/impl/src/com/intellij/compiler/ExternalCompilerConfigurationStorage.kt b/java/compiler/impl/src/com/intellij/compiler/ExternalCompilerConfigurationStorage.kt new file mode 100644 index 000000000000..14f7feab2f0c --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/ExternalCompilerConfigurationStorage.kt @@ -0,0 +1,85 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.compiler + +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.module.impl.ModuleManagerImpl +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.isExternalStorageEnabled +import com.intellij.openapi.roots.ExternalProjectSystemRegistry +import com.intellij.openapi.roots.ProjectModelElement +import com.intellij.openapi.roots.ProjectModelExternalSource +import com.intellij.util.element +import gnu.trove.THashMap +import org.jdom.Element +import org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerConfigurationSerializer +import java.util.* + +@State(name = "ExternalCompilerConfigurationStorage", storages = arrayOf(Storage("compiler.xml")), externalStorageOnly = true) +internal class ExternalCompilerConfigurationStorage(private val project: Project) : PersistentStateComponent, ProjectModelElement { + var loadedState: Map? = null + private set + + override fun getState(): Element { + val e = Element("state") + if (!project.isExternalStorageEnabled) { + return e + } + + val map = (CompilerConfigurationImpl.getInstance(project) as CompilerConfigurationImpl).modulesBytecodeTargetMap + val moduleNames = getFilteredModuleNameList(project, map, true) + if (moduleNames.isNotEmpty()) { + writeBytecodeTarget(moduleNames, map, e.element(JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL)) + } + return e + } + + override fun loadState(state: Element) { + loadedState = readByteTargetLevel(state) + } + + override fun getExternalSource(): ProjectModelExternalSource? { + val externalProjectSystemRegistry = ExternalProjectSystemRegistry.getInstance() + for (module in ModuleManagerImpl.getInstanceImpl(project).modules) { + externalProjectSystemRegistry.getExternalSource(module)?.let { + return it + } + } + return null + } +} + +internal fun getFilteredModuleNameList(project: Project, map: Map, isExternal: Boolean): List { + if (!project.isExternalStorageEnabled) { + return map.keys.toList() + } + + val moduleManager = ModuleManagerImpl.getInstanceImpl(project) + val externalProjectSystemRegistry = ExternalProjectSystemRegistry.getInstance() + return map.keys.filter { + // if no module and !isExternal - return true because CompilerConfigurationImpl saves module name as is without module existence check and this logic is preserved + val module = moduleManager.findModuleByName(it) ?: return@filter !isExternal + (externalProjectSystemRegistry.getExternalSource(module) != null) == isExternal + } +} + +internal fun writeBytecodeTarget(moduleNames: List, map: Map, element: Element) { + Collections.sort(moduleNames, String.CASE_INSENSITIVE_ORDER) + for (name in moduleNames) { + val moduleElement = element.element(JpsJavaCompilerConfigurationSerializer.MODULE) + moduleElement.setAttribute(JpsJavaCompilerConfigurationSerializer.NAME, name) + moduleElement.setAttribute(JpsJavaCompilerConfigurationSerializer.TARGET_ATTRIBUTE, map.get(name) ?: "") + } +} + +internal fun readByteTargetLevel(parentNode: Element): Map { + val result = THashMap() + val bytecodeTargetElement = parentNode.getChild(JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL) ?: return result + for (element in bytecodeTargetElement.getChildren(JpsJavaCompilerConfigurationSerializer.MODULE)) { + val name = element.getAttributeValue(JpsJavaCompilerConfigurationSerializer.NAME) ?: continue + val target = element.getAttributeValue(JpsJavaCompilerConfigurationSerializer.TARGET_ATTRIBUTE) ?: continue + result.put(name, target) + } + return result +} \ No newline at end of file diff --git a/java/compiler/tests/com/intellij/compiler/CorruptedBuildCachesTest.java b/java/compiler/tests/com/intellij/compiler/CorruptedBuildCachesTest.java index 878405244b73..06e8c0bdffba 100644 --- a/java/compiler/tests/com/intellij/compiler/CorruptedBuildCachesTest.java +++ b/java/compiler/tests/com/intellij/compiler/CorruptedBuildCachesTest.java @@ -37,19 +37,21 @@ public class CorruptedBuildCachesTest extends BaseCompilerTestCase { } public void testSrcOutMapping() { + final String moduleName = "m"; + final String moduleDirName = moduleName + "_" + Integer.toHexString(moduleName.hashCode()); VirtualFile a = createFile("src/A.java", "class A{}"); - Module m = addModule("m", a.getParent()); + Module m = addModule(moduleName, a.getParent()); make(m); assertOutput(m, fs().file("A.class")); File systemDirectory = BuildManager.getInstance().getProjectSystemDirectory(myProject); - assertTrue(FileUtil.delete(new File(systemDirectory, "targets/java-production/m/src-out"))); + assertTrue(FileUtil.delete(new File(systemDirectory, "targets/java-production/"+moduleDirName+"/src-out"))); changeFile(a, "class A{int b;}"); make(m).assertGenerated("A.class"); make(m).assertUpToDate(); changeFile(a, "class A{int c;}"); - corruptCaches(new File(systemDirectory, "targets/java-production/m/src-out/data")); + corruptCaches(new File(systemDirectory, "targets/java-production/"+moduleDirName+"/src-out/data")); make(m).assertGenerated("A.class"); assertOutput(m, fs().file("A.class")); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 16d5c4b016b0..2d36cc14cbc9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -558,7 +558,7 @@ public class DebugProcessEvents extends DebugProcessImpl { if (event != null && myNotificationsCoolDown.compareAndSet(false, true)) { AppExecutorUtil.getAppScheduledExecutorService().schedule(() -> myNotificationsCoolDown.set(false), 1, TimeUnit.SECONDS); XDebuggerManagerImpl.NOTIFICATION_GROUP - .createNotification(DebuggerBundle.message("message.breakpoint.skipped", event.location()), MessageType.INFO) + .createNotification(DebuggerBundle.message("message.breakpoint.skipped", event.location()), MessageType.WARNING) .notify(getProject()); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 6000a4b9eda2..00a973e4a306 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -474,17 +474,21 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb if (timeoutArg != null) { timeoutArg.setValue("0"); // wait forever } - String listeningAddress = connector.startListening(myArguments); - String port = StringUtil.substringAfter(listeningAddress, ":"); - if (port != null) { - listeningAddress = port; - } - myConnection.setAddress(listeningAddress); - - myDebugProcessDispatcher.getMulticaster().connectorIsReady(); try { + String listeningAddress = connector.startListening(myArguments); + String port = StringUtil.substringAfter(listeningAddress, ":"); + if (port != null) { + listeningAddress = port; + } + myConnection.setAddress(listeningAddress); + + myDebugProcessDispatcher.getMulticaster().connectorIsReady(); + return connector.accept(myArguments); } + catch (IllegalArgumentException e) { + throw new CantRunException(e.getLocalizedMessage()); + } finally { if(myArguments != null) { try { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java index 4046ea343b03..b0b149916c77 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.engine; import com.intellij.debugger.DebuggerBundle; @@ -51,7 +37,7 @@ public abstract class JavaValueModifier extends XValueModifier { @Override public void calculateInitialValueEditorText(final XInitialValueCallback callback) { final Value value = myJavaValue.getDescriptor().getValue(); - if (value instanceof PrimitiveValue) { + if (value == null || value instanceof PrimitiveValue) { String valueString = myJavaValue.getValueString(); int pos = valueString.lastIndexOf('('); //skip hex presentation if any if (pos > 1) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java index 14a504add554..9ada361e9aca 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.ui.impl.watch; import com.intellij.debugger.DebuggerBundle; @@ -128,6 +114,11 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl { } } + @Override + protected boolean isPrintExceptionToConsole() { + return false; + } + @Nullable public Modifier getModifier() { return myModifier; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java index 2ea8ad3c79b0..637a9748174b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.ui.impl.watch; import com.intellij.debugger.DebuggerBundle; @@ -31,7 +17,9 @@ import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.tree.FieldDescriptor; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.CommonClassNames; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiExpression; @@ -95,13 +83,32 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); try { - return (myObject != null) ? myObject.getValue(myField) : myField.declaringType().getValue(myField); + if (myObject != null) { + populateExceptionStackTraceIfNeeded(evaluationContext); + return myObject.getValue(myField); + } + else { + return myField.declaringType().getValue(myField); + } } catch (ObjectCollectedException ignored) { throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED; } } + private void populateExceptionStackTraceIfNeeded(EvaluationContextImpl evaluationContext) { + if ("stackTrace".equals(getName()) && + Registry.is("debugger.populate.exception.stack") && + DebuggerUtils.instanceOf(myObject.type(), CommonClassNames.JAVA_LANG_THROWABLE)) { + try { + invokeExceptionGetStackTrace(myObject, evaluationContext); + } + catch (Throwable e) { + LOG.info(e); // catch all exceptions to ensure the method returns gracefully + } + } + } + public boolean isStatic() { return myIsStatic; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java index 3c582fc7e35b..19cdc1641949 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.ui.impl.watch; import com.intellij.Patches; @@ -221,7 +207,8 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements catch (EvaluateException e) { myValueException = e; setFailed(e); - myValue = getTargetExceptionWithStackTraceFilled(evaluationContext, e); + myValue = getTargetExceptionWithStackTraceFilled(evaluationContext, e, + isPrintExceptionToConsole() || ApplicationManager.getApplication().isUnitTestMode()); myIsExpandable = false; } finally { @@ -231,24 +218,36 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements myIsNew = false; } + protected boolean isPrintExceptionToConsole() { + return true; + } + @Nullable - private static ObjectReference getTargetExceptionWithStackTraceFilled(final EvaluationContextImpl evaluationContext, EvaluateException ex){ + protected static Value invokeExceptionGetStackTrace(ObjectReference exceptionObj, EvaluationContextImpl evaluationContext) + throws EvaluateException { + Method method = ((ClassType)exceptionObj.referenceType()).concreteMethodByName("getStackTrace", "()[Ljava/lang/StackTraceElement;"); + if (method != null) { + return evaluationContext.getDebugProcess().invokeMethod(evaluationContext, exceptionObj, method, Collections.emptyList()); + } + return null; + } + + @Nullable + private static ObjectReference getTargetExceptionWithStackTraceFilled(@Nullable EvaluationContextImpl evaluationContext, + EvaluateException ex, + boolean printToConsole) { final ObjectReference exceptionObj = ex.getExceptionFromTargetVM(); if (exceptionObj != null && evaluationContext != null) { try { - ClassType refType = (ClassType)exceptionObj.referenceType(); - Method method = refType.concreteMethodByName("getStackTrace", "()[Ljava/lang/StackTraceElement;"); - if (method != null) { - final DebugProcessImpl process = evaluationContext.getDebugProcess(); - Value trace = process.invokeMethod(evaluationContext, exceptionObj, method, Collections.emptyList()); + Value trace = invokeExceptionGetStackTrace(exceptionObj, evaluationContext); - // print to console as well - if (trace instanceof ArrayReference) { - ArrayReference traceArray = (ArrayReference)trace; - process.printToConsole(DebuggerUtils.getValueAsString(evaluationContext, exceptionObj) + "\n"); - for (Value stackElement : traceArray.getValues()) { - process.printToConsole("\tat " + DebuggerUtils.getValueAsString(evaluationContext, stackElement) + "\n"); - } + // print to console as well + if (printToConsole && trace instanceof ArrayReference) { + DebugProcessImpl process = evaluationContext.getDebugProcess(); + ArrayReference traceArray = (ArrayReference)trace; + process.printToConsole(DebuggerUtils.getValueAsString(evaluationContext, exceptionObj) + "\n"); + for (Value stackElement : traceArray.getValues()) { + process.printToConsole("\tat " + DebuggerUtils.getValueAsString(evaluationContext, stackElement) + "\n"); } } } diff --git a/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.form b/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.form index 4d422a7538c7..e2f091d39508 100644 --- a/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.form +++ b/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.form @@ -51,7 +51,7 @@ - + diff --git a/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.java b/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.java index b364546d6af5..fa0407cc14df 100644 --- a/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.java +++ b/java/execution/impl/src/com/intellij/execution/remote/RemoteConfigurable.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. /* * Class RemoteConfigurable @@ -31,6 +17,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.components.fields.IntegerField; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -47,7 +34,7 @@ public class RemoteConfigurable extends SettingsEditor { private JRadioButton myRbAttach; private JTextField myAddressField; private JTextField myHostField; - private JTextField myPortField; + private IntegerField myPortField; private JPanel myShmemPanel; private JPanel mySocketPanel; private ConfigurationArgumentsHelpArea myHelpArea; @@ -147,6 +134,9 @@ public class RemoteConfigurable extends SettingsEditor { configuration.SHMEM_ADDRESS = null; } configuration.USE_SOCKET_TRANSPORT = myRbSocket.isSelected(); + if (configuration.USE_SOCKET_TRANSPORT) { + myPortField.validateContent(); + } configuration.SERVER_MODE = myRbListen.isSelected(); myModuleSelector.applyTo(configuration); } @@ -199,5 +189,7 @@ public class RemoteConfigurable extends SettingsEditor { myJDK13HelpArea.updateText("-Xnoagent -Djava.compiler=NONE " + cmdLine); } - + private void createUIComponents() { + myPortField = new IntegerField("Port", 0, 0xFFFF); + } } \ No newline at end of file diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java index 8d97e808fa73..f48f1cd14025 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java @@ -473,7 +473,7 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change ContainerUtil.addIfNotNull(modifiableRootModels, modifiableRootModel); } - ModuleDeleteProvider.removeModule(moduleToRemove, null, modifiableRootModels, myModuleModel); + ModuleDeleteProvider.removeModule(moduleToRemove, modifiableRootModels, myModuleModel); Disposer.dispose(editor); } processModuleCountChanged(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java index baa17ba5854b..3e5815fe2abe 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java @@ -171,47 +171,21 @@ public class ModuleHighlightUtil { @NotNull static List checkDuplicateStatements(@NotNull PsiJavaModule module) { List results = ContainerUtil.newSmartList(); - - checkDuplicateRefs( - module.getRequires(), - st -> Optional.ofNullable(st.getReferenceElement()).map(PsiJavaModuleReferenceElement::getReferenceText), - "module.duplicate.requires", - results); - - checkDuplicateRefs( - module.getExports(), - st -> Optional.ofNullable(st.getPackageReference()).map(ModuleHighlightUtil::refText), - "module.duplicate.exports", - results); - - checkDuplicateRefs( - module.getOpens(), - st -> Optional.ofNullable(st.getPackageReference()).map(ModuleHighlightUtil::refText), - "module.duplicate.opens", - results); - - checkDuplicateRefs( - module.getUses(), - st -> Optional.ofNullable(st.getClassReference()).map(ModuleHighlightUtil::qName), - "module.duplicate.uses", - results); - - checkDuplicateRefs( - module.getProvides(), - st -> Optional.ofNullable(st.getInterfaceReference()).map(ModuleHighlightUtil::qName), - "module.duplicate.provides", - results); - + checkDuplicateRefs(module.getRequires(), st -> st.getModuleName(), "module.duplicate.requires", results); + checkDuplicateRefs(module.getExports(), st -> st.getPackageName(), "module.duplicate.exports", results); + checkDuplicateRefs(module.getOpens(), st -> st.getPackageName(), "module.duplicate.opens", results); + checkDuplicateRefs(module.getUses(), st -> qName(st.getClassReference()), "module.duplicate.uses", results); + checkDuplicateRefs(module.getProvides(), st -> qName(st.getInterfaceReference()), "module.duplicate.provides", results); return results; } - private static void checkDuplicateRefs(Iterable statements, - Function> ref, - @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String key, - List results) { + private static void checkDuplicateRefs(Iterable statements, + Function ref, + @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String key, + List results) { Set filter = ContainerUtil.newTroveSet(); for (T statement : statements) { - String refText = ref.apply(statement).orElse(null); + String refText = ref.apply(statement); if (refText != null && !filter.add(refText)) { String message = JavaErrorMessages.message(key, refText); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); @@ -226,20 +200,25 @@ public class ModuleHighlightUtil { static List checkUnusedServices(@NotNull PsiJavaModule module, @NotNull PsiFile file) { List results = ContainerUtil.newSmartList(); - Set exports = JBIterable.from(module.getExports()).map(st -> refText(st.getPackageReference())).filter(Objects::nonNull).toSet(); - Set uses = JBIterable.from(module.getUses()).map(st -> qName(st.getClassReference())).filter(Objects::nonNull).toSet(); - Module host = findModuleForFile(file); if (host != null) { - for (PsiProvidesStatement statement : module.getProvides()) { - PsiJavaCodeReferenceElement ref = statement.getInterfaceReference(); - if (ref != null) { - PsiElement target = ref.resolve(); - if (target instanceof PsiClass && findModuleForFile(target.getContainingFile()) == host) { - String className = qName(ref), packageName = StringUtil.getPackageName(className); - if (!exports.contains(packageName) && !uses.contains(className)) { - String message = JavaErrorMessages.message("module.service.unused"); - results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(range(ref)).descriptionAndTooltip(message).create()); + List provides = JBIterable.from(module.getProvides()).toList(); + if (!provides.isEmpty()) { + Set exports = JBIterable.from(module.getExports()).map(PsiPackageAccessibilityStatement::getPackageName).filter(Objects::nonNull).toSet(); + Set uses = JBIterable.from(module.getUses()).map(st -> qName(st.getClassReference())).filter(Objects::nonNull).toSet(); + for (PsiProvidesStatement statement : provides) { + PsiJavaCodeReferenceElement ref = statement.getInterfaceReference(); + if (ref != null) { + PsiElement target = ref.resolve(); + if (target instanceof PsiClass && findModuleForFile(target.getContainingFile()) == host) { + String className = qName(ref), packageName = StringUtil.getPackageName(className); + if (!exports.contains(packageName) && !uses.contains(className)) { + String message = JavaErrorMessages.message("module.service.unused"); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(range(ref)).descriptionAndTooltip(message).create(); + QuickFixAction.registerQuickFixAction(info, new AddExportsDirectiveFix(module, packageName, "")); + QuickFixAction.registerQuickFixAction(info, new AddUsesDirectiveFix(module, className)); + results.add(info); + } } } } @@ -249,10 +228,6 @@ public class ModuleHighlightUtil { return results; } - private static String refText(PsiJavaCodeReferenceElement ref) { - return ref != null ? PsiNameHelper.getQualifiedClassName(ref.getText(), true) : null; - } - private static String qName(PsiJavaCodeReferenceElement ref) { return ref != null ? ref.getQualifiedName() : null; } @@ -324,13 +299,13 @@ public class ModuleHighlightUtil { if (module != null) { PsiElement target = refElement.resolve(); PsiDirectory[] directories = target instanceof PsiPackage ? ((PsiPackage)target).getDirectories(module.getModuleScope(false)) : null; - String packageName = refText(refElement); + String packageName = statement.getPackageName(); HighlightInfoType type = statement.getRole() == Role.OPENS ? HighlightInfoType.WARNING : HighlightInfoType.ERROR; if (directories == null || directories.length == 0) { String message = JavaErrorMessages.message("package.not.found", packageName); return HighlightInfo.newHighlightInfo(type).range(refElement).descriptionAndTooltip(message).create(); } - if (PsiUtil.isPackageEmpty(directories, packageName)) { + if (packageName != null && PsiUtil.isPackageEmpty(directories, packageName)) { String message = JavaErrorMessages.message("package.is.empty", packageName); return HighlightInfo.newHighlightInfo(type).range(refElement).descriptionAndTooltip(message).create(); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDirectiveFix.kt b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDirectiveFix.kt index 5cfb1b98b5c8..c87df4242386 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDirectiveFix.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDirectiveFix.kt @@ -40,11 +40,21 @@ class AddExportsDirectiveFix(module: PsiJavaModule, if (existing == null) { PsiUtil.addModuleStatement(module, PsiKeyword.EXPORTS + ' ' + packageName) } - else { + else if (!targetName.isEmpty()) { val targets = existing.moduleReferences.map { it.referenceText } if (!targets.isEmpty() && targetName !in targets) { existing.add(PsiElementFactory.SERVICE.getInstance(project).createModuleReferenceFromText(targetName)) } } } +} + +class AddUsesDirectiveFix(module: PsiJavaModule, private val svcName: String) : AddModuleDirectiveFix(module) { + override fun getText() = QuickFixBundle.message("module.info.add.uses.name", svcName) + + override fun invoke(project: Project, file: PsiFile, editor: Editor?, module: PsiJavaModule) { + if (module.uses.find { svcName == it.classReference?.qualifiedName } == null) { + PsiUtil.addModuleStatement(module, PsiKeyword.USES + ' ' + svcName) + } + } } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java index f89565ccd385..1cbd6aef81c5 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java @@ -564,7 +564,7 @@ public class DuplicatesFinder { PsiElement child2 = children2[i]; if (!matchPattern(child1, child2, candidates, match)) { matchedExtractablePart = matchExtractableExpression(child1, child2, candidates, match, true); - return matchedExtractablePart != null && matchedExtractablePart; + if (matchedExtractablePart == null || !matchedExtractablePart) return false; } } diff --git a/java/java-analysis-impl/src/messages/QuickFixBundle.properties b/java/java-analysis-impl/src/messages/QuickFixBundle.properties index 2dc6a985ffc9..84644bb302ee 100644 --- a/java/java-analysis-impl/src/messages/QuickFixBundle.properties +++ b/java/java-analysis-impl/src/messages/QuickFixBundle.properties @@ -308,6 +308,7 @@ extract.side.effects.family.name=Delete statement extracting side effects module.info.add.directive.family.name=Add a directive to module-info.java module.info.add.requires.name=Add ''requires {0}'' directive to module-info.java module.info.add.exports.name=Add ''exports {0}'' directive to module-info.java +module.info.add.uses.name=Add ''uses {0}'' directive to module-info.java collection.to.array.text=Apply conversion ''.toArray({0})'' collection.to.array.family.name=Apply conversion '.toArray()' diff --git a/java/java-impl/src/com/intellij/execution/configuration/JavaRunConfigurationPathMacroFilter.java b/java/java-impl/src/com/intellij/execution/configuration/JavaRunConfigurationPathMacroFilter.java index ffaf6f5376b5..f6208dbccd2d 100644 --- a/java/java-impl/src/com/intellij/execution/configuration/JavaRunConfigurationPathMacroFilter.java +++ b/java/java-impl/src/com/intellij/execution/configuration/JavaRunConfigurationPathMacroFilter.java @@ -1,30 +1,17 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.execution.configuration; import com.intellij.openapi.application.PathMacroFilter; import org.jdom.Attribute; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; /** * @author peter */ public class JavaRunConfigurationPathMacroFilter extends PathMacroFilter { @Override - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { final Element parent = attribute.getParent(); if (parent.getName().equals("option")) { diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index f9ff0993035b..279c21623c58 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -811,7 +811,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo * * @param child variable declaration child node which alignment is to be defined * @return alignment to use for the given node - * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS + * @see CommonCodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS */ private boolean shouldAlignFieldInColumns(@NotNull ASTNode child) { // The whole idea of variable declarations alignment is that complete declaration blocks which children are to be aligned hold diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 20464e3aa8c6..0dddfea1eda8 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -521,7 +521,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { /** * Initializes {@link #myResult} property with {@link Spacing} which {@code 'min line feeds'} property is defined - * from {@link CodeStyleSettings#BLANK_LINES_AROUND_CLASS} value. + * from {@link CommonCodeStyleSettings#BLANK_LINES_AROUND_CLASS} value. */ private void setAroundClassSpacing() { myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, mySettings.BLANK_LINES_AROUND_CLASS + 1, diff --git a/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java b/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java index 8e2567a70dc4..50227e2d677a 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi; import org.jetbrains.annotations.Nullable; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsUsesStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsUsesStatementImpl.java index 87b7c324dcf0..fcd0e2d87db8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsUsesStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsUsesStatementImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.impl.compiled; import com.intellij.openapi.util.text.StringUtil; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java index bc5a1cb4df15..2a0ebd57e8e6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java @@ -1,25 +1,8 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.impl.source; import com.intellij.lang.ASTNode; -import com.intellij.psi.JavaElementVisitor; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiJavaCodeReferenceElement; -import com.intellij.psi.PsiUsesStatement; +import com.intellij.psi.*; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiUsesStatementStub; import com.intellij.psi.util.PsiTreeUtil; diff --git a/java/java-tests/testData/refactoring/extractMethod/WriteDifferentFieldsDuplicate.java b/java/java-tests/testData/refactoring/extractMethod/WriteDifferentFieldsDuplicate.java new file mode 100644 index 000000000000..5f9077a97e74 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/WriteDifferentFieldsDuplicate.java @@ -0,0 +1,17 @@ +class WriteDifferentFieldsDuplicate { + Runnable x; + Runnable y; + + private void foo() { + + if (x != null) { + x.run(); + x = null; + } + + if (y != null) { + y.run(); + y = null; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/WriteDifferentFieldsDuplicate_after.java b/java/java-tests/testData/refactoring/extractMethod/WriteDifferentFieldsDuplicate_after.java new file mode 100644 index 000000000000..7132e803b47a --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/WriteDifferentFieldsDuplicate_after.java @@ -0,0 +1,21 @@ +class WriteDifferentFieldsDuplicate { + Runnable x; + Runnable y; + + private void foo() { + + newMethod(); + + if (y != null) { + y.run(); + y = null; + } + } + + private void newMethod() { + if (x != null) { + x.run(); + x = null; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java index 1fc884aa30c8..a6e2a1b72c51 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java @@ -21,8 +21,6 @@ import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.actionSystem.EditorActionManager; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.testFramework.LightCodeInsightTestCase; @@ -43,81 +41,81 @@ public class JoinLinesTest extends LightCodeInsightTestCase { public void testLiteralSCR4989() { doTest(); } public void testSCR3493() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; } } public void testSCR3493a() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; } } public void testSCR3493b() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER;; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; } } public void testSCR3493c() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; } } public void testSCR3493d() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; } } public void testSCR3493e() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; } } public void testSCR5959() { @@ -138,49 +136,54 @@ public class JoinLinesTest extends LightCodeInsightTestCase { public void testDeclarationWithInitializer() {doTest(); } public void testUnwrapCodeBlock1() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; int old = settings.IF_BRACE_FORCE; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; - settings.getCommonSettings(JavaLanguage.INSTANCE).IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_IF_MULTILINE; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; + settings.IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_IF_MULTILINE; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; - settings.getCommonSettings(JavaLanguage.INSTANCE).IF_BRACE_FORCE = old; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; + settings.IF_BRACE_FORCE = old; } } public void testUnwrapCodeBlock2() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - boolean use_tab_character = settings.useTabCharacter(null); - boolean smart_tabs = settings.isSmartTabs(null); + CommonCodeStyleSettings settings = getJavaSettings(); + boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER; + boolean smart_tabs = settings.getIndentOptions().SMART_TABS; int old = settings.IF_BRACE_FORCE; try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; - settings.getCommonSettings(JavaLanguage.INSTANCE).IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_ALWAYS; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; + settings.IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_ALWAYS; doTest(); } finally { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = use_tab_character; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = smart_tabs; - settings.getCommonSettings(JavaLanguage.INSTANCE).IF_BRACE_FORCE = old; + settings.getIndentOptions().USE_TAB_CHARACTER = use_tab_character; + settings.getIndentOptions().SMART_TABS = smart_tabs; + settings.IF_BRACE_FORCE = old; } } + @NotNull + protected CommonCodeStyleSettings getJavaSettings() { + return CodeStyleSettingsManager.getSettings(getProject()).getCommonSettings(JavaLanguage.INSTANCE); + } + public void testAssignmentExpression() { doTest(); } public void testReformatInsertsNewlines() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + CommonCodeStyleSettings settings = getJavaSettings(); final Element root = new Element("fake"); settings.writeExternal(root); try { - settings.getIndentOptions(StdFileTypes.JAVA).USE_TAB_CHARACTER = true; - settings.getIndentOptions(StdFileTypes.JAVA).SMART_TABS = true; + settings.getIndentOptions().USE_TAB_CHARACTER = true; + settings.getIndentOptions().SMART_TABS = true; settings.IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_ALWAYS; settings.METHOD_BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE; doTest(); @@ -190,7 +193,7 @@ public class JoinLinesTest extends LightCodeInsightTestCase { } public void testForceBrace() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + CommonCodeStyleSettings settings = getJavaSettings(); int old = settings.IF_BRACE_FORCE; try { settings.IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_ALWAYS; @@ -201,8 +204,8 @@ public class JoinLinesTest extends LightCodeInsightTestCase { } public void testWrongWrapping() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - settings.setDefaultRightMargin(80); + CommonCodeStyleSettings settings = getJavaSettings(); + settings.RIGHT_MARGIN = 80; settings.CALL_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED; settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; doTest(); @@ -210,9 +213,9 @@ public class JoinLinesTest extends LightCodeInsightTestCase { public void testSubsequentJoiningAndUnexpectedTextRemoval() { // Inspired by IDEA-65342 - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - settings.setDefaultRightMargin(50); - settings.getCommonSettings(JavaLanguage.INSTANCE).CALL_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED; + CommonCodeStyleSettings settings = getJavaSettings(); + settings.RIGHT_MARGIN = 50; + settings.CALL_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED; doTest(2); } @@ -223,7 +226,7 @@ public class JoinLinesTest extends LightCodeInsightTestCase { } public void testJoiningMethodCallWhenItDoesntFit() { - CommonCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).getCommonSettings(JavaLanguage.INSTANCE); + CommonCodeStyleSettings settings = getJavaSettings(); settings.METHOD_CALL_CHAIN_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED; settings.RIGHT_MARGIN = 20; doTest(); @@ -232,7 +235,7 @@ public class JoinLinesTest extends LightCodeInsightTestCase { public void testMultipleBlockComments() { doTest(); } public void testPreserveSpaceIfOnNewLineOptionEnabled() { - CommonCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).getCommonSettings(JavaLanguage.INSTANCE); + CommonCodeStyleSettings settings = getJavaSettings(); settings.CATCH_ON_NEW_LINE = true; doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/ModuleHighlightingTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/ModuleHighlightingTest.kt index 5a67190ae3b1..ad1766c4046b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/ModuleHighlightingTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/ModuleHighlightingTest.kt @@ -221,6 +221,9 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() { addFile("module-info.java", "module M2 { }", M2) fixes("module M { requires M2; uses pkg.m2.C2; }", arrayOf("AddExportsDirectiveFix")) fixes("pkg/main/C.java", "package pkg.main;\nimport pkg.m2.C2;", arrayOf("AddExportsDirectiveFix")) + + addFile("pkg/main/S.java", "package pkg.main;\npublic class S { }") + fixes("module M { provides pkg.main.S with pkg.main.S; }", arrayOf("AddExportsDirectiveFix", "AddUsesDirectiveFix")) } fun testPackageAccessibility() = doTestPackageAccessibility(moduleFileInTests = false, checkFileInTests = false) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AddModuleDirectiveTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AddModuleDirectiveTest.kt index 72932ddb526c..723326f754e5 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AddModuleDirectiveTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AddModuleDirectiveTest.kt @@ -3,6 +3,7 @@ package com.intellij.java.codeInsight.daemon.quickFix import com.intellij.codeInsight.daemon.impl.quickfix.AddExportsDirectiveFix import com.intellij.codeInsight.daemon.impl.quickfix.AddRequiresDirectiveFix +import com.intellij.codeInsight.daemon.impl.quickfix.AddUsesDirectiveFix import com.intellij.codeInsight.intention.IntentionAction import com.intellij.java.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase import com.intellij.openapi.command.WriteCommandAction @@ -57,6 +58,11 @@ class AddModuleDirectiveTest : LightJava9ModulesCodeInsightFixtureTestCase() { "module M { exports pkg.m to M1, M2; }", "module M { exports pkg.m to M1, M2; }") + fun testNoExportsToUnnamed() = doExportsTest( + "module M { exports pkg.m to M1; }", + "module M { exports pkg.m to M1; }", + target = "") + fun testExportsExtendsOther() = doExportsTest( "module M {\n" + " exports pkg.m to M1;\n" + @@ -73,8 +79,28 @@ class AddModuleDirectiveTest : LightJava9ModulesCodeInsightFixtureTestCase() { " exports pkg.m to M1, M2\n" + "}") + fun testNewUses() = doUsesTest( + "module M { }", + "module M {\n" + + " uses pkg.m.C;\n" + + "}") + + fun testUsesAfterOther() = doUsesTest( + "module M {\n" + + " uses pkg.m.B;\n" + + "}", + "module M {\n" + + " uses pkg.m.B;\n" + + " uses pkg.m.C;\n" + + "}") + + fun testNoDuplicateUses() = doUsesTest( + "module M { uses pkg.m.C; }", + "module M { uses pkg.m.C; }") + private fun doRequiresTest(text: String, expected: String) = doTest(text, { AddRequiresDirectiveFix(it, "M2") }, expected) - private fun doExportsTest(text: String, expected: String) = doTest(text, { AddExportsDirectiveFix(it, "pkg.m", "M2") }, expected) + private fun doExportsTest(text: String, expected: String, target: String = "M2") = doTest(text, { AddExportsDirectiveFix(it, "pkg.m", target) }, expected) + private fun doUsesTest(text: String, expected: String) = doTest(text, { AddUsesDirectiveFix(it, "pkg.m.C") }, expected) private fun doTest(text: String, fix: (PsiJavaModule) -> IntentionAction, expected: String) { val file = myFixture.configureByText("module-info.java", text) as PsiJavaFile diff --git a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java index 38db528ea8f9..5861c6ea43b6 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java @@ -83,7 +83,7 @@ public class DetectIndentAndTypeTest extends LightPlatformCodeInsightFixtureTest public void testContinuationTab_AsTabSize() { CommonCodeStyleSettings common = mySettings.getCommonSettings(JavaLanguage.INSTANCE); - mySettings.ALIGN_MULTILINE_BINARY_OPERATION = false; + common.ALIGN_MULTILINE_BINARY_OPERATION = false; CommonCodeStyleSettings.IndentOptions indentOptions = common.getIndentOptions(); assert indentOptions != null; @@ -106,7 +106,7 @@ public class DetectIndentAndTypeTest extends LightPlatformCodeInsightFixtureTest public void testContinuationTabs_AsDoubleTabSize() { CommonCodeStyleSettings common = mySettings.getCommonSettings(JavaLanguage.INSTANCE); - mySettings.ALIGN_MULTILINE_BINARY_OPERATION = false; + common.ALIGN_MULTILINE_BINARY_OPERATION = false; CommonCodeStyleSettings.IndentOptions indentOptions = common.getIndentOptions(); assert indentOptions != null; diff --git a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/IndentTest.java b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/IndentTest.java index 200eefe9b6e3..6dea46692e18 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/IndentTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/IndentTest.java @@ -106,7 +106,7 @@ public class IndentTest extends LightIdeaTestCase { public void testParenthesizedContinuation() throws Exception { defaultSettings(); - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + CommonCodeStyleSettings settings = getJavaSettings(); settings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION = true; doTest("ParenthesizedContinuation.java", "ParenthesizedContinuation_after.java"); @@ -115,7 +115,7 @@ public class IndentTest extends LightIdeaTestCase { public void testParenthesizedContinuation2() throws Exception { defaultSettings(); - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + CommonCodeStyleSettings settings = getJavaSettings(); settings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION = true; doTest("ParenthesizedContinuation2.java", "ParenthesizedContinuation2_after.java"); @@ -159,7 +159,7 @@ public class IndentTest extends LightIdeaTestCase { } private void defaultSettings() { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + CommonCodeStyleSettings settings = getJavaSettings(); settings.ALIGN_MULTILINE_PARAMETERS = true; settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false; diff --git a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt index f97e72aa6942..5c9c65919f71 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt @@ -1953,16 +1953,17 @@ class JavaFormatterTest : AbstractJavaFormatterTest() { } fun testWrapParamsOnEveryItem() { - val codeStyleSettings = CodeStyleSettingsManager.getSettings(LightPlatformTestCase.getProject()) + val codeStyleSettings = CodeStyleSettingsManager.getSettings(getProject()) - val oldMargin = codeStyleSettings.getCommonSettings(JavaLanguage.INSTANCE).RIGHT_MARGIN - val oldKeep = codeStyleSettings.KEEP_LINE_BREAKS - val oldWrap = codeStyleSettings.METHOD_PARAMETERS_WRAP + val javaSettings = codeStyleSettings.getCommonSettings(JavaLanguage.INSTANCE) + val oldMargin = javaSettings.RIGHT_MARGIN + val oldKeep = javaSettings.KEEP_LINE_BREAKS + val oldWrap = javaSettings.METHOD_PARAMETERS_WRAP try { codeStyleSettings.setRightMargin(JavaLanguage.INSTANCE, 80) - codeStyleSettings.KEEP_LINE_BREAKS = false - codeStyleSettings.METHOD_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM + javaSettings.KEEP_LINE_BREAKS = false + javaSettings.METHOD_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM doClassTest( "public void foo(String p1,\n" + @@ -1986,8 +1987,8 @@ class JavaFormatterTest : AbstractJavaFormatterTest() { } finally { codeStyleSettings.setRightMargin(JavaLanguage.INSTANCE, oldMargin) - codeStyleSettings.KEEP_LINE_BREAKS = oldKeep - codeStyleSettings.METHOD_PARAMETERS_WRAP = oldWrap + javaSettings.KEEP_LINE_BREAKS = oldKeep + javaSettings.METHOD_PARAMETERS_WRAP = oldWrap } } diff --git a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaWrapOnTypingTest.java b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaWrapOnTypingTest.java index be9bc0d632ce..d87e590227b9 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaWrapOnTypingTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaWrapOnTypingTest.java @@ -1,26 +1,10 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.java.psi.formatter.java; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; public class JavaWrapOnTypingTest extends LightCodeInsightFixtureTestCase { - - public void testWrapInsideTags() { myFixture.configureByText(JavaFileType.INSTANCE, "public class Hw {\n" + @@ -51,4 +35,32 @@ public class JavaWrapOnTypingTest extends LightCodeInsightFixtureTestCase { " }\n" + "}\n"); } + + public void testWrapAtLineWithParameterHints() { + myFixture.configureByText(JavaFileType.INSTANCE, + "public class C {\n" + + " void m(int a, int b) {}\n" + + " void other() { m(1, 2); }\n" + + "}"); + myFixture.doHighlighting(); + myFixture.checkResultWithInlays("public class C {\n" + + " void m(int a, int b) {}\n" + + " void other() { m(1, 2); }\n" + + "}"); + + myFixture.getEditor().getSettings().setWrapWhenTypingReachesRightMargin(true); + myFixture.getEditor().getSettings().setRightMargin(30); + + myFixture.type(" "); + myFixture.checkResultWithInlays("public class C {\n" + + " void m(int a, int b) {}\n" + + " void other() { m(1, 2 ); }\n" + + "}"); + myFixture.type(" "); + myFixture.checkResultWithInlays("public class C {\n" + + " void m(int a, int b) {}\n" + + " void other() { m(1, 2 \n" + + " ); }\n" + + "}"); + } } diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java index 425f6317ffb0..817e8b7dbf01 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java @@ -1177,6 +1177,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testWriteDifferentFieldsDuplicate() throws Exception { + doDuplicatesTest(); + } + private void doTestDisabledParam() throws PrepareFailedException { final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); settings.ELSE_ON_NEW_LINE = true; diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java b/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java new file mode 100644 index 000000000000..4dccc099bd23 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java @@ -0,0 +1,129 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots.ui.configuration.actions; + +import com.intellij.ide.projectView.ProjectView; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.UnloadedModuleDescription; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TestDialog; +import com.intellij.testFramework.MapDataContext; +import com.intellij.testFramework.PlatformTestCase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author nik + */ +public class ModuleDeleteProviderTest extends PlatformTestCase { + @Override + public void setUp() throws Exception { + super.setUp(); + Messages.setTestDialog(TestDialog.OK); + } + + public void testSimple() { + createModule("a"); + assertNotNull(getModuleManager().findModuleByName("a")); + deleteModules("a"); + assertNull(getModuleManager().findModuleByName("a")); + } + + public void testDeleteDependency() { + Module a = createModule("a"); + Module b = createModule("b"); + ModuleRootModificationUtil.addDependency(a, b); + assertSameElements(ModuleRootManager.getInstance(a).getDependencyModuleNames(), "b"); + deleteModules("b"); + assertEmpty(ModuleRootManager.getInstance(a).getDependencyModuleNames()); + } + + public void testDeleteTwoModules() { + Module a = createModule("a"); + Module b = createModule("b"); + ModuleRootModificationUtil.addDependency(a, b); + ModuleRootModificationUtil.addDependency(myModule, a); + ModuleRootModificationUtil.addDependency(myModule, b); + assertSameElements(ModuleRootManager.getInstance(myModule).getDependencyModuleNames(), "a", "b"); + deleteModules("a", "b"); + assertNull(getModuleManager().findModuleByName("a")); + assertNull(getModuleManager().findModuleByName("b")); + assertEmpty(ModuleRootManager.getInstance(myModule).getDependencyModuleNames()); + } + + public void testUnloaded() { + createModule("a"); + getModuleManager().setUnloadedModules(Arrays.asList("a")); + assertNotNull(getModuleManager().getUnloadedModuleDescription("a")); + deleteModules("a"); + assertNull(getModuleManager().getUnloadedModuleDescription("a")); + } + + public void testDeleteDependencyOnUnloadedModule() { + Module a = createModule("a"); + Module b = createModule("b"); + ModuleRootModificationUtil.addDependency(a, b); + getModuleManager().setUnloadedModules(Arrays.asList("b")); + assertSameElements(ModuleRootManager.getInstance(a).getDependencyModuleNames(), "b"); + deleteModules("b"); + assertEmpty(ModuleRootManager.getInstance(a).getDependencyModuleNames()); + } + + public void testLoadedAndUnloadedModule() { + Module a = createModule("a"); + Module b = createModule("b"); + ModuleRootModificationUtil.addDependency(a, b); + ModuleRootModificationUtil.addDependency(myModule, a); + ModuleRootModificationUtil.addDependency(myModule, b); + getModuleManager().setUnloadedModules(Arrays.asList("a")); + assertSameElements(ModuleRootManager.getInstance(myModule).getDependencyModuleNames(), "a", "b"); + deleteModules("a", "b"); + assertNull(getModuleManager().findModuleByName("a")); + assertNull(getModuleManager().findModuleByName("b")); + assertEmpty(getModuleManager().getUnloadedModuleDescriptions()); + assertEmpty(ModuleRootManager.getInstance(myModule).getDependencyModuleNames()); + } + + private ModuleManager getModuleManager() { + return ModuleManager.getInstance(myProject); + } + + private void deleteModules(String... names) { + ModuleDeleteProvider provider = new ModuleDeleteProvider(); + MapDataContext dataContext = new MapDataContext(); + dataContext.put(CommonDataKeys.PROJECT, myProject); + List modules = new ArrayList<>(); + List unloaded = new ArrayList<>(); + for (String name : names) { + UnloadedModuleDescription description = getModuleManager().getUnloadedModuleDescription(name); + if (description != null) { + unloaded.add(description); + } + else { + Module module = getModuleManager().findModuleByName(name); + assertNotNull("Module " + name + " not found", module); + modules.add(module); + } + } + if (!modules.isEmpty()) { + dataContext.put(LangDataKeys.MODULE_CONTEXT_ARRAY, modules.toArray(Module.EMPTY_ARRAY)); + } + if (!unloaded.isEmpty()) { + dataContext.put(ProjectView.UNLOADED_MODULES_CONTEXT_KEY, unloaded); + } + assertTrue(provider.canDeleteElement(dataContext)); + provider.deleteElement(dataContext); + } + + @Override + public void tearDown() throws Exception { + Messages.setTestDialog(TestDialog.DEFAULT); + super.tearDown(); + } +} diff --git a/jps/model-serialization/src/com/intellij/openapi/application/PathMacroFilter.java b/jps/model-serialization/src/com/intellij/openapi/application/PathMacroFilter.java index f6beb95d4239..7d463bee9dc6 100644 --- a/jps/model-serialization/src/com/intellij/openapi/application/PathMacroFilter.java +++ b/jps/model-serialization/src/com/intellij/openapi/application/PathMacroFilter.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.application; import org.jdom.Attribute; @@ -34,7 +20,7 @@ public abstract class PathMacroFilter { return false; } - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { return false; } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java index 2211f06e6872..ebe2263a932c 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.jps.model.serialization; import com.intellij.openapi.diagnostic.Logger; @@ -57,7 +43,7 @@ public abstract class JpsLoaderBase { String fileName = serializer.getConfigFileName(); Path configFile = fileName == null ? defaultConfigFile : dir.resolve(fileName); Runnable timingLog = TimingLog.startActivity("loading: " + configFile.getFileName() + ":" + serializer.getComponentName()); - Element componentTag = JDomSerializationUtil.findComponent(loadRootElement(configFile), serializer.getComponentName()); + Element componentTag = loadComponentData(serializer, configFile); if (componentTag != null) { serializer.loadExtension(element, componentTag); } @@ -67,6 +53,11 @@ public abstract class JpsLoaderBase { timingLog.run(); } + @Nullable + private Element loadComponentData(@NotNull JpsElementExtensionSerializerBase serializer, Path configFile) { + return JDomSerializationUtil.findComponent(loadRootElement(configFile), serializer.getComponentName()); + } + /** * Returns null if file doesn't exist */ diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java index c975881354e5..73ae4db6bab1 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java @@ -110,6 +110,12 @@ public class JpsProjectLoader extends JpsLoaderBase { return dir.getParent().getFileName().toString(); } + @Nullable + @Override + protected Element loadRootElement(@NotNull Path file) { + return super.loadRootElement(file); + } + private void loadFromDirectory(@NotNull Path dir) { myProject.setName(getDirectoryBaseProjectName(dir)); Path defaultConfigFile = dir.resolve("misc.xml"); diff --git a/platform/analysis-impl/src/com/intellij/psi/search/PredefinedSearchScopeProvider.java b/platform/analysis-impl/src/com/intellij/psi/search/PredefinedSearchScopeProvider.java index b0a8e6e50446..1da60759d671 100644 --- a/platform/analysis-impl/src/com/intellij/psi/search/PredefinedSearchScopeProvider.java +++ b/platform/analysis-impl/src/com/intellij/psi/search/PredefinedSearchScopeProvider.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.search; import com.intellij.openapi.actionSystem.DataContext; diff --git a/platform/analysis-impl/src/com/intellij/psi/search/SearchScopeProvider.java b/platform/analysis-impl/src/com/intellij/psi/search/SearchScopeProvider.java new file mode 100644 index 000000000000..aedcbac7c864 --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/psi/search/SearchScopeProvider.java @@ -0,0 +1,16 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.psi.search; + +import com.intellij.openapi.extensions.ExtensionPointName; + +import java.util.List; + +public interface SearchScopeProvider { + ExtensionPointName EP = ExtensionPointName.create("com.intellij.searchScopesProvider"); + + /** + * General project scopes are added after 'Project', 'Everything' but before 'Production', 'Tests', etc. + * @see PredefinedSearchScopeProvider + */ + List getGeneralProjectScopes(); +} diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy index c575419504f4..5dbadc32fe8c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy @@ -222,10 +222,6 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder { } } - buildContext.ant.concat(destfile: "${unixDistPath}/bin/idea.properties", append: true) { - filelist(dir: "${buildContext.paths.communityHome}/platform/build-scripts/resources/linux/snap", files: "idea-snap.properties") - } - buildContext.ant.delete(quiet: true) { fileset(dir: "${unixDistPath}/bin") { include(name: "fsnotifier") diff --git a/platform/build-scripts/icons/src/org/jetbrains/intellij/build/images/util.kt b/platform/build-scripts/icons/src/org/jetbrains/intellij/build/images/util.kt index 1dcd5bdb3cd2..948410b9fea5 100644 --- a/platform/build-scripts/icons/src/org/jetbrains/intellij/build/images/util.kt +++ b/platform/build-scripts/icons/src/org/jetbrains/intellij/build/images/util.kt @@ -16,8 +16,9 @@ package org.jetbrains.intellij.build.images import com.intellij.openapi.util.text.StringUtil -import java.awt.* +import java.awt.Dimension import java.io.File +import javax.imageio.ImageIO internal val File.children: List get() = if (isDirectory) listFiles().toList() else emptyList() @@ -35,27 +36,12 @@ internal fun isIcon(file: File): Boolean { private fun isImage(name: String) = name.endsWith(".png") || name.endsWith(".gif") internal fun imageSize(file: File): Dimension? { - val image = loadImage(file) ?: return null + val image = ImageIO.read(file) ?: return null val width = image.getWidth(null) val height = image.getHeight(null) return Dimension(width, height) } -private fun loadImage(file: File): Image? { - val image = Toolkit.getDefaultToolkit().createImage(file.absolutePath) - if (!waitForImage(image)) return null - return image -} - -private fun waitForImage(image: Image?): Boolean { - if (image == null) return false - if (image.getWidth(null) > 0) return true - val mediaTracker = MediaTracker(object : Component() {}) - mediaTracker.addImage(image, 1) - mediaTracker.waitForID(1, 5000) - return !mediaTracker.isErrorID(1) -} - internal enum class ImageType(private val suffix: String) { BASIC(""), RETINA("@2x"), DARCULA("_dark"), RETINA_DARCULA("@2x_dark"); diff --git a/platform/build-scripts/resources/linux/snap/idea-snap.properties b/platform/build-scripts/resources/linux/snap/idea-snap.properties deleted file mode 100644 index 2afae5831d38..000000000000 --- a/platform/build-scripts/resources/linux/snap/idea-snap.properties +++ /dev/null @@ -1,6 +0,0 @@ - -#----------------------------------------------------------------------- -# Snap-specific properties -#----------------------------------------------------------------------- -idea.skip.desktop.entry.step=true -ide.no.platform.update=Snap diff --git a/platform/configuration-store-impl/src/ModuleStoreImpl.kt b/platform/configuration-store-impl/src/ModuleStoreImpl.kt index 37ef72ee11d6..3ddcd88e3ef3 100644 --- a/platform/configuration-store-impl/src/ModuleStoreImpl.kt +++ b/platform/configuration-store-impl/src/ModuleStoreImpl.kt @@ -36,7 +36,7 @@ private open class ModuleStoreImpl(module: Module, private val pathMacroManager: override fun getStorageSpecs(component: PersistentStateComponent, stateSpec: State, operation: StateStorageOperation): List { val result = super.getStorageSpecs(component, stateSpec, operation) return StreamProviderFactory.EP_NAME.getExtensions(project).computeIfAny { - LOG.runAndLogException { it.customizeStorageSpecs(component, storageManager.componentManager!!, result, operation) } + LOG.runAndLogException { it.customizeStorageSpecs(component, storageManager.componentManager!!, stateSpec, result, operation) } } ?: result } } diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index 8cbb8b9eb5f6..0aafad519394 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -201,7 +201,7 @@ abstract class ProjectStoreBase(override final val project: ProjectImpl) : Compo else { result!!.sortWith(deprecatedComparator) StreamProviderFactory.EP_NAME.getExtensions(project).computeIfAny { - LOG.runAndLogException { it.customizeStorageSpecs(component, project, result!!, operation) } + LOG.runAndLogException { it.customizeStorageSpecs(component, project, stateSpec, result!!, operation) } }?.let { // yes, DEPRECATED_PROJECT_FILE_STORAGE_ANNOTATION is not added in this case return it diff --git a/platform/configuration-store-impl/src/StateMap.kt b/platform/configuration-store-impl/src/StateMap.kt index 170c9045fb03..43d06f92c48f 100644 --- a/platform/configuration-store-impl/src/StateMap.kt +++ b/platform/configuration-store-impl/src/StateMap.kt @@ -130,16 +130,7 @@ class StateMap private constructor(private val names: Array, private val fun hasState(key: String) = get(key) is Element fun hasStates(): Boolean { - if (isEmpty()) { - return false - } - - for (i in names.indices) { - if (states.get(i) is Element) { - return true - } - } - return false + return !isEmpty() && names.indices.any { states.get(it) is Element } } fun compare(key: String, newStates: StateMap, diffs: MutableSet) { @@ -241,16 +232,5 @@ private fun arrayEquals(a: ByteArray, a2: ByteArray, size: Int = a.size): Boolea if (a === a2) { return true } - - if (a2.size != size) { - return false - } - - for (i in 0 until size) { - if (a[i] != a2[i]) { - return false - } - } - - return true + return a2.size == size && (0 until size).none { a[it] != a2[it] } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt index 98a1a70e7bab..3cc27b26aab7 100644 --- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -174,7 +174,14 @@ open class StateStorageManagerImpl(private val rootTagName: String, key = normalizedCollapsedPath } else { - key = storageClass.name!! + val storageClassName = storageClass.name!! + // we cannot change this ancient logic for now, so, detect this case manually + if (storageClassName === "com.intellij.openapi.externalSystem.configurationStore.ExternalProjectStorage") { + key = "$normalizedCollapsedPath@ExternalProjectStorage" + } + else { + key = storageClassName + } } val storage = storageLock.read { storages.get(key) } ?: return storageLock.write { diff --git a/platform/platform-api/src/com/intellij/util/graph/GraphAlgorithms.java b/platform/core-api/src/com/intellij/util/graph/GraphAlgorithms.java similarity index 74% rename from platform/platform-api/src/com/intellij/util/graph/GraphAlgorithms.java rename to platform/core-api/src/com/intellij/util/graph/GraphAlgorithms.java index 40b3064dc9db..6f9192fdfd46 100644 --- a/platform/platform-api/src/com/intellij/util/graph/GraphAlgorithms.java +++ b/platform/core-api/src/com/intellij/util/graph/GraphAlgorithms.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.graph; import com.intellij.openapi.components.ServiceManager; diff --git a/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java index 52f0935f19d1..b3c6b9adfdcc 100644 --- a/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.core; import com.intellij.codeInsight.folding.CodeFoldingSettings; @@ -66,6 +52,8 @@ import com.intellij.psi.stubs.CoreStubTreeLoader; import com.intellij.psi.stubs.StubTreeLoader; import com.intellij.util.Consumer; import com.intellij.util.Processor; +import com.intellij.util.graph.GraphAlgorithms; +import com.intellij.util.graph.impl.GraphAlgorithmsImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.picocontainer.MutablePicoContainer; @@ -126,12 +114,12 @@ public class CoreApplicationEnvironment { registerApplicationService(StubTreeLoader.class, new CoreStubTreeLoader()); registerApplicationService(PsiReferenceService.class, new PsiReferenceServiceImpl()); registerApplicationService(MetaDataRegistrar.class, new MetaRegistry()); - registerApplicationService(ProgressManager.class, createProgressIndicatorProvider()); - registerApplicationService(JobLauncher.class, createJobLauncher()); registerApplicationService(CodeFoldingSettings.class, new CodeFoldingSettings()); registerApplicationService(CommandProcessor.class, new CoreCommandProcessor()); + registerApplicationService(GraphAlgorithms.class, new GraphAlgorithmsImpl()); + myApplication.registerService(ApplicationInfo.class, ApplicationInfoImpl.class); } diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java b/platform/core-impl/src/com/intellij/util/graph/impl/CycleFinder.java similarity index 77% rename from platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java rename to platform/core-impl/src/com/intellij/util/graph/impl/CycleFinder.java index 8f71253c23ec..d9f0bcb10939 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java +++ b/platform/core-impl/src/com/intellij/util/graph/impl/CycleFinder.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.graph.impl; import com.intellij.util.containers.ContainerUtil; diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java b/platform/core-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java similarity index 86% rename from platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java rename to platform/core-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java index 18d9e3565997..397b905ab023 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java +++ b/platform/core-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.graph.impl; import com.intellij.openapi.progress.ProgressIndicator; diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/GraphEdge.java b/platform/core-impl/src/com/intellij/util/graph/impl/GraphEdge.java similarity index 59% rename from platform/platform-impl/src/com/intellij/util/graph/impl/GraphEdge.java rename to platform/core-impl/src/com/intellij/util/graph/impl/GraphEdge.java index d7f977f0a810..5b3354bb126f 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/GraphEdge.java +++ b/platform/core-impl/src/com/intellij/util/graph/impl/GraphEdge.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.graph.impl; import org.jetbrains.annotations.NotNull; diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/KShortestPathsFinder.java b/platform/core-impl/src/com/intellij/util/graph/impl/KShortestPathsFinder.java similarity index 94% rename from platform/platform-impl/src/com/intellij/util/graph/impl/KShortestPathsFinder.java rename to platform/core-impl/src/com/intellij/util/graph/impl/KShortestPathsFinder.java index d7527c991944..384f412bc024 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/KShortestPathsFinder.java +++ b/platform/core-impl/src/com/intellij/util/graph/impl/KShortestPathsFinder.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.graph.impl; import com.intellij.openapi.diagnostic.Logger; diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/ShortestPathFinder.java b/platform/core-impl/src/com/intellij/util/graph/impl/ShortestPathFinder.java similarity index 66% rename from platform/platform-impl/src/com/intellij/util/graph/impl/ShortestPathFinder.java rename to platform/core-impl/src/com/intellij/util/graph/impl/ShortestPathFinder.java index 1546ecd6f717..322b1e9e8479 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/ShortestPathFinder.java +++ b/platform/core-impl/src/com/intellij/util/graph/impl/ShortestPathFinder.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.graph.impl; import com.intellij.util.graph.Graph; diff --git a/platform/diff-impl/src/com/intellij/diff/contents/DocumentContentImpl.java b/platform/diff-impl/src/com/intellij/diff/contents/DocumentContentImpl.java index 077ea0b638b5..d36bdcd09a6f 100644 --- a/platform/diff-impl/src/com/intellij/diff/contents/DocumentContentImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/contents/DocumentContentImpl.java @@ -139,7 +139,9 @@ public class DocumentContentImpl extends DiffContentBase implements DocumentCont public void navigate(boolean requestFocus) { Document targetDocument = FileDocumentManager.getInstance().getDocument(myTargetFile); LineCol targetPosition = translatePosition(myDocument, targetDocument, myPosition); - OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, myTargetFile, targetPosition.line, targetPosition.column); + OpenFileDescriptor descriptor = targetDocument != null + ? new OpenFileDescriptor(myProject, myTargetFile, targetPosition.toOffset(targetDocument)) + : new OpenFileDescriptor(myProject, myTargetFile, targetPosition.line, targetPosition.column); if (descriptor.canNavigate()) descriptor.navigate(true); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt index 890e4102a600..24e40a1a3f52 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt @@ -33,12 +33,7 @@ internal open class ExternalProjectStorage(fileSpec: String, project: Project, s override fun createSaveSession(states: StateMap) = object : XmlElementStorageSaveSession(states, this) { override fun saveLocally(element: Element?) { - if (element == null) { - manager.fileStorage.remove(fileSpec) - } - else { - manager.fileStorage.write(fileSpec, element) - } + manager.fileStorage.write(fileSpec, element) } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStreamProviderFactory.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStreamProviderFactory.kt index c9f391121733..a455b5a6debe 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStreamProviderFactory.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStreamProviderFactory.kt @@ -63,7 +63,7 @@ internal class ExternalSystemStreamProviderFactory(private val project: Project) }) } - override fun customizeStorageSpecs(component: PersistentStateComponent<*>, componentManager: ComponentManager, storages: List, operation: StateStorageOperation): List? { + override fun customizeStorageSpecs(component: PersistentStateComponent<*>, componentManager: ComponentManager, stateSpec: State, storages: List, operation: StateStorageOperation): List? { val project = componentManager as? Project ?: (componentManager as Module).project // we store isExternalStorageEnabled option in the project workspace file, so, for such components external storage is always disabled and not applicable if ((storages.size == 1 && storages.first().value == StoragePathMacros.WORKSPACE_FILE) || !project.isExternalStorageEnabled) { @@ -94,14 +94,21 @@ internal class ExternalSystemStreamProviderFactory(private val project: Project) // so, we just add our storage as first and default storages in the end as fallback // on write default storages also returned, because default FileBasedStorage will remove data if component has external source - - val result = ArrayList(storages.size + 1) + val annotation: FileStorageAnnotation if (componentManager is Project) { - result.add(FileStorageAnnotation(storages.get(0).value, false, ExternalProjectStorage::class.java)) + val fileSpec = storages.get(0).value + annotation = FileStorageAnnotation(fileSpec, false, ExternalProjectStorage::class.java) } else { - result.add(EXTERNAL_MODULE_STORAGE_ANNOTATION) + annotation = EXTERNAL_MODULE_STORAGE_ANNOTATION } + + if (stateSpec.externalStorageOnly) { + return listOf(annotation) + } + + val result = ArrayList(storages.size + 1) + result.add(annotation) result.addAll(storages) return result } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemProcessHandler.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemProcessHandler.java index 4b9a65d0251c..8afa13aa2658 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemProcessHandler.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemProcessHandler.java @@ -105,6 +105,9 @@ public class ExternalSystemProcessHandler extends BuildProcessHandler implements } protected void closeInput() { + if (myTask instanceof UserDataHolder) { + ((UserDataHolder)myTask).putUserData(ExternalSystemRunConfiguration.RUN_INPUT_KEY, null); + } StreamUtil.closeStream(myProcessInput); myProcessInput = null; } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java index d6447c1e4619..6b5398f2b320 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java @@ -118,11 +118,6 @@ public class ExternalSystemResolveProjectTask extends AbstractExternalSystemTask return resolver.cancelTask(getId()); } - @Nullable - public DataNode getExternalProject() { - return myExternalProject.get(); - } - @Override @NotNull protected String wrapProgressText(@NotNull String text) { @@ -134,7 +129,7 @@ public class ExternalSystemResolveProjectTask extends AbstractExternalSystemTask super.setState(state); if (state.isStopped()) { InternalExternalProjectInfo projectInfo = - new InternalExternalProjectInfo(getExternalSystemId(), getExternalProjectPath(), getExternalProject()); + new InternalExternalProjectInfo(getExternalSystemId(), getExternalProjectPath(), myExternalProject.getAndSet(null)); final long currentTimeMillis = System.currentTimeMillis(); projectInfo.setLastImportTimestamp(currentTimeMillis); projectInfo.setLastSuccessfulImportTimestamp(state == ExternalSystemTaskState.FAILED ? -1 : currentTimeMillis); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java index 6ff668a87567..db8a40bf120e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java @@ -221,8 +221,13 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { public static void clearActions(Project project, Collection> taskData) { ActionManager actionManager = ActionManager.getInstance(); if (actionManager != null) { - for (DataNode each : taskData) { - for (String eachAction : actionManager.getActionIds(getActionPrefix(project, each.getData().getLinkedExternalProjectPath()))) { + Set externalProjectPaths = ContainerUtil.newHashSet(); + for (DataNode node : taskData) { + externalProjectPaths.add(node.getData().getLinkedExternalProjectPath()); + } + + for (String externalProjectPath : externalProjectPaths) { + for (String eachAction : actionManager.getActionIds(getActionPrefix(project, externalProjectPath))) { AnAction action = actionManager.getAction(eachAction); if (!(action instanceof ExternalSystemRunConfigurationAction)) { actionManager.unregisterAction(eachAction); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java index 50d9e4a9ad7d..e66dc30f5f28 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java @@ -23,7 +23,6 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.RootPolicy; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -145,7 +144,6 @@ public class LibraryDataService extends AbstractProjectDataService> toImport, @@ -157,15 +155,45 @@ public class LibraryDataService extends AbstractProjectDataService orphanIdeLibraries = ContainerUtil.newSmartList(); final LibraryTable.ModifiableModel librariesModel = modelsProvider.getModifiableProjectLibrariesModel(); + final Map namesToLibs = ContainerUtil.newHashMap(); + final Set potentialOrphans = ContainerUtil.newHashSet(); + RootPolicy excludeUsedLibraries = new RootPolicy() { + @Override + public Void visitLibraryOrderEntry(@NotNull LibraryOrderEntry ideDependency, Void value) { + if (ideDependency.isModuleLevel()) { + return null; + } + Library lib = ideDependency.getLibrary(); + if (lib == null) { + lib = namesToLibs.get(ideDependency.getLibraryName()); + } + if (lib != null) { + potentialOrphans.remove(lib); + } + return null; + } + }; + for (Library library : librariesModel.getLibraries()) { if (!ExternalSystemApiUtil.isExternalSystemLibrary(library, projectData.getOwner())) continue; - if (isOrphanProjectLibrary(library, modelsProvider) && !modelsProvider.isSubstituted(library.getName())) { - orphanIdeLibraries.add(library); + namesToLibs.put(library.getName(), library); + potentialOrphans.add(library); + } + + for (Module module : modelsProvider.getModules()) { + for (OrderEntry entry : modelsProvider.getOrderEntries(module)) { + entry.accept(excludeUsedLibraries, null); + } + } + + for (Library lib : potentialOrphans) { + if (!modelsProvider.isSubstituted(lib.getName())) { + orphanIdeLibraries.add(lib); } } @@ -220,22 +248,4 @@ public class LibraryDataService extends AbstractProjectDataService visitor = new RootPolicy() { - @Override - public Boolean visitLibraryOrderEntry(@NotNull LibraryOrderEntry ideDependency, Boolean value) { - return !ideDependency.isModuleLevel() && - (library == ideDependency.getLibrary() || - (ideDependency.getLibrary() == null && StringUtil.equals(library.getName(), ideDependency.getLibraryName()))); - } - }; - for (Module module : modelsProvider.getModules()) { - for (OrderEntry entry : modelsProvider.getOrderEntries(module)) { - if (entry.accept(visitor, false)) return false; - } - } - return true; - } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java index 731d8c23015b..99bd646b0784 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java @@ -275,7 +275,7 @@ public class ExternalSystemUtil { final ExternalProjectRefreshCallback callback; if (spec.getCallback() == null) { - callback = new MyMultiExternalProjectRefreshCallback(spec.getProject(), projectDataManager, spec.getExternalSystemId()); + callback = new MyMultiExternalProjectRefreshCallback(spec.getProject(), projectDataManager); } else { callback = spec.getCallback(); @@ -390,9 +390,10 @@ public class ExternalSystemUtil { else { projectName = projectFile.getName(); } + final ExternalSystemResolveProjectTask myTask = + new ExternalSystemResolveProjectTask(externalSystemId, project, externalProjectPath, vmOptions, arguments, isPreviewMode); + final TaskUnderProgress refreshProjectStructureTask = new TaskUnderProgress() { - private final ExternalSystemResolveProjectTask myTask - = new ExternalSystemResolveProjectTask(externalSystemId, project, externalProjectPath, vmOptions, arguments, isPreviewMode); @SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "IOResourceOpenedButNotSafelyClosed"}) @Override @@ -404,7 +405,7 @@ public class ExternalSystemUtil { @Override public void cancel() { super.cancel(); - cancellImport(); + cancelImport(); } }); } @@ -430,7 +431,7 @@ public class ExternalSystemUtil { final ExternalSystemProcessHandler processHandler = new ExternalSystemProcessHandler(myTask, projectName + " import") { @Override protected void destroyProcessImpl() { - cancellImport(); + cancelImport(); closeInput(); } }; @@ -442,7 +443,6 @@ public class ExternalSystemUtil { consoleManager.attachExecutionConsole(project, myTask, null, processHandler); if (consoleView != null) { Disposer.register(project, consoleView); - Disposer.register(consoleView, processHandler); } else { Disposer.register(project, processHandler); } @@ -529,11 +529,15 @@ public class ExternalSystemUtil { final Throwable error = myTask.getError(); if (error == null) { if (callback != null) { - DataNode externalProject = myTask.getExternalProject(); - if (externalProject != null && importSpec.shouldCreateDirectoriesForEmptyContentRoots()) { - externalProject.putUserData(ContentRootDataService.CREATE_EMPTY_DIRECTORIES, Boolean.TRUE); + final ExternalProjectInfo externalProjectData = ProjectDataManagerImpl.getInstance() + .getExternalProjectData(project, externalSystemId, externalProjectPath); + if (externalProjectData != null) { + DataNode externalProject = externalProjectData.getExternalProjectStructure(); + if (externalProject != null && importSpec.shouldCreateDirectoriesForEmptyContentRoots()) { + externalProject.putUserData(ContentRootDataService.CREATE_EMPTY_DIRECTORIES, Boolean.TRUE); + } + callback.onSuccess(externalProject); } - callback.onSuccess(externalProject); } if (!isPreviewMode) { externalSystemTaskActivator.runTasks(externalProjectPath, ExternalSystemTaskActivator.Phase.AFTER_SYNC); @@ -556,7 +560,7 @@ public class ExternalSystemUtil { } } - public void cancellImport() { + private void cancelImport() { myTask.cancel(ExternalSystemTaskNotificationListener.EP_NAME.getExtensions()); } }; @@ -1064,14 +1068,10 @@ public class ExternalSystemUtil { private final Set myExternalModulePaths; private final Project myProject; private final ProjectDataManager myProjectDataManager; - private final ProjectSystemId myExternalSystemId; - public MyMultiExternalProjectRefreshCallback(Project project, - ProjectDataManager projectDataManager, - ProjectSystemId externalSystemId) { + public MyMultiExternalProjectRefreshCallback(Project project, ProjectDataManager projectDataManager) { myProject = project; myProjectDataManager = projectDataManager; - myExternalSystemId = externalSystemId; myExternalModulePaths = ContainerUtilRt.newHashSet(); } diff --git a/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java b/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java index a81e17937966..e1e141747e51 100644 --- a/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java +++ b/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java @@ -57,6 +57,8 @@ public interface RunDashboardManager { void createToolWindowContent(@NotNull ToolWindow toolWindow); + void updateDashboard(boolean withSStructure); + List> getRunConfigurations(); boolean isShowConfigurations(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java index bfb0665a8254..b77feee795d2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.editorActions; import com.intellij.codeInsight.template.TemplateManager; @@ -118,8 +104,8 @@ public class AutoHardWrapHandler { return; } - VisualPosition visEndLinePosition = editor.offsetToVisualPosition(endOffset); - if (margin >= visEndLinePosition.column) { + LogicalPosition logEndLinePosition = editor.offsetToLogicalPosition(endOffset); + if (margin >= logEndLinePosition.column) { if (change != null) { change.modificationStamp = document.getModificationStamp(); } @@ -159,9 +145,9 @@ public class AutoHardWrapHandler { change.update(editor); // Is assumed to be max possible number of characters inserted on the visual line with caret. - int maxPreferredOffset = editor.logicalPositionToOffset(editor.visualToLogicalPosition( - new VisualPosition(caretModel.getVisualPosition().line, margin - FormatConstants.getReservedLineWrapWidthInColumns(editor)) - )); + int maxPreferredOffset = editor.logicalPositionToOffset( + new LogicalPosition(caretModel.getLogicalPosition().line, margin - FormatConstants.getReservedLineWrapWidthInColumns(editor)) + ); int wrapOffset = strategy.calculateWrapPosition(document, project, startOffset, endOffset, maxPreferredOffset, true, false); if (wrapOffset < 0) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java index 6933bfef1306..f867c5ea679d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java @@ -1045,7 +1045,14 @@ public class CtrlMouseHandler extends AbstractProjectComponent { for (AbstractDocumentationTooltipAction action : ourTooltipActions) { Icon icon = action.getTemplatePresentation().getIcon(); Dimension minSize = new Dimension(icon.getIconWidth(), icon.getIconHeight()); - myButtons.add(new ActionButton(action, presentationFactory.getPresentation(action), IdeTooltipManager.IDE_TOOLTIP_PLACE, minSize)); + ActionButton actionButton = + new ActionButton(action, presentationFactory.getPresentation(action), IdeTooltipManager.IDE_TOOLTIP_PLACE, minSize) { + @Override + protected boolean checkSkipPressForEvent(@NotNull MouseEvent e) { + return e.getButton() != MouseEvent.BUTTON1; + } + }; + myButtons.add(actionButton); action.setDocInfo(documentationAnchor, elementUnderMouse); } Collections.reverse(myButtons); diff --git a/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java b/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java index 19399e0156c3..1a640094b3cb 100644 --- a/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java +++ b/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.execution.configuration; import com.intellij.openapi.application.PathMacroFilter; @@ -26,7 +12,7 @@ import org.jetbrains.annotations.NotNull; class RunConfigurationPathMacroFilter extends PathMacroFilter { @Override public boolean skipPathMacros(@NotNull Attribute attribute) { - return attribute.getParent().getName().equals("configuration") && attribute.getName().equals("name"); + return attribute.getName().equals("name") && attribute.getParent().getName().equals("configuration"); } @Override diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java index 69708551cf83..9b44e58a8bd4 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java @@ -140,21 +140,7 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab myContentManagerListener = new ContentManagerAdapter() { @Override public void contentAdded(ContentManagerEvent event) { - Content content = event.getContent(); - RunContentDescriptor descriptor = RunContentManagerImpl.getRunContentDescriptorByContent(content); - if (descriptor == null) { - return; - } - RunnerLayoutUi layoutUi = descriptor.getRunnerLayoutUi(); - if (!(layoutUi instanceof RunnerLayoutUiImpl)) { - return; - } - RunnerLayoutUiImpl layoutUiImpl = (RunnerLayoutUiImpl)layoutUi; - layoutUiImpl.setLeftToolbarVisible(false); - layoutUiImpl.setContentToolbarBefore(false); - List leftToolbarActions = layoutUiImpl.getActions(); - myContentActions.put(content, leftToolbarActions); - updateContentToolbar(content); + onContentAdded(event.getContent()); } @Override @@ -172,17 +158,9 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab if (ContentManagerEvent.ContentOperation.add != event.getOperation()) { return; } - contentAdded(event); - myBuilder.queueUpdate().doWhenDone(() -> myBuilder.accept(RunDashboardNode.class, new TreeVisitor() { - @Override - public boolean visit(@NotNull RunDashboardNode node) { - if (node.getContent() == event.getContent()) { - myBuilder.select(node); - } - return false; - } - })); - showContentPanel(); + Content content = event.getContent(); + onContentAdded(content); + onContentSelectionChanged(content); } }; myContentManager.addContentManagerListener(myContentManagerListener); @@ -261,6 +239,16 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true); setTreeVisible(dashboardManager.isShowConfigurations()); + + // RunDashboardContent may be initialized when some contents have been already added to content manager. + // Process already added content. + for (Content content : myContentManager.getContents()) { + onContentAdded(content); + } + Content selectedContent = myContentManager.getSelectedContent(); + if (selectedContent != null) { + onContentSelectionChanged(selectedContent); + } } private void setTreeVisible(boolean visible) { @@ -331,6 +319,36 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab showMessagePanel(ExecutionBundle.message("run.dashboard.empty.selection.message")); } + private void onContentAdded(Content content) { + RunContentDescriptor descriptor = RunContentManagerImpl.getRunContentDescriptorByContent(content); + if (descriptor == null) { + return; + } + RunnerLayoutUi layoutUi = descriptor.getRunnerLayoutUi(); + if (!(layoutUi instanceof RunnerLayoutUiImpl)) { + return; + } + RunnerLayoutUiImpl layoutUiImpl = (RunnerLayoutUiImpl)layoutUi; + layoutUiImpl.setLeftToolbarVisible(false); + layoutUiImpl.setContentToolbarBefore(false); + List leftToolbarActions = layoutUiImpl.getActions(); + myContentActions.put(content, leftToolbarActions); + updateContentToolbar(content); + } + + private void onContentSelectionChanged(Content content) { + myBuilder.queueUpdate().doWhenDone(() -> myBuilder.accept(RunDashboardNode.class, new TreeVisitor() { + @Override + public boolean visit(@NotNull RunDashboardNode node) { + if (node.getContent() == content) { + myBuilder.select(node); + } + return false; + } + })); + showContentPanel(); + } + private void showMessagePanel(String text) { Content selectedContent = myContentManager.getSelectedContent(); if (selectedContent != null) { diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java index 8e580bc8578a..e8cee4905041 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java @@ -53,6 +53,7 @@ import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; /** @@ -71,6 +72,7 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS @NotNull private final Set myTypes = ContainerUtil.newHashSet(); @NotNull private final List myGroupers; @NotNull private final Condition myReuseCondition; + @NotNull private final AtomicBoolean myListenersInitialized = new AtomicBoolean(); private boolean myShowConfigurations = true; private float myContentProportion = DEFAULT_CONTENT_PROPORTION; @@ -94,18 +96,17 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS .sorted(RunDashboardGroupingRule.PRIORITY_COMPARATOR) .map(RunDashboardGrouper::new) .collect(Collectors.toList()); - - if (isDashboardEnabled()) { - addRunConfigurationListener(); - } } private static boolean isDashboardEnabled() { return Registry.is("ide.run.dashboard"); } - private void addRunConfigurationListener() { - myProject.getMessageBus().connect(myProject).subscribe(RunManagerListener.TOPIC, new RunManagerListener() { + private void initToolWindowContentListeners() { + if (!myListenersInitialized.compareAndSet(false, true)) return; + + MessageBusConnection connection = myProject.getMessageBus().connect(myProject); + connection.subscribe(RunManagerListener.TOPIC, new RunManagerListener() { private volatile boolean myUpdateStarted; @Override @@ -140,10 +141,6 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS updateDashboard(true); } }); - } - - private void initToolWindowContentListeners() { - MessageBusConnection connection = myProject.getMessageBus().connect(myProject); connection.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionListener() { @Override public void processStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env, final @NotNull ProcessHandler handler) { @@ -225,8 +222,6 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS myToolWindowContentManager.addContent(myToolWindowContent); myToolWindowContentManagerListener = new ToolWindowContentManagerListener(); - - initToolWindowContentListeners(); } @Override @@ -317,6 +312,9 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS public void setTypes(@NotNull Set types) { myTypes.clear(); myTypes.addAll(types); + if (!myTypes.isEmpty()) { + initToolWindowContentListeners(); + } updateDashboard(true); } @@ -363,7 +361,8 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS }); } - private void updateDashboard(final boolean withStructure) { + @Override + public void updateDashboard(final boolean withStructure) { final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); if (toolWindowManager == null) return; @@ -376,8 +375,11 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS boolean available = hasContent(); ToolWindow toolWindow = toolWindowManager.getToolWindow(getToolWindowId()); if (toolWindow == null) { + if (!myTypes.isEmpty() || available) { + toolWindow = createToolWindow(toolWindowManager, available); + } if (available) { - createToolWindow(toolWindowManager).show(null); + toolWindow.show(null); } return; } @@ -395,10 +397,11 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS }); } - private ToolWindow createToolWindow(ToolWindowManager toolWindowManager) { + private ToolWindow createToolWindow(ToolWindowManager toolWindowManager, boolean available) { ToolWindow toolWindow = toolWindowManager.registerToolWindow(getToolWindowId(), true, ToolWindowAnchor.BOTTOM, myProject, true); toolWindow.setIcon(getToolWindowIcon()); + toolWindow.setAvailable(available, null); createToolWindowContent(toolWindow); return toolWindow; } @@ -495,6 +498,9 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS public void loadState(State state) { myTypes.clear(); myTypes.addAll(state.configurationTypes); + if (!myTypes.isEmpty()) { + initToolWindowContentListeners(); + } state.ruleStates.forEach(ruleState -> { for (RunDashboardGrouper grouper : myGroupers) { if (grouper.getRule().getName().equals(ruleState.name) && !grouper.getRule().isAlwaysEnabled()) { diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java index 6a7fb2f88ce4..ed77163662d0 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java @@ -28,6 +28,11 @@ import org.jetbrains.annotations.NotNull; public class RunDashboardToolWindowFactory implements ToolWindowFactory, Condition, DumbAware { @Override public boolean value(Project project) { + return !RunDashboardManager.getInstance(project).getTypes().isEmpty(); + } + + @Override + public boolean shouldBeAvailable(@NotNull Project project) { return RunDashboardManager.getInstance(project).isToolWindowAvailable(); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java index 8d8323823af7..53a08c1ed692 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java @@ -162,7 +162,15 @@ extends BeforeRunTaskProvider> UNLOADED_MODULES_CONTEXT_KEY = DataKey.create("context.unloaded.modules.list"); + public static ProjectView getInstance(Project project) { return ServiceManager.getService(project, ProjectView.class); } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java index 03e43d8fc8d4..b8393940daea 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java @@ -28,6 +28,8 @@ import org.jetbrains.annotations.NotNull; import javax.swing.tree.DefaultMutableTreeNode; +import static com.intellij.util.ObjectUtils.notNull; + public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdapter { private final PsiModificationTracker myModificationTracker; private long myOutOfCodeBlockModificationCount; @@ -105,7 +107,7 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap break; } - if (addSubtreeToUpdateByElement(parent)) { + if (addSubtreeToUpdateByElementFile(parent)) { break; } @@ -122,8 +124,8 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap addSubtreeToUpdateByRoot(); } else if (propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)){ - if (!addSubtreeToUpdateByElement(element) && element instanceof PsiFile) { - addSubtreeToUpdateByElement(((PsiFile)element).getContainingDirectory()); + if (!addSubtreeToUpdateByElementFile(element) && element instanceof PsiFile) { + addSubtreeToUpdateByElementFile(((PsiFile)element).getContainingDirectory()); } } else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_NAME) || propertyName.equals(PsiTreeChangeEvent.PROP_DIRECTORY_NAME)){ @@ -132,11 +134,11 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap return; } final PsiElement parent = element.getParent(); - if (parent == null || !addSubtreeToUpdateByElement(parent)) { - addSubtreeToUpdateByElement(element); + if (parent == null || !addSubtreeToUpdateByElementFile(parent)) { + addSubtreeToUpdateByElementFile(element); } } - else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_TYPES)){ + else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_TYPES) || propertyName.equals(PsiTreeChangeEvent.PROP_UNLOADED_PSI)) { addSubtreeToUpdateByRoot(); } } @@ -151,4 +153,8 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap AbstractTreeUpdater updater = getUpdater(); return updater != null && updater.addSubtreeToUpdateByElement(element); } + + private boolean addSubtreeToUpdateByElementFile(PsiElement element) { + return element != null && addSubtreeToUpdateByElement(notNull(element.getContainingFile(), element)); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index 9240f2c3a1af..7a27af4cdcab 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -1,22 +1,9 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.projectView.impl; import com.intellij.ide.DataManager; +import com.intellij.ide.IdeBundle; import com.intellij.ide.PsiCopyPasteManager; import com.intellij.ide.SelectInTarget; import com.intellij.ide.dnd.*; @@ -72,11 +59,8 @@ import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.image.BufferedImage; import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.*; import java.util.List; -import java.util.Map; public abstract class AbstractProjectViewPane implements DataProvider, Disposable, BusyObject { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.projectViewPane"); @@ -159,6 +143,10 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl public boolean supportsManualOrder() { return false; } + + protected String getManualOrderOptionText() { + return IdeBundle.message("action.manual.order"); + } /** * @return all supported sub views IDs. diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 68de580e2ef9..369121f0a6ee 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.projectView.impl; @@ -51,7 +37,9 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.module.UnloadedModuleDescription; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; @@ -87,6 +75,7 @@ import com.intellij.ui.tree.TreeVisitor; import com.intellij.util.ArrayUtil; import com.intellij.util.IJSwingUtilities; import com.intellij.util.PlatformIcons; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.JBIterable; import com.intellij.util.messages.MessageBusConnection; @@ -1104,7 +1093,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo } if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) { final Module[] modules = getSelectedModules(); - if (modules != null) { + if (modules != null || !getSelectedUnloadedModules().isEmpty()) { return myDeleteModuleProvider; } final LibraryOrderEntry orderEntry = getSelectedLibrary(); @@ -1152,6 +1141,9 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo if (LangDataKeys.MODULE_CONTEXT_ARRAY.is(dataId)) { return getSelectedModules(); } + if (UNLOADED_MODULES_CONTEXT_KEY.is(dataId)) { + return Collections.unmodifiableList(getSelectedUnloadedModules()); + } if (ModuleGroup.ARRAY_DATA_KEY.is(dataId)) { final List selectedElements = getSelectedElements(ModuleGroup.class); return selectedElements.isEmpty() ? null : selectedElements.toArray(new ModuleGroup[selectedElements.size()]); @@ -1165,6 +1157,11 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return selectedElements.isEmpty() ? null : selectedElements.toArray(new NamedLibraryElement[selectedElements.size()]); } + if (PlatformDataKeys.SELECTED_ITEMS.is(dataId)) { + final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); + return viewPane == null ? null : viewPane.getSelectedElements(); + } + if (QuickActionProvider.KEY.is(dataId)) { return ProjectViewImpl.this; } @@ -1260,6 +1257,21 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return result.toArray(new Module[result.size()]); } } + + private List getSelectedUnloadedModules() { + final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); + if (viewPane == null) return Collections.emptyList(); + List result = new SmartList<>(); + for (Object element : viewPane.getSelectedElements()) { + if (element instanceof PsiDirectory) { + ContainerUtil.addIfNotNull(result, getUnloadedModuleByContentRoot(((PsiDirectory)element).getVirtualFile())); + } + else if (element instanceof VirtualFile) { + ContainerUtil.addIfNotNull(result, getUnloadedModuleByContentRoot((VirtualFile)element)); + } + } + return result; + } } /** Project view has the same node for module and its single content root @@ -1280,6 +1292,15 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return null; } + @Nullable + private UnloadedModuleDescription getUnloadedModuleByContentRoot(@NotNull VirtualFile file) { + String moduleName = ProjectRootsUtil.findUnloadedModuleByContentRoot(file, myProject); + if (moduleName != null) { + return ModuleManager.getInstance(myProject).getUnloadedModuleDescription(moduleName); + } + return null; + } + @NotNull private List getSelectedElements(@NotNull Class klass) { List result = new ArrayList<>(); @@ -1922,10 +1943,6 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo pane.installComparator(); } - protected String getManualOrderOptionText() { - return IdeBundle.message("action.manual.order"); - } - @Override public boolean isSortByType(String paneId) { return getPaneOptionValue(mySortByType, paneId, ourSortByTypeDefaults); @@ -1940,7 +1957,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo private class ManualOrderAction extends ToggleAction implements DumbAware { private ManualOrderAction() { - super(getManualOrderOptionText(), getManualOrderOptionText(), AllIcons.ObjectBrowser.Sorted); + super(IdeBundle.message("action.manual.order"), null, AllIcons.ObjectBrowser.Sorted); } @Override @@ -1958,7 +1975,13 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo super.update(e); final Presentation presentation = e.getPresentation(); AbstractProjectViewPane pane = getCurrentProjectViewPane(); - presentation.setEnabledAndVisible(pane != null && pane.supportsManualOrder()); + if (pane == null) { + presentation.setEnabledAndVisible(false); + } + else { + presentation.setEnabledAndVisible(pane.supportsManualOrder()); + presentation.setText(pane.getManualOrderOptionText()); + } } } diff --git a/platform/lang-impl/src/com/intellij/openapi/application/PathMappingsMacroFilter.java b/platform/lang-impl/src/com/intellij/openapi/application/PathMappingsMacroFilter.java index 6cebf1782001..ad4f555c4f22 100644 --- a/platform/lang-impl/src/com/intellij/openapi/application/PathMappingsMacroFilter.java +++ b/platform/lang-impl/src/com/intellij/openapi/application/PathMappingsMacroFilter.java @@ -1,22 +1,9 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.application; import org.jdom.Attribute; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; /** * Filter remote path in {@link com.intellij.util.PathMappingSettings.PathMapping} @@ -25,7 +12,7 @@ import org.jdom.Element; */ public class PathMappingsMacroFilter extends PathMacroFilter { @Override - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { final Element parent = attribute.getParent(); if ("mapping".equals(parent.getName()) && "remote-root".equals(attribute.getName())) { return true; diff --git a/platform/lang-impl/src/com/intellij/openapi/application/StructuralSearchPathMacroFilter.java b/platform/lang-impl/src/com/intellij/openapi/application/StructuralSearchPathMacroFilter.java index b42ba1701b31..23d6b0fe53f7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/application/StructuralSearchPathMacroFilter.java +++ b/platform/lang-impl/src/com/intellij/openapi/application/StructuralSearchPathMacroFilter.java @@ -1,21 +1,8 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.application; import org.jdom.Attribute; +import org.jetbrains.annotations.NotNull; /** * Since SSR inspections can be stored in inspection profiles and loaded by users who don't have the SSR plugin installed, unfortunately @@ -25,7 +12,7 @@ import org.jdom.Attribute; */ public class StructuralSearchPathMacroFilter extends PathMacroFilter { @Override - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { final String parentName = attribute.getParent().getName(); if ("replaceConfiguration".equals(parentName) || "searchConfiguration".equals(parentName)) { return true; diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProvider.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProvider.java index 9aabb14c1f5a..0f69824e17de 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProvider.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProvider.java @@ -18,14 +18,14 @@ package com.intellij.openapi.roots.ui.configuration.actions; import com.intellij.ide.DeleteProvider; import com.intellij.ide.TitledHandler; +import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.module.ModifiableModuleModel; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.*; +import com.intellij.openapi.module.impl.LoadedModuleDescriptionImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.ModifiableRootModel; @@ -37,22 +37,20 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; import com.intellij.project.ProjectKt; import com.intellij.projectImport.ProjectAttachProcessor; -import com.intellij.util.ArrayUtilRt; import com.intellij.util.PathUtilRt; import com.intellij.util.PlatformUtils; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; public class ModuleDeleteProvider implements DeleteProvider, TitledHandler { @Override public boolean canDeleteElement(@NotNull DataContext dataContext) { final Module[] modules = LangDataKeys.MODULE_CONTEXT_ARRAY.getData(dataContext); - return modules != null && !containsPrimaryModule(modules); + List unloadedModules = ProjectView.UNLOADED_MODULES_CONTEXT_KEY.getData(dataContext); + return modules != null && !containsPrimaryModule(modules) || unloadedModules != null && !unloadedModules.isEmpty(); } private static boolean containsPrimaryModule(Module[] modules) { @@ -77,12 +75,21 @@ public class ModuleDeleteProvider implements DeleteProvider, TitledHandler { @Override public void deleteElement(@NotNull DataContext dataContext) { - final Module[] modules = LangDataKeys.MODULE_CONTEXT_ARRAY.getData(dataContext); - assert modules != null; final Project project = CommonDataKeys.PROJECT.getData(dataContext); assert project != null; - String names = StringUtil.join(Arrays.asList(modules), module -> "\'" + module.getName() + "\'", ", "); - int ret = Messages.showOkCancelDialog(getConfirmationText(modules, names), getActionTitle(), Messages.getQuestionIcon()); + + List moduleDescriptions = new ArrayList<>(); + final Module[] modules = LangDataKeys.MODULE_CONTEXT_ARRAY.getData(dataContext); + if (modules != null) { + moduleDescriptions.addAll(ContainerUtil.map(modules, LoadedModuleDescriptionImpl::new)); + } + List unloadedModules = ProjectView.UNLOADED_MODULES_CONTEXT_KEY.getData(dataContext); + if (unloadedModules != null) { + moduleDescriptions.addAll(unloadedModules); + } + + String names = StringUtil.join(moduleDescriptions, description -> "\'" + description.getName() + "\'", ", "); + int ret = Messages.showOkCancelDialog(getConfirmationText(names, moduleDescriptions.size()), getActionTitle(), Messages.getQuestionIcon()); if (ret != Messages.OK) return; CommandProcessor.getInstance().executeCommand(project, () -> { final Runnable action = () -> { @@ -90,28 +97,33 @@ public class ModuleDeleteProvider implements DeleteProvider, TitledHandler { final Module[] currentModules = moduleManager.getModules(); final ModifiableModuleModel modifiableModuleModel = moduleManager.getModifiableModel(); final Map otherModuleRootModels = new HashMap<>(); - for (final Module module : modules) { - final ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel(); - for (final Module otherModule : currentModules) { - if (otherModule == module || ArrayUtilRt.find(modules, otherModule) != -1) continue; - if (!otherModuleRootModels.containsKey(otherModule)) { - otherModuleRootModels.put(otherModule, ModuleRootManager.getInstance(otherModule).getModifiableModel()); - } + Set moduleNamesToDelete = moduleDescriptions.stream().map(ModuleDescription::getName).collect(Collectors.toSet()); + for (final Module otherModule : currentModules) { + if (!moduleNamesToDelete.contains(otherModule.getName())) { + otherModuleRootModels.put(otherModule, ModuleRootManager.getInstance(otherModule).getModifiableModel()); + } + } + removeDependenciesOnModules(moduleNamesToDelete, otherModuleRootModels.values()); + if (modules != null) { + for (final Module module : modules) { + modifiableModuleModel.disposeModule(module); } - removeModule(module, modifiableModel, otherModuleRootModels.values(), modifiableModuleModel); } final ModifiableRootModel[] modifiableRootModels = otherModuleRootModels.values().toArray(new ModifiableRootModel[otherModuleRootModels.size()]); ModifiableModelCommitter.multiCommit(modifiableRootModels, modifiableModuleModel); + if (unloadedModules != null) { + moduleManager.removeUnloadedModules(unloadedModules); + } }; ApplicationManager.getApplication().runWriteAction(action); }, ProjectBundle.message("module.remove.command"), null); } - private static String getConfirmationText(Module[] modules, String names) { + private static String getConfirmationText(String names, int numberOfModules) { if (ProjectAttachProcessor.canAttachToProject()) { - return ProjectBundle.message("project.remove.confirmation.prompt", names, modules.length); + return ProjectBundle.message("project.remove.confirmation.prompt", names, numberOfModules); } - return ProjectBundle.message("module.remove.confirmation.prompt", names, modules.length); + return ProjectBundle.message("module.remove.confirmation.prompt", names, numberOfModules); } @Override @@ -120,26 +132,21 @@ public class ModuleDeleteProvider implements DeleteProvider, TitledHandler { } public static void removeModule(@NotNull final Module moduleToRemove, - @Nullable ModifiableRootModel modifiableRootModelToRemove, - @NotNull Collection otherModuleRootModels, - @NotNull final ModifiableModuleModel moduleModel) { - // remove all dependencies on the module that is about to be removed + @NotNull Collection otherModuleRootModels, + @NotNull final ModifiableModuleModel moduleModel) { + removeDependenciesOnModules(Collections.singleton(moduleToRemove.getName()), otherModuleRootModels); + moduleModel.disposeModule(moduleToRemove); + } + + private static void removeDependenciesOnModules(@NotNull Set moduleNamesToRemove, + @NotNull Collection otherModuleRootModels) { for (final ModifiableRootModel modifiableRootModel : otherModuleRootModels) { final OrderEntry[] orderEntries = modifiableRootModel.getOrderEntries(); for (final OrderEntry orderEntry : orderEntries) { - if (orderEntry instanceof ModuleOrderEntry && orderEntry.isValid()) { - final Module orderEntryModule = ((ModuleOrderEntry)orderEntry).getModule(); - if (orderEntryModule != null && orderEntryModule.equals(moduleToRemove)) { - modifiableRootModel.removeOrderEntry(orderEntry); - } + if (orderEntry instanceof ModuleOrderEntry && moduleNamesToRemove.contains(((ModuleOrderEntry)orderEntry).getModuleName())) { + modifiableRootModel.removeOrderEntry(orderEntry); } } } - // destroyProcess editor - if (modifiableRootModelToRemove != null) { - modifiableRootModelToRemove.dispose(); - } - // destroyProcess module - moduleModel.disposeModule(moduleToRemove); } } diff --git a/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java b/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java index 4471768a6531..10c4db661566 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.search; import com.intellij.ide.IdeBundle; @@ -27,6 +13,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.module.*; import com.intellij.openapi.project.Project; @@ -76,6 +63,10 @@ public class PredefinedSearchScopeProviderImpl extends PredefinedSearchScopeProv result.add(GlobalSearchScope.allScope(project)); } + for (SearchScopeProvider each : Extensions.getExtensions(SearchScopeProvider.EP, project)) { + result.addAll(each.getGeneralProjectScopes()); + } + if (ModuleUtil.isSupportedRootType(project, JavaSourceRootType.TEST_SOURCE)) { result.add(GlobalSearchScopesCore.projectProductionScope(project)); result.add(GlobalSearchScopesCore.projectTestScope(project)); diff --git a/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java b/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java index 3cae95375efc..d7ebd8f3115a 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java @@ -80,6 +80,11 @@ public class ToolEditorDialog extends DialogWrapper { private JBCheckBox myShowConsoleOnStdErrCheckbox; private RawCommandLineEditor myOutputFilterField; + @Nullable + public Project getProject() { + return myProject; + } + @Override @NotNull protected JPanel createCenterPanel() { diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java index 8f8401a476c1..6f253e8c88cd 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ui.tabs; @@ -29,7 +15,6 @@ import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.psi.search.scope.packageSet.PackageSet; import com.intellij.psi.search.scope.packageSet.PackageSetBase; import com.intellij.ui.ColorUtil; -import com.intellij.util.PlatformUtils; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import org.jdom.Element; @@ -49,65 +34,61 @@ import java.util.Map; public class FileColorsModel implements Cloneable { public static final String FILE_COLOR = "fileColor"; - private final List myApplicationLevelConfigurations; - private final List myProjectLevelConfigurations; - private static final Map predefinedScopeNameToPropertyKey; - private static final Map predefinedScopeNameToColor; - - static { - predefinedScopeNameToPropertyKey = new THashMap<>(); - predefinedScopeNameToPropertyKey.put(NonProjectFilesScope.NAME, "file.colors.enable.non.project"); - // These IDEs have TestScope registered (via PackagesScopesProvider or TestScopeProvider) - if (PlatformUtils.isIntelliJ() || PlatformUtils.isRubyMine() || PlatformUtils.isPhpStorm() || PlatformUtils.isWebStorm() || PlatformUtils.isGoIde()) { - predefinedScopeNameToPropertyKey.put(TestsScope.NAME, "file.colors.enable.tests"); - } - - predefinedScopeNameToColor = new THashMap<>(); - } + private final List myApplicationLevelConfigurations = new ArrayList<>(); + private final List myProjectLevelConfigurations = new ArrayList<>(); + private final Map myPredefinedScopeNameToPropertyKey = new THashMap<>(); + private final Map myPredefinedScopeNameToColor = new THashMap<>(); @NotNull private final Project myProject; FileColorsModel(@NotNull final Project project) { myProject = project; - myApplicationLevelConfigurations = new ArrayList<>(); - myProjectLevelConfigurations = new ArrayList<>(); - - if (predefinedScopeNameToColor.size() < predefinedScopeNameToPropertyKey.size()) { - DefaultScopesProvider defaultScopesProvider = DefaultScopesProvider.getInstance(project); - for (String scopeName : predefinedScopeNameToPropertyKey.keySet()) { - final NamedScope scope = defaultScopesProvider.findCustomScope(scopeName); - assert scope != null : "There is no custom scope with name " + scopeName; - final Color color = ColorUtil.getColor(scope.getClass()); - assert color != null : scope.getClass().getName() + " is not annotated with @Colored"; - final String colorName = FileColorManagerImpl.getColorName(color); - predefinedScopeNameToColor.put(scopeName, colorName == null ? ColorUtil.toHex(color) : colorName); - } - } - initGlobalScopes(); + initPredefinedAndGlobalScopes(); } private FileColorsModel(@NotNull Project project, @NotNull List applicationLevel, @NotNull List projectLevel) { myProject = project; - myApplicationLevelConfigurations = new ArrayList<>(); - myProjectLevelConfigurations = new ArrayList<>(); myApplicationLevelConfigurations.addAll(applicationLevel); myProjectLevelConfigurations.addAll(projectLevel); - initGlobalScopes(); + initPredefinedAndGlobalScopes(); } - private void initGlobalScopes() { + private void initPredefinedAndGlobalScopes() { + for (NamedScope scope : DefaultScopesProvider.getInstance(myProject).getAllCustomScopes()) { + String scopeName = scope.getName(); + + final Color color = ColorUtil.getColor(scope.getClass()); + if (color == null) continue; + String colorName = FileColorManagerImpl.getColorName(color); + + myPredefinedScopeNameToColor.put(scopeName, colorName == null ? ColorUtil.toHex(color) : colorName); + + String propertyKey; + if (NonProjectFilesScope.NAME.equals(scopeName)) { + propertyKey = "file.colors.enable.non.project"; + } + else if (TestsScope.NAME.equals(scopeName)) { + propertyKey = "file.colors.enable.tests"; + } + else { + propertyKey = "file.colors.enable.custom." + scopeName; + } + + myPredefinedScopeNameToPropertyKey.put(scopeName, propertyKey); + } + PropertiesComponent propertyComponent = PropertiesComponent.getInstance(); - for (String scopeName : predefinedScopeNameToPropertyKey.keySet()) { + for (String scopeName : myPredefinedScopeNameToPropertyKey.keySet()) { if (findConfiguration(scopeName, false) == null) { - String color = propertyComponent.getValue(predefinedScopeNameToPropertyKey.get(scopeName)); + String color = propertyComponent.getValue(myPredefinedScopeNameToPropertyKey.get(scopeName)); if (color == null) { // backward compatibility, previously it was saved incorrectly as scope name instead of specified property key color = propertyComponent.getValue(scopeName); if (color == null) { - color = predefinedScopeNameToColor.get(scopeName); + color = myPredefinedScopeNameToColor.get(scopeName); } } @@ -124,13 +105,13 @@ public class FileColorsModel implements Cloneable { List configurations = isProjectLevel ? myProjectLevelConfigurations : myApplicationLevelConfigurations; for (FileColorConfiguration configuration : configurations) { String scopeName = configuration.getScopeName(); - String propertyKey = isProjectLevel ? null : predefinedScopeNameToPropertyKey.get(scopeName); + String propertyKey = isProjectLevel ? null : myPredefinedScopeNameToPropertyKey.get(scopeName); if (propertyKey == null) { configuration.save(e); } else { PropertiesComponent propertyComponent = PropertiesComponent.getInstance(); - propertyComponent.setValue(propertyKey, configuration.getColorName(), predefinedScopeNameToColor.get(scopeName)); + propertyComponent.setValue(propertyKey, configuration.getColorName(), myPredefinedScopeNameToColor.get(scopeName)); // previously it was saved incorrectly as scope name instead of specified property key PropertiesComponent.getInstance().setValue(scopeName, null); } @@ -142,7 +123,7 @@ public class FileColorsModel implements Cloneable { configurations.clear(); - Map predefinedScopeNameToPropertyKey = new THashMap<>(FileColorsModel.predefinedScopeNameToPropertyKey); + Map predefinedScopeNameToPropertyKey = new THashMap<>(myPredefinedScopeNameToPropertyKey); for (Element child : e.getChildren(FILE_COLOR)) { FileColorConfiguration configuration = FileColorConfiguration.load(child); if (configuration != null) { @@ -163,7 +144,7 @@ public class FileColorsModel implements Cloneable { // so, default value if (colorName == null) { - colorName = predefinedScopeNameToColor.get(scopeName); + colorName = myPredefinedScopeNameToColor.get(scopeName); } } // empty means that value deleted @@ -282,7 +263,7 @@ public class FileColorsModel implements Cloneable { } else { myApplicationLevelConfigurations.clear(); - Map predefinedScopeNameToPropertyKey = new THashMap<>(FileColorsModel.predefinedScopeNameToPropertyKey); + Map predefinedScopeNameToPropertyKey = new THashMap<>(myPredefinedScopeNameToPropertyKey); PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); for (FileColorConfiguration configuration : configurations) { myApplicationLevelConfigurations.add(configuration); diff --git a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java index 8cf6ab30512a..84775ffbda6a 100644 --- a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java +++ b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java @@ -1,20 +1,19 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package com.intellij.execution.util; +import com.intellij.execution.CommandLineUtil; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.CapturingProcessHandler; @@ -93,7 +92,7 @@ public class ExecUtil { @NotNull public static String getWindowsShellName() { - return SystemInfo.isWin2kOrNewer ? "cmd.exe" : "command.com"; + return CommandLineUtil.getWinShellName(); } @NotNull diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 85e6cbc2f50d..bf57059bc5ce 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -1790,7 +1790,7 @@ public class AbstractTreeUi { @Override public void perform() { if (!pass.isExpired()) { - queueUpdate(node); + queueUpdate(getElementFor(node)); } } }); diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java index 6bc25b8d46c3..681823348df0 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java @@ -49,10 +49,14 @@ import java.beans.PropertyChangeListener; public abstract class ComboBoxAction extends AnAction implements CustomComponentAction { private static Icon myIcon = null; private static Icon myDisabledIcon = null; + private static Icon myWin10ComboDropTriagleIcon = null; public static Icon getArrowIcon(boolean enabled) { if (UIUtil.isUnderWin10LookAndFeel()) { - return IconLoader.getIcon("/com/intellij/ide/ui/laf/icons/win10/comboDropTriangle.png"); + if (myWin10ComboDropTriagleIcon == null) { + myWin10ComboDropTriagleIcon = IconLoader.getIcon("/com/intellij/ide/ui/laf/icons/win10/comboDropTriangle.png"); + } + return myWin10ComboDropTriagleIcon; } Icon icon = UIUtil.isUnderDarcula() ? AllIcons.General.ComboArrow : AllIcons.General.ComboBoxButtonArrow; if (myIcon != icon) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/CreateDesktopEntryAction.java b/platform/platform-impl/src/com/intellij/ide/actions/CreateDesktopEntryAction.java index 36eef3cbf1e1..320d6d44734b 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/CreateDesktopEntryAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/CreateDesktopEntryAction.java @@ -76,7 +76,7 @@ public class CreateDesktopEntryAction extends DumbAwareAction { }; public static boolean isAvailable() { - return SystemInfo.isUnix && SystemInfo.hasXdgOpen(); + return SystemInfo.isUnix && !SystemInfo.isSnap() && SystemInfo.hasXdgOpen(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java b/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java index f82b02a3b5d1..fe6f09eca668 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java @@ -51,7 +51,7 @@ public class CreateLauncherScriptAction extends DumbAwareAction { private static final String CONTENTS = "/Contents"; public static boolean isAvailable() { - return SystemInfo.isUnix; + return SystemInfo.isUnix && !SystemInfo.isSnap(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowFilePathAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowFilePathAction.java index e6ccccc56b94..9b890d48a20b 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ShowFilePathAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowFilePathAction.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions; import com.intellij.execution.ExecutionException; @@ -283,9 +269,9 @@ public class ShowFilePathAction extends AnAction { String toSelect = _toSelect != null ? FileUtil.toSystemDependentName(FileUtil.toCanonicalPath(_toSelect.getPath())) : null; if (SystemInfo.isWindows) { - String cmd = toSelect != null ? "explorer /select," + toSelect : "explorer /root," + dir; + String cmd = toSelect != null ? "explorer /select,\"" + toSelect + '"' : "explorer /root,\"" + dir + '"'; LOG.debug(cmd); - Process process = Runtime.getRuntime().exec(cmd); // no quoting/escaping is needed + Process process = Runtime.getRuntime().exec(cmd); // no advanced quoting/escaping is needed new CapturingProcessHandler(process, null, cmd).runProcess().checkSuccess(LOG); } else if (SystemInfo.isMac) { diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java index 7e61b5893ae4..e721a9ab3199 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java @@ -20,6 +20,7 @@ import com.intellij.idea.ActionsBundle; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.SystemInfo; import com.intellij.util.ExceptionUtil; import com.intellij.util.ui.GridBag; import com.intellij.util.ui.UIUtil; diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java index dc05cf0e68d3..8424eac3cfaf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java @@ -30,8 +30,8 @@ import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ui.*; -import com.intellij.util.ui.accessibility.ScreenReader; import com.intellij.util.ui.accessibility.AccessibleContextUtil; +import com.intellij.util.ui.accessibility.ScreenReader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -337,7 +337,7 @@ public class ActionButton extends JComponent implements ActionButtonComponent, A protected void processMouseEvent(MouseEvent e) { super.processMouseEvent(e); if (e.isConsumed()) return; - boolean skipPress = e.isMetaDown() || e.getButton() != MouseEvent.BUTTON1; + boolean skipPress = checkSkipPressForEvent(e); switch (e.getID()) { case MouseEvent.MOUSE_PRESSED: if (skipPress || !isButtonEnabled()) return; @@ -372,6 +372,10 @@ public class ActionButton extends JComponent implements ActionButtonComponent, A } } + protected boolean checkSkipPressForEvent(@NotNull MouseEvent e) { + return e.isMetaDown() || e.getButton() != MouseEvent.BUTTON1; + } + private int getPopState(boolean isPushed) { if (isPushed || myRollover && myMouseDown && isButtonEnabled()) { return PUSHED; diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java index 29e34ff3a776..e90e15905f02 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java @@ -18,6 +18,7 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.components.*; import com.intellij.openapi.updateSettings.UpdateStrategyCustomization; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -65,7 +66,7 @@ public class UpdateSettings implements PersistentStateComponent= 0) { + FSRecords.NameId[] persistentIds = FSRecords.listAll(id); + for (FSRecords.NameId nameId : persistentIds) { + existingNames.add(nameId.name); + } } validateAgainst(childrenToCreate, existingNames); diff --git a/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java b/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java index b6a990871620..74edbe5e6437 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java @@ -205,11 +205,12 @@ public class StructureTreeModel extends AbstractTreeModel implements Disposable, Object element = structure.getRootElement(); if (!isValid(element)) return null; - Node node = root.get(); - boolean leaf = structure.isAlwaysLeaf(element); - if (node == null || leaf == node.getAllowsChildren() || !element.equals(node.getElement())) node = new Node(leaf); - node.update(structure.createDescriptor(element, null)); - return node; + Node newNode = new Node(structure, element, null); // an exception may be thrown while getting a root + Node oldNode = root.get(); + if (oldNode != null && oldNode.canReuse(newNode, element)) { + return oldNode; // reuse old node with possible children + } + return newNode; } private List getValidChildren(@NotNull Node node) { @@ -225,32 +226,37 @@ public class StructureTreeModel extends AbstractTreeModel implements Disposable, Object[] elements = structure.getChildElements(parent); if (elements == null || elements.length == 0) return null; + List list = new ArrayList<>(elements.length); + for (Object element : elements) { + if (isValid(element)) { + list.add(new Node(structure, element, descriptor)); // an exception may be thrown while getting children + } + } + Comparator comparator = this.comparator; + if (comparator != null) list.sort(comparator); // an exception may be thrown while sorting children + HashMap map = new HashMap<>(); node.getChildren().forEach(child -> { Object element = child.getElement(); if (element != null) map.put(element, child); }); - List list = new ArrayList<>(elements.length); - for (Object element : elements) { - if (isValid(element)) { - Node child = map.get(element); - boolean leaf = structure.isAlwaysLeaf(element); - if (child == null || leaf == child.getAllowsChildren()) child = new Node(leaf); - child.update(structure.createDescriptor(element, descriptor)); - list.add(child); + for (int i = 0; i < list.size(); i++) { + Node newNode = list.get(i); + Node oldNode = map.get(newNode.getElement()); + if (oldNode != null && oldNode.canReuse(newNode, null)) { + list.set(i, oldNode); // reuse old node with possible children } } - Comparator comparator = this.comparator; - if (comparator != null) list.sort(comparator); return list; } private static final class Node extends DefaultMutableTreeNode { private final Reference> children = new Reference<>(); - private Node(boolean leaf) { - super(null, !leaf); - if (leaf) children.set(null); + private Node(@NotNull AbstractTreeStructure structure, Object element, NodeDescriptor parent) { + super(structure.createDescriptor(element, parent), !structure.isAlwaysLeaf(element)); + if (!getAllowsChildren()) children.set(null); // validate children for leaf node + update(); // an exception may be thrown while updating } private void dispose() { @@ -259,9 +265,11 @@ public class StructureTreeModel extends AbstractTreeModel implements Disposable, if (list != null) list.forEach(Node::dispose); } - private void update(@NotNull NodeDescriptor descriptor) { - descriptor.update(); - super.userObject = descriptor; + private boolean canReuse(@NotNull Node node, Object element) { + if (super.allowsChildren != node.allowsChildren) return false; + if (element != null && !element.equals(getElement())) return false; + super.userObject = node.userObject; // replace old descriptor + return true; } private boolean update() { diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 41cee2c5356e..970491cb8ef0 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -258,6 +258,7 @@ + diff --git a/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java b/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java index 92a689e7a731..9bebe47437ba 100644 --- a/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.run; import com.intellij.application.options.PathMacrosCollector; @@ -23,6 +9,7 @@ import junit.framework.TestCase; import org.jdom.Attribute; import org.jdom.Element; import org.jdom.Text; +import org.jetbrains.annotations.NotNull; import java.util.Set; @@ -78,7 +65,7 @@ public class PathMacrosCollectorTest extends TestCase { final Set filtered = PathMacrosCollector.getMacroNames(root, new PathMacroFilter() { @Override - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { return "ignore".equals(attribute.getName()); } }, new PathMacrosImpl()); diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/State.java b/platform/projectModel-api/src/com/intellij/openapi/components/State.java index 1e59be363c5f..456a17d2edd2 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/State.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/State.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.components; import com.intellij.openapi.util.Getter; @@ -60,6 +46,11 @@ public @interface State { Class presentableName() default NameGetter.class; + /** + * Is this component intended to store data only in the external storage. + */ + boolean externalStorageOnly() default false; + abstract class NameGetter implements Getter { } } diff --git a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.java b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.java index 8b51b206c968..8a8028d91252 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.java +++ b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.java @@ -194,4 +194,8 @@ public abstract class ModuleManager extends SimpleModificationTracker { */ @ApiStatus.Experimental public abstract void setUnloadedModules(@NotNull List unloadedModuleNames); + + @ApiStatus.Experimental + public void removeUnloadedModules(@NotNull Collection unloadedModules) { + } } diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/StreamProviderFactory.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/StreamProviderFactory.kt index 86675c12dbdd..226bf230936b 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/StreamProviderFactory.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/StreamProviderFactory.kt @@ -1,24 +1,7 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.configurationStore -import com.intellij.openapi.components.ComponentManager -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.StateStorageOperation -import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.* import com.intellij.openapi.extensions.ExtensionPointName /** @@ -38,5 +21,5 @@ interface StreamProviderFactory { * `storages` are preprocessed by component store - not raw from state spec. * @return null if not applicable */ - fun customizeStorageSpecs(component: PersistentStateComponent<*>, componentManager: ComponentManager, storages: List, operation: StateStorageOperation): List? = null + fun customizeStorageSpecs(component: PersistentStateComponent<*>, componentManager: ComponentManager, stateSpec: State, storages: List, operation: StateStorageOperation): List? = null } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java b/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java index 93bd2a16f317..32a68da8ee2f 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.components; import com.intellij.openapi.application.PathMacroFilter; @@ -50,9 +36,11 @@ public class CompositePathMacroFilter extends PathMacroFilter { } @Override - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { for (PathMacroFilter filter : myFilters) { - if (filter.skipPathMacros(attribute)) return true; + if (filter.skipPathMacros(attribute)) { + return true; + } } return false; } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt b/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt index a2e67b6bfc73..7b41113790a3 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt @@ -57,4 +57,7 @@ class EmptyModuleManager(project: Project, messageBus: MessageBus) : ModuleManag override fun getUnloadedModuleDescriptions() = emptyList() override fun getUnloadedModuleDescription(moduleName: String) = null + + override fun removeUnloadedModules(unloadedModules: MutableCollection) { + } } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt index 2509f15e7528..285fcc567962 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt @@ -12,7 +12,7 @@ import com.intellij.openapi.roots.ProjectModelElement import com.intellij.openapi.roots.ProjectModelExternalSource import org.jdom.Element -@State(name = "ExternalModuleListStorage", storages = arrayOf(Storage("modules.xml"))) +@State(name = "ExternalModuleListStorage", storages = arrayOf(Storage("modules.xml")), externalStorageOnly = true) internal class ExternalModuleListStorage(private val project: Project) : PersistentStateComponent, ProjectModelElement { var loadedState: Set? = null private set diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java index 03f40655d69a..56f073da061d 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java @@ -1068,6 +1068,15 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Disposa myModulePathsToLoad.clear(); } + @Override + public void removeUnloadedModules(@NotNull Collection unloadedModules) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + for (UnloadedModuleDescription module : unloadedModules) { + myUnloadedModules.remove(module.getName()); + } + setUnloadedModuleNames(new ArrayList<>(myUnloadedModules.keySet())); + } + protected void setUnloadedModuleNames(@NotNull List unloadedModuleNames) { UnloadedModulesListStorage.getInstance(myProject).setUnloadedModuleNames(unloadedModuleNames); } diff --git a/platform/testFramework/src/_FirstInSuiteTest.java b/platform/testFramework/src/_FirstInSuiteTest.java index b647ec1ec25c..042bab53e35d 100644 --- a/platform/testFramework/src/_FirstInSuiteTest.java +++ b/platform/testFramework/src/_FirstInSuiteTest.java @@ -64,6 +64,7 @@ public class _FirstInSuiteTest extends TestCase { // some tests do not initialize Application but want to use parallel streams IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool(); System.out.println("ForkJoinPool.commonPool: " + ForkJoinPool.commonPool()); + System.out.println("cpu cores: " + Runtime.getRuntime().availableProcessors()); suiteStarted = System.nanoTime(); diff --git a/platform/testFramework/src/_LastInSuiteTest.java b/platform/testFramework/src/_LastInSuiteTest.java index a8bcc62057fd..0264fba0d9e5 100644 --- a/platform/testFramework/src/_LastInSuiteTest.java +++ b/platform/testFramework/src/_LastInSuiteTest.java @@ -27,7 +27,7 @@ import junit.framework.TestCase; import java.util.concurrent.TimeUnit; import static com.intellij.testFramework.PlatformTestUtil.captureMemorySnapshot; -import static com.intellij.testFramework.PlatformTestUtil.disposeApplicationAndStopNonDaemonThreads; +import static com.intellij.testFramework.PlatformTestUtil.disposeApplicationAndCheckForProjectLeaks; /** * This must be the last test. @@ -60,7 +60,7 @@ public class _LastInSuiteTest extends TestCase { return; } - disposeApplicationAndStopNonDaemonThreads(); + disposeApplicationAndCheckForProjectLeaks(); try { Disposer.assertIsEmpty(true); diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java index 283070291809..23b6c94811c8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java @@ -1090,7 +1090,11 @@ public class PlatformTestUtil { ourProjectCleanups.clear(); } - public static void disposeApplicationAndStopNonDaemonThreads() { + /** + * Disposes the application (it also stops some application-related threads) + * and checks for project leaks. + */ + public static void disposeApplicationAndCheckForProjectLeaks() { EdtTestUtil.runInEdtAndWait(() -> { try { LightPlatformTestCase.initApplication(); // in case nobody cared to init. LightPlatformTestCase.disposeApplication() would not work otherwise. diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt index e9d08705934a..6749b0afd88b 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt @@ -65,6 +65,8 @@ import java.util.concurrent.TimeUnit class GuiTestRule : TestRule { + var CREATE_NEW_PROJECT_ACTION_NAME = "Create New Project" + private val myRobotTestRule = RobotTestRule() private val myFatalErrorsFlusher = FatalErrorsFlusher() private var myProjectPath: File? = null @@ -156,12 +158,12 @@ class GuiTestRule : TestRule { } private fun returnToTheFirstStepOfWelcomeFrame() { - val welcomeFrameFixture = WelcomeFrameFixture.find(robot()); + val welcomeFrameFixture = WelcomeFrameFixture.find(robot()) val tenSec = org.fest.swing.timing.Timeout.timeout(10, TimeUnit.SECONDS) fun isFirstStep(): Boolean { return try { - val actionLinkFixture = ActionLinkFixture.findActionLinkByName("Create New Project", robot(), welcomeFrameFixture.target(), tenSec) + val actionLinkFixture = ActionLinkFixture.findActionLinkByName(CREATE_NEW_PROJECT_ACTION_NAME, robot(), welcomeFrameFixture.target(), tenSec) actionLinkFixture.target().isShowing } catch (componentLookupException: ComponentLookupException) { false diff --git a/platform/util-rt/src/com/intellij/util/ReadEnv.java b/platform/util-rt/src/com/intellij/util/ReadEnv.java new file mode 100644 index 000000000000..391bd5eafb97 --- /dev/null +++ b/platform/util-rt/src/com/intellij/util/ReadEnv.java @@ -0,0 +1,33 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.util; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.Map; + +public class ReadEnv { + public static void main(String[] args) throws Exception { + if (args.length != 1) throw new Exception("Exactly one argument expected"); + + Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(args[0]), "UTF-8")); + try { + for (Map.Entry each : System.getenv().entrySet()) { + // on Windows Java getenv() includes variables that start from '='. + // These variables are not available available in normal command environment. + + // https://stackoverflow.com/questions/30102750/java-system-getenv-environment-names-starting-with + if (each.getKey().startsWith("=")) continue; + + out.write(each.getKey()); + out.write("="); + out.write(each.getValue()); + out.write("\0"); + } + } + finally { + out.close(); + } + } +} diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 44f21f1ed344..60d48f5055d2 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -368,6 +368,8 @@ debugger.keep.step.requests=false debugger.enable.memory.view=true debugger.enable.overhead.monitor=true debugger.tree.states.depth=100 +debugger.populate.exception.stack=true +debugger.populate.exception.stack.description=Automatically fill exception's stacktrace by calling getStackTrace analyze.exceptions.on.the.fly=false analyze.exceptions.on.the.fly.description=Automatically analyze clipboard on frame activation,\ @@ -1060,9 +1062,6 @@ cidr.indexer.thread.count.description=Number of CPU cores which will be used to how many cores should NOT be involved, e.g. "0" equals to "use every available CPU core", "-1" means "use every core but one". cidr.max.intellisense.file.length=500000 cidr.max.intellisense.file.length.description=Maximum length of C-based language file (in characters) IDE should provide code assistance for. -clion.enable.msvc=false -clion.enable.msvc.description=Experimental MSVC compiler support.\n\ - Please submit feedback and issues in https://youtrack.jetbrains.com/issue/CPP-819 ide.window.shadow.painter=false ide.window.shadow.painter.restartRequired=true diff --git a/platform/util/src/com/intellij/execution/CommandLineUtil.java b/platform/util/src/com/intellij/execution/CommandLineUtil.java index 91942b726eeb..1513665ca7c9 100644 --- a/platform/util/src/com/intellij/execution/CommandLineUtil.java +++ b/platform/util/src/com/intellij/execution/CommandLineUtil.java @@ -1,18 +1,16 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package com.intellij.execution; import com.intellij.openapi.diagnostic.Logger; @@ -421,6 +419,11 @@ public class CommandLineUtil { return numTrailingBackslashes / 2; } + + @NotNull + public static String getWinShellName() { + return "cmd.exe"; + } private static boolean isWinShell(String command) { return "cmd".equalsIgnoreCase(command) || "cmd.exe".equalsIgnoreCase(command); diff --git a/platform/util/src/com/intellij/openapi/util/SystemInfo.java b/platform/util/src/com/intellij/openapi/util/SystemInfo.java index 1fba851eea0b..f2ea2f4bcb56 100644 --- a/platform/util/src/com/intellij/openapi/util/SystemInfo.java +++ b/platform/util/src/com/intellij/openapi/util/SystemInfo.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.util; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.PathExecLazyValue; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ObjectUtils; @@ -71,6 +72,17 @@ public class SystemInfo extends SystemInfoRt { /* https://userbase.kde.org/KDE_System_Administration/Environment_Variables#KDE_FULL_SESSION */ public static final boolean isKDE = isXWindow && !StringUtil.isEmpty(System.getenv("KDE_FULL_SESSION")); + private static final NotNullLazyValue ourIsSnap = new AtomicNotNullLazyValue() { + @NotNull + @Override + protected Boolean compute() { + return PathManager.getHomePath().startsWith("/snap/"); + } + }; + public static boolean isSnap() { + return isLinux && ourIsSnap.getValue(); + } + public static final boolean isMacSystemMenu = isMac && "true".equals(System.getProperty("apple.laf.useScreenMenuBar")); public static final boolean isFileSystemCaseSensitive = SystemInfoRt.isFileSystemCaseSensitive; diff --git a/platform/util/src/com/intellij/util/EnvironmentUtil.java b/platform/util/src/com/intellij/util/EnvironmentUtil.java index 4872757931ae..55e9a9bd2977 100644 --- a/platform/util/src/com/intellij/util/EnvironmentUtil.java +++ b/platform/util/src/com/intellij/util/EnvironmentUtil.java @@ -1,25 +1,25 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package com.intellij.util; +import com.intellij.execution.CommandLineUtil; import com.intellij.execution.process.UnixProcessManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -34,7 +34,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -import java.io.*; +import java.io.File; +import java.io.InputStream; import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.Callable; @@ -161,8 +162,11 @@ public class EnvironmentUtil { public static class ShellEnvReader { - public Map readShellEnv() throws Exception { + return readShellEnv(null); + } + + protected Map readShellEnv(@Nullable Map additionalEnvironment) throws Exception { File reader = PathManager.findBinFileWithException("printenv.py"); File envFile = FileUtil.createTempFile("intellij-shell-env.", ".tmp", false); @@ -180,7 +184,34 @@ public class EnvironmentUtil { LOG.info("loading shell env: " + StringUtil.join(command, " ")); - return dumpProcessEnvToFile(command, envFile, "\0"); + return runProcessAndReadOutputAndEnvs(command, null, additionalEnvironment, envFile).second; + } + finally { + FileUtil.delete(envFile); + } + } + + @NotNull + public Map readBatEnv(@NotNull File batchFile, List args) throws Exception { + return readBatOutputAndEnv(batchFile, args).second; + } + + @NotNull + protected Pair> readBatOutputAndEnv(@NotNull File batchFile, List args) throws Exception { + File envFile = FileUtil.createTempFile("intellij-cmd-env.", ".tmp", false); + try { + List cl = new ArrayList(); + cl.add(CommandLineUtil.getWinShellName()); + cl.add("/c"); + cl.add("call"); + cl.add(batchFile.getPath()); + cl.addAll(args); + cl.add("&&"); + cl.addAll(getReadEnvCommand()); + cl.add(envFile.getPath()); + cl.addAll(Arrays.asList("||", "exit", "/B", "%ERRORLEVEL%")); + + return runProcessAndReadOutputAndEnvs(cl, batchFile.getParentFile(), null, envFile); } finally { FileUtil.delete(envFile); @@ -188,35 +219,21 @@ public class EnvironmentUtil { } @NotNull - protected Map dumpProcessEnvToFile(@NotNull List command, @NotNull File envFile, String lineSeparator) - throws Exception { - return runProcessAndReadEnvs(command, envFile, lineSeparator); + private static List getReadEnvCommand() { + return Arrays.asList(FileUtil.toSystemDependentName(System.getProperty("java.home") + "/bin/java"), + "-cp", PathManager.getJarPathForClass(ReadEnv.class), + ReadEnv.class.getCanonicalName()); } @NotNull - protected static Map runProcessAndReadEnvs(@NotNull List command, @NotNull File envFile, String lineSeparator) - throws Exception { - return runProcessAndReadEnvs(command, null, envFile, lineSeparator); - } - - @NotNull - protected static Map runProcessAndReadEnvs(@NotNull List command, - @Nullable File workingDir, - @NotNull File envFile, - String lineSeparator) throws Exception { - return runProcessAndReadEnvs(command, workingDir, null, envFile, lineSeparator); - } - - @NotNull - protected static Map runProcessAndReadEnvs(@NotNull List command, - @Nullable File workingDir, - @Nullable Map envs, - @NotNull File envFile, - String lineSeparator) throws Exception { + protected static Pair> runProcessAndReadOutputAndEnvs(@NotNull List command, + @Nullable File workingDir, + @Nullable Map scriptEnvironment, + @NotNull File envFile) throws Exception { ProcessBuilder builder = new ProcessBuilder(command).redirectErrorStream(true); - if (envs != null) { + if (scriptEnvironment != null) { // we might need default environment for the process to launch correctly - builder.environment().putAll(envs); + builder.environment().putAll(scriptEnvironment); } if (workingDir != null) builder.directory(workingDir); builder.environment().put(DISABLE_OMZ_AUTO_UPDATE, "true"); @@ -230,7 +247,7 @@ public class EnvironmentUtil { if (rv != 0 || lines.isEmpty()) { throw new Exception("rv:" + rv + " text:" + lines.length() + " out:" + StringUtil.trimEnd(gobbler.getText(), '\n')); } - return parseEnv(lines, lineSeparator); + return Pair.create(gobbler.getText(), parseEnv(lines)); } @NotNull @@ -250,18 +267,18 @@ public class EnvironmentUtil { } @Nullable - protected String getShell() throws Exception { + protected String getShell() { return System.getenv("SHELL"); } } @NotNull - private static Map parseEnv(String text, String lineSeparator) throws Exception { + private static Map parseEnv(String text) throws Exception { Set toIgnore = new HashSet(Arrays.asList("_", "PWD", "SHLVL", DISABLE_OMZ_AUTO_UPDATE, INTELLIJ_ENVIRONMENT_READER)); Map env = System.getenv(); Map newEnv = new HashMap(); - String[] lines = text.split(lineSeparator); + String[] lines = text.split("\0"); for (String line : lines) { int pos = line.indexOf('='); if (pos <= 0) { @@ -390,7 +407,7 @@ public class EnvironmentUtil { @TestOnly static Map testParser(@NotNull String lines) { try { - return parseEnv(lines, "\0"); + return parseEnv(lines); } catch (Exception e) { throw new RuntimeException(e); diff --git a/platform/util/src/com/intellij/util/lang/ClassPath.java b/platform/util/src/com/intellij/util/lang/ClassPath.java index 03a76797f817..e9dc13257636 100644 --- a/platform/util/src/com/intellij/util/lang/ClassPath.java +++ b/platform/util/src/com/intellij/util/lang/ClassPath.java @@ -266,19 +266,16 @@ public class ClassPath { List loaders = null; if (myCanUseCache && myAllUrlsWereProcessed) { - boolean nameIsDirectory = name.endsWith("/"); - Collection loadersSet = nameIsDirectory ? new SmartList() : new LinkedHashSet(); + Collection loadersSet = new LinkedHashSet(); myCache.iterateLoaders(name, ourLoaderCollector, loadersSet, this); - if (!nameIsDirectory) { + if (name.endsWith("/")) { + myCache.iterateLoaders(name.substring(0, name.length() - 1), ourLoaderCollector, loadersSet, this); + } else { myCache.iterateLoaders(name.concat("/"), ourLoaderCollector, loadersSet, this); } - if (nameIsDirectory) { - loaders = (List)loadersSet; - } else { - loaders = new ArrayList(loadersSet); - } + loaders = new ArrayList(loadersSet); } myLoaders = loaders; diff --git a/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java b/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java index 4d51cb94a75f..17afc9565792 100644 --- a/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java @@ -1,23 +1,12 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; import org.junit.Test; +import java.io.File; +import java.util.Arrays; import java.util.Map; import static org.junit.Assert.*; @@ -63,4 +52,32 @@ public class EnvironmentUtilTest { Map env = EnvironmentUtil.testLoader(); assertTrue(env.size() >= System.getenv().size() / 2); } + + @Test(timeout = 30000) + public void loadingBatEnv() throws Exception { + assumeTrue(SystemInfo.isWindows); + + File file = FileUtil.createTempFile("test", ".bat", true); + FileUtil.writeToFile(file, "set FOO_TEST_1=123\r\nset FOO_TEST_2=%1"); + + Map result = new EnvironmentUtil.ShellEnvReader().readBatEnv(file, Arrays.asList("arg_value")); + assertEquals("123", result.get("FOO_TEST_1")); + assertEquals("arg_value", result.get("FOO_TEST_2")); + } + + @Test(timeout = 30000) + public void loadingBatEnv_ErrorHandling() throws Exception { + assumeTrue(SystemInfo.isWindows); + + File file = FileUtil.createTempFile("test", ".bat", true); + FileUtil.writeToFile(file, "echo some error\r\nexit /B 1"); + + try { + new EnvironmentUtil.ShellEnvReader().readBatEnv(file, Arrays.asList()); + fail("error should be reported"); + } + catch (Exception e) { + assertTrue(e.getMessage(), e.getMessage().contains("some error")); + } + } } \ No newline at end of file diff --git a/platform/util/testSrc/com/intellij/util/lang/UrlClassLoaderTest.java b/platform/util/testSrc/com/intellij/util/lang/UrlClassLoaderTest.java index 89c5e664636c..fd3cd2a2f56b 100644 --- a/platform/util/testSrc/com/intellij/util/lang/UrlClassLoaderTest.java +++ b/platform/util/testSrc/com/intellij/util/lang/UrlClassLoaderTest.java @@ -17,8 +17,7 @@ package com.intellij.util.lang; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.ConcurrencyUtil; -import com.intellij.util.ObjectUtils; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import org.junit.Test; @@ -218,4 +217,43 @@ public class UrlClassLoaderTest { return loader.findResource(name); } } + + @Test + public void testFindDirWhenUsingCache() throws IOException { + int counter = 1; + for (String dirName : new String[]{ "dir", "dir/", "dir.class", "dir.class/"}) { + for(String resourceName: new String[] {"a.class", "a.txt"} ) { + File root = FileUtil.createTempDirectory("testFindDirWhenUsingCache", String.valueOf(counter++)); + File subDir = createTestDir(root, dirName); + createTestFile(subDir, resourceName); + + URL url = root.toURI().toURL(); + URLClassLoader standardCl = new URLClassLoader(new URL[] {url}); + + try { + Enumeration resources = standardCl.findResources(dirName); + assertTrue(resources.hasMoreElements()); + URL expectedResourceUrl = resources.nextElement(); + + withCustomCachedClassloader(url, (customCl) -> { + assertNull(customCl.findResource("SomeNonExistentResource.resource")); + checkResourceUrlIsTheSame(customCl, dirName, expectedResourceUrl); + }); + withCustomCachedClassloader(url, (customCl) -> checkResourceUrlIsTheSame(customCl, dirName, expectedResourceUrl)); + } finally { + standardCl.close(); + } + } + } + } + + private static void checkResourceUrlIsTheSame(UrlClassLoader customCl, String resourceName, URL expectedResourceUrl) throws IOException { + Enumeration customClResources = customCl.findResources(resourceName); + assertTrue(customClResources.hasMoreElements()); + assertEquals(expectedResourceUrl, customClResources.nextElement()); + } + + private static void withCustomCachedClassloader(URL url, ThrowableConsumer testAction) throws IOException { + testAction.consume(UrlClassLoader.build().useCache().urls(url).get()); + } } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java index 04f52d7d6ee8..cfe26ff4f52e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java @@ -1,30 +1,17 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vcs; import com.intellij.openapi.application.PathMacroFilter; import org.jdom.Attribute; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; /** * @author yole */ public class VcsPathMacroFilter extends PathMacroFilter { @Override - public boolean skipPathMacros(Attribute attribute) { + public boolean skipPathMacros(@NotNull Attribute attribute) { final Element parent = attribute.getParent(); final String parentName = parent.getName(); if ("MESSAGE".equals(parentName) && "value".equals(attribute.getName())) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java index 7e6aaf943b8c..e50481143208 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java @@ -127,7 +127,7 @@ public class XLightBreakpointPropertiesPanel implements XSuspendPolicyPanel.Dele if (debuggerEditorsProvider != null) { myConditionEnabledCheckbox = new JBCheckBox(XDebuggerBundle.message("xbreakpoints.condition.checkbox")); myConditionComboBox = new XDebuggerExpressionComboBox(project, debuggerEditorsProvider, CONDITION_HISTORY_ID, - myBreakpoint.getSourcePosition(), true, true); + myBreakpoint.getSourcePosition(), true, false); myLanguageChooserPanel.add(myConditionComboBox.getLanguageChooser(), BorderLayout.CENTER); myConditionExpressionPanel.add(myConditionComboBox.getComponent(), BorderLayout.CENTER); myConditionEnabledCheckbox.addActionListener(e -> onCheckboxChanged()); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java index 1ae06c2ea7e9..422634bf7897 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java @@ -1,35 +1,11 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.xdebugger.impl.evaluate; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.FixedSizeButton; -import com.intellij.openapi.ui.popup.PopupStep; -import com.intellij.openapi.ui.popup.util.BaseListPopupStep; -import com.intellij.ui.ColoredListCellRenderer; import com.intellij.ui.components.JBLabel; -import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.components.BorderLayoutPanel; @@ -37,23 +13,19 @@ import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; -import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase; -import com.intellij.xdebugger.impl.ui.XDebuggerExpressionEditor; +import com.intellij.xdebugger.impl.ui.XDebuggerExpressionComboBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.List; /** * @author nik */ public class ExpressionInputComponent extends EvaluationInputComponent { - private final XDebuggerExpressionEditor myExpressionEditor; + private final XDebuggerEditorBase myExpressionEditor; private final ExpressionInputForm myMainForm = new ExpressionInputForm(); public ExpressionInputComponent(final @NotNull Project project, @@ -65,25 +37,13 @@ public class ExpressionInputComponent extends EvaluationInputComponent { boolean showHelp) { super(XDebuggerBundle.message("xdebugger.dialog.title.evaluate.expression")); BorderLayoutPanel expressionPanel = JBUI.Panels.simplePanel(); - //myMainPanel.add(new JLabel(XDebuggerBundle.message("xdebugger.evaluate.label.expression")), BorderLayout.WEST); - myExpressionEditor = new XDebuggerExpressionEditor(project, editorsProvider, historyId, sourcePosition, - expression != null ? expression : XExpressionImpl.EMPTY_EXPRESSION, false, true, true) { + myExpressionEditor = new XDebuggerExpressionComboBox(project, editorsProvider, historyId, sourcePosition, true, false) { @Override - protected JComponent decorate(JComponent component, boolean multiline, boolean showEditor) { - return component; + protected void prepareEditor(Editor editor) { } }; + myExpressionEditor.setExpression(expression); expressionPanel.addToCenter(myExpressionEditor.getComponent()); - JButton historyButton = new FixedSizeButton(myExpressionEditor.getComponent()); - historyButton.setIcon(AllIcons.General.MessageHistory); - historyButton.setToolTipText(XDebuggerBundle.message("xdebugger.evaluate.history.hint")); - historyButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showHistory(); - } - }); - expressionPanel.addToRight(myExpressionEditor.addExpand(historyButton)); final JBLabel help = new JBLabel(XDebuggerBundle.message("xdebugger.evaluate.addtowatches.hint", KeymapUtil.getKeystrokeText(XDebuggerEvaluationDialog.ADD_WATCH_KEYSTROKE)), SwingConstants.RIGHT); @@ -95,44 +55,6 @@ public class ExpressionInputComponent extends EvaluationInputComponent { myMainForm.addExpressionComponent(expressionPanel); myMainForm.addLanguageComponent(myExpressionEditor.getLanguageChooser()); - - new AnAction("XEvaluateDialog.ShowHistory") { - @Override - public void actionPerformed(AnActionEvent e) { - showHistory(); - } - - @Override - public void update(AnActionEvent e) { - e.getPresentation().setEnabled(LookupManager.getActiveLookup(myExpressionEditor.getEditor()) == null); - } - }.registerCustomShortcutSet(CustomShortcutSet.fromString("DOWN"), myMainForm.getMainPanel(), parentDisposable); - } - - private void showHistory() { - List expressions = myExpressionEditor.getRecentExpressions(); - if (!expressions.isEmpty()) { - ListPopupImpl popup = new ListPopupImpl(new BaseListPopupStep(null, expressions) { - @Override - public PopupStep onChosen(XExpression selectedValue, boolean finalChoice) { - myExpressionEditor.setExpression(selectedValue); - myExpressionEditor.requestFocusInEditor(); - return FINAL_CHOICE; - } - }) { - @Override - protected ListCellRenderer getListElementRenderer() { - return new ColoredListCellRenderer() { - @Override - protected void customizeCellRenderer(@NotNull JList list, XExpression value, int index, boolean selected, boolean hasFocus) { - append(value.getExpression()); - } - }; - } - }; - popup.getList().setFont(EditorUtil.getEditorFont()); - popup.showUnderneathOf(myExpressionEditor.getEditorComponent()); - } } @Override diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java index 7e0a22875b50..8c5e1ed92531 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.xdebugger.impl.ui; import com.intellij.icons.AllIcons; @@ -185,7 +171,7 @@ public abstract class XDebuggerEditorBase implements Expandable { panel.add(factoryPanel, BorderLayout.WEST); if (!multiline && showEditor) { - component = addExpand(component); + component = addExpand(component, false); } panel.addToCenter(component); @@ -207,12 +193,20 @@ public abstract class XDebuggerEditorBase implements Expandable { return panel; } - public JComponent addExpand(JComponent component) { - BorderLayoutPanel panel = new BorderLayoutPanel() { - @Override public Color getBackground() { - return component.getBackground(); - } - }; + protected JComponent addExpand(JComponent component, boolean inheritBackground) { + BorderLayoutPanel panel; + if (inheritBackground) { + panel = new BorderLayoutPanel() { + @Override + public Color getBackground() { + return component.getBackground(); + } + }; + } + else { + panel = JBUI.Panels.simplePanel(); + panel.setOpaque(false); + } panel.addToCenter(component); panel.addToRight(myExpandButton); return panel; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java index 8053ebe38b47..869a6be6ab28 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.xdebugger.impl.ui; import com.intellij.openapi.editor.Document; @@ -212,7 +198,7 @@ public class XDebuggerExpressionComboBox extends XDebuggerEditorBase { comp = addChooser(comp); } if (showMultiline) { - comp = addExpand(comp); + comp = addExpand(comp, true); } myPanel = comp; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/TreeInplaceEditor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/TreeInplaceEditor.java index 1cf8615c519e..fb39b171553e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/TreeInplaceEditor.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/TreeInplaceEditor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.xdebugger.impl.ui.tree; import com.intellij.codeInsight.lookup.LookupManager; @@ -271,7 +257,7 @@ public abstract class TreeInplaceEditor implements AWTEventListener { } if (id != MouseEvent.MOUSE_RELEASED) { // do not cancel on release outside of the component - cancelEditing(); + doOKAction(); } } diff --git a/plugins/devkit/src/references/PluginDescriptorXIncludeReferenceContributor.java b/plugins/devkit/src/references/PluginDescriptorXIncludeReferenceContributor.java index 62f2d4bffb5e..db1fb306b98f 100644 --- a/plugins/devkit/src/references/PluginDescriptorXIncludeReferenceContributor.java +++ b/plugins/devkit/src/references/PluginDescriptorXIncludeReferenceContributor.java @@ -1,18 +1,17 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.idea.devkit.references; +import com.intellij.openapi.util.Condition; import com.intellij.patterns.PatternCondition; import com.intellij.patterns.XmlAttributeValuePattern; import com.intellij.patterns.XmlPatterns; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; -import com.intellij.psi.PsiReferenceContributor; -import com.intellij.psi.PsiReferenceRegistrar; +import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; import com.intellij.psi.impl.source.resolve.reference.impl.providers.XmlBaseReferenceProvider; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.devkit.util.DescriptorUtil; import org.jetbrains.idea.devkit.util.PsiUtil; /** @@ -45,8 +44,12 @@ public class PluginDescriptorXIncludeReferenceContributor extends PsiReferenceCo @NotNull @Override public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { - // No customizations for PluginDescriptorXIncludeFileReferenceHelper to be used - return FileReferenceSet.createSet(element, false, false, false).getAllReferences(); + return new FileReferenceSet(element) { + @Override + protected Condition getReferenceCompletionFilter() { + return item -> DescriptorUtil.isPluginXml(item.getContainingFile()); + } + }.getAllReferences(); } } } diff --git a/plugins/git4idea/src/git4idea/GitApplyChangesProcess.kt b/plugins/git4idea/src/git4idea/GitApplyChangesProcess.kt index b66da9186088..cff5a2493d5a 100644 --- a/plugins/git4idea/src/git4idea/GitApplyChangesProcess.kt +++ b/plugins/git4idea/src/git4idea/GitApplyChangesProcess.kt @@ -138,6 +138,7 @@ class GitApplyChangesProcess(private val project: Project, waitForChangeListManagerUpdate() if (mergeCompleted) { + LOG.debug("All conflicts resolved, will show commit dialog. Current default changelist is [$changeList]") val committed = commit(repository, commit, commitMessage, changeList, successfulCommits, alreadyPicked) if (!committed) return false @@ -198,10 +199,12 @@ class GitApplyChangesProcess(private val project: Project, } val changes = actualList.changes if (changes.isEmpty()) { + LOG.debug("No changes in the $actualList. All changes in the CLM: ${getAllChangesInLogFriendlyPresentation(changeListManager)}") alreadyPicked.add(commit) return true } + LOG.debug("Showing commit dialog for changes: ${changes}") val committed = showCommitDialogAndWaitForCommit(repository, changeList, commitMessage, changes) if (committed) { refreshVfsAndMarkDirty(changes) @@ -216,6 +219,9 @@ class GitApplyChangesProcess(private val project: Project, } } + private fun getAllChangesInLogFriendlyPresentation(changeListManagerEx: ChangeListManagerEx) = + changeListManagerEx.changeLists.map { it -> "[${it.name}] ${it.changes}" } + private fun waitForChangeListManagerUpdate() { val waiter = CountDownLatch(1) changeListManager.invokeAfterUpdate({ @@ -248,6 +254,8 @@ class GitApplyChangesProcess(private val project: Project, private fun removeChangeListIfEmpty(changeList: LocalChangeList) { val actualList = changeListManager.getChangeList(changeList.id) if (actualList != null && actualList.changes.isEmpty()) { + LOG.debug("Changelist $actualList is empty, removing. " + + "All changes in the CLM: ${getAllChangesInLogFriendlyPresentation(changeListManager)}") changeListManager.removeChangeList(actualList) } } diff --git a/plugins/git4idea/src/git4idea/crlf/GitCrlfProblemsDetector.java b/plugins/git4idea/src/git4idea/crlf/GitCrlfProblemsDetector.java index c66202aafa84..7eefe8127b4b 100644 --- a/plugins/git4idea/src/git4idea/crlf/GitCrlfProblemsDetector.java +++ b/plugins/git4idea/src/git4idea/crlf/GitCrlfProblemsDetector.java @@ -55,7 +55,6 @@ public class GitCrlfProblemsDetector { private static final Logger LOG = Logger.getInstance(GitCrlfProblemsDetector.class); private static final String CRLF = "\r\n"; - @NotNull private final Project myProject; @NotNull private final Git myGit; @NotNull private final GitRepositoryManager myRepositoryManager; @@ -68,7 +67,6 @@ public class GitCrlfProblemsDetector { private GitCrlfProblemsDetector(@NotNull Project project, @NotNull Git git, @NotNull Collection files) { - myProject = project; myRepositoryManager = GitUtil.getRepositoryManager(project); myGit = git; @@ -127,8 +125,8 @@ public class GitCrlfProblemsDetector { } @NotNull - private Map> findFilesWithCrlf(@NotNull Map> allFilesByRoots, - @NotNull Collection rootsWithIncorrectAutoCrlf) { + private static Map> findFilesWithCrlf(@NotNull Map> allFilesByRoots, + @NotNull Collection rootsWithIncorrectAutoCrlf) { Map> filesWithCrlfByRoots = new HashMap<>(); for (Map.Entry> entry : allFilesByRoots.entrySet()) { VirtualFile root = entry.getKey(); @@ -144,7 +142,7 @@ public class GitCrlfProblemsDetector { } @NotNull - private Collection findFilesWithCrlf(@NotNull Collection files) { + private static Collection findFilesWithCrlf(@NotNull Collection files) { Collection filesWithCrlf = new ArrayList<>(); for (VirtualFile file : files) { ProgressIndicatorProvider.checkCanceled(); diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt index 0fb78f2bcd5d..bac4735cb5c9 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt @@ -18,7 +18,6 @@ package git4idea.branch import com.intellij.dvcs.repo.Repository import com.intellij.notification.Notification import com.intellij.openapi.progress.EmptyProgressIndicator -import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.util.Ref import com.intellij.openapi.util.io.FileUtil @@ -948,9 +947,7 @@ class GitBranchWorkerTest : GitPlatformTest() { } open class TestUiHandler : GitBranchUiHandler { - override fun getProgressIndicator(): ProgressIndicator { - return EmptyProgressIndicator() - } + override fun getProgressIndicator() = EmptyProgressIndicator() override fun showSmartOperationDialog(project: Project, changes: List, @@ -966,32 +963,32 @@ class GitBranchWorkerTest : GitPlatformTest() { } override fun notifyErrorWithRollbackProposal(title: String, message: String, rollbackProposal: String): Boolean { - throw UnsupportedOperationException() + throw UnsupportedOperationException("$title\n$message\n$rollbackProposal") } override fun showUnmergedFilesNotification(operationName: String, repositories: Collection) { - throw UnsupportedOperationException() + throw UnsupportedOperationException("$operationName\n$repositories") } override fun showUnmergedFilesMessageWithRollback(operationName: String, rollbackProposal: String): Boolean { - throw UnsupportedOperationException() + throw UnsupportedOperationException("$operationName\n$rollbackProposal") } override fun showUntrackedFilesNotification(operationName: String, root: VirtualFile, relativePaths: Collection) { - throw UnsupportedOperationException() + throw UnsupportedOperationException("$operationName $root\n$relativePaths") } override fun showUntrackedFilesDialogWithRollback(operationName: String, rollbackProposal: String, root: VirtualFile, relativePaths: Collection): Boolean { - throw UnsupportedOperationException() + throw UnsupportedOperationException("$operationName\n$rollbackProposal\n$root\n$relativePaths") } override fun confirmRemoteBranchDeletion(branchName: String, trackingBranches: MutableCollection, repositories: MutableCollection): DeleteRemoteBranchDecision { - throw UnsupportedOperationException() + throw UnsupportedOperationException("$branchName\n$trackingBranches\n$repositories") } } diff --git a/plugins/git4idea/tests/git4idea/cherrypick/GitCherryPickAutoCommitTest.kt b/plugins/git4idea/tests/git4idea/cherrypick/GitCherryPickAutoCommitTest.kt index cdbc1cfd6753..b564ace8a888 100644 --- a/plugins/git4idea/tests/git4idea/cherrypick/GitCherryPickAutoCommitTest.kt +++ b/plugins/git4idea/tests/git4idea/cherrypick/GitCherryPickAutoCommitTest.kt @@ -74,6 +74,7 @@ class GitCherryPickAutoCommitTest : GitCherryPickTest() { cherryPick(commit) `assert merge dialog was shown`() + `assert commit dialog was shown`() changeListManager.assertChangeListExists("on_master\n\n(cherry picked from commit ${shortHash(commit)})") assertNoNotification() } diff --git a/plugins/git4idea/tests/git4idea/crlf/GitCrlfProblemsDetectorTest.java b/plugins/git4idea/tests/git4idea/crlf/GitCrlfProblemsDetectorTest.java index 8fce99351c42..8c92f2897bf3 100644 --- a/plugins/git4idea/tests/git4idea/crlf/GitCrlfProblemsDetectorTest.java +++ b/plugins/git4idea/tests/git4idea/crlf/GitCrlfProblemsDetectorTest.java @@ -14,7 +14,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import static git4idea.test.GitExecutor.git; import static java.util.Arrays.asList; public class GitCrlfProblemsDetectorTest extends GitSingleRepoTest { @@ -50,7 +49,7 @@ public class GitCrlfProblemsDetectorTest extends GitSingleRepoTest { } if (!StringUtil.isEmptyOrSpaces(myOldSystemAutoCrlfValue)) { - git("config --global core.autocrlf " + myOldSystemAutoCrlfValue); + git("config --system core.autocrlf " + myOldSystemAutoCrlfValue); } } finally { diff --git a/plugins/git4idea/tests/git4idea/history/GitHistoryUtilsTest.java b/plugins/git4idea/tests/git4idea/history/GitHistoryUtilsTest.java index dfa0665e70f1..9ae4047cf45f 100644 --- a/plugins/git4idea/tests/git4idea/history/GitHistoryUtilsTest.java +++ b/plugins/git4idea/tests/git4idea/history/GitHistoryUtilsTest.java @@ -31,6 +31,7 @@ import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitFileRevision; import git4idea.GitRevisionNumber; +import git4idea.config.GitVersion; import git4idea.history.browser.SHAHash; import git4idea.test.GitSingleRepoTest; import org.jetbrains.annotations.NotNull; @@ -45,6 +46,7 @@ import static com.intellij.openapi.vcs.Executor.*; import static git4idea.test.GitExecutor.*; import static git4idea.test.GitTestUtil.USER_EMAIL; import static git4idea.test.GitTestUtil.USER_NAME; +import static org.junit.Assume.assumeTrue; /** * Tests for low-level history methods in GitHistoryUtils. @@ -377,6 +379,9 @@ public class GitHistoryUtilsTest extends GitSingleRepoTest { } public void testLoadingDetailsWithoutChanges() throws Exception { + assumeTrue("Not testing: Git doesn't know --allow-empty-message in " + vcs.getVersion(), + vcs.getVersion().isLaterOrEqual(new GitVersion(1, 7, 2, 0))); + List expected = ContainerUtil.newArrayList(); String messageFile = "message.txt"; diff --git a/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt b/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt index d90d68a51db6..7ef5bd03749d 100644 --- a/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt +++ b/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vcs.Executor import git4idea.GitUtil import git4idea.branch.GitRebaseParams +import git4idea.config.GitVersion import git4idea.repo.GitRepository import git4idea.test.* @@ -205,9 +206,10 @@ abstract class GitRebaseBaseTest : GitPlatformTest() { } protected fun `assert error about unstaged file before continue rebase`(file : String) { + val fileLine = if (vcs.version.isLaterOrEqual(GitVersion(1, 7, 3, 0))) "$file: needs update" else "" assertErrorNotification("Continue Rebase Failed", - """ - $file: needs update + """ + $fileLine You must edit all merge conflicts and then mark them as resolved using git add You can retry or abort rebase. diff --git a/plugins/git4idea/tests/git4idea/rebase/GitRewordTest.kt b/plugins/git4idea/tests/git4idea/rebase/GitRewordTest.kt index 4da235621e92..494d4d3898b0 100644 --- a/plugins/git4idea/tests/git4idea/rebase/GitRewordTest.kt +++ b/plugins/git4idea/tests/git4idea/rebase/GitRewordTest.kt @@ -55,7 +55,7 @@ class GitRewordTest : GitSingleRepoTest() { val newMessage = "Correct message" GitRewordOperation(repo, commit, newMessage).execute() - assertMessage(newMessage, git("log HEAD^ --no-walk --pretty=%B"), "Message reworded incorrectly") + assertLastMessage(newMessage, "Message reworded incorrectly") } fun `test undo reword`() { @@ -114,9 +114,7 @@ class GitRewordTest : GitSingleRepoTest() { val newMessage = "Subject with trailing spaces \n\nBody \nwith \nspaces." GitRewordOperation(repo, commit, newMessage).execute() - val actualMessage = git("log HEAD --no-walk --pretty=%B") - assertTrue("Message reworded incorrectly. Expected:\n[$newMessage] Actual:\n[$actualMessage]", - StringUtil.equalsIgnoreWhitespaces(newMessage, actualMessage)) + assertLastMessage("Message reworded incorrectly") } // IDEA-175443 diff --git a/plugins/git4idea/tests/git4idea/remote/GitRemoteTest.kt b/plugins/git4idea/tests/git4idea/remote/GitRemoteTest.kt index 1906cf76a362..38c445857b65 100644 --- a/plugins/git4idea/tests/git4idea/remote/GitRemoteTest.kt +++ b/plugins/git4idea/tests/git4idea/remote/GitRemoteTest.kt @@ -16,16 +16,12 @@ package git4idea.remote import com.intellij.openapi.components.service -import com.intellij.testFramework.RunAll -import com.intellij.util.ThrowableRunnable import git4idea.checkout.GitCheckoutProvider import git4idea.commands.GitHttpAuthService import git4idea.commands.GitHttpAuthenticator -import git4idea.remote.GitRemoteTest.ConfigScope.GLOBAL -import git4idea.remote.GitRemoteTest.ConfigScope.SYSTEM +import git4idea.config.GitVersion import git4idea.test.GitHttpAuthTestService import git4idea.test.GitPlatformTest -import git4idea.test.git import java.io.File import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit @@ -34,7 +30,6 @@ class GitRemoteTest : GitPlatformTest() { private lateinit var authenticator : TestAuthenticator private lateinit var authTestService : GitHttpAuthTestService - private lateinit var credentialHelpers: Map private val projectName = "projectA" @@ -44,18 +39,19 @@ class GitRemoteTest : GitPlatformTest() { authenticator = TestAuthenticator() authTestService = service() as GitHttpAuthTestService authTestService.register(authenticator) - - credentialHelpers = readAndResetCredentialHelpers() } override fun tearDown() { - RunAll() - .append(ThrowableRunnable { authTestService.cleanup() }) - .append(ThrowableRunnable { restoreCredentialHelpers() }) - .append(ThrowableRunnable { super.tearDown() }) - .run() + try { + authTestService.cleanup() + } + finally { + super.tearDown() + } } + override fun hasRemoteGitOperation() = true + fun `test clone from http with username`() { val cloneWaiter = cloneOnPooledThread(makeUrl("gituser")) @@ -86,7 +82,14 @@ class GitRemoteTest : GitPlatformTest() { assertTrue("Clone didn't complete during the reasonable period of time", cloneWaiter.await(30, TimeUnit.SECONDS)) assertFalse("Repository directory shouldn't be created", File(testRoot, projectName).exists()) - assertErrorNotification("Clone failed", "Authentication failed for '$url/'") + + val expectedAuthFailureMessage = if (vcs.version.isLaterOrEqual(GitVersion(1, 8, 3, 0))) { + "Authentication failed for '$url/'" + } + else { + "Authentication failed" + } + assertErrorNotification("Clone failed", expectedAuthFailureMessage) } private fun makeUrl(username: String?) : String { @@ -104,24 +107,6 @@ class GitRemoteTest : GitPlatformTest() { return cloneWaiter } - private fun readAndResetCredentialHelpers(): Map { - val system = readAndResetCredentialHelper(SYSTEM) - val global = readAndResetCredentialHelper(GLOBAL) - return mapOf(SYSTEM to system, GLOBAL to global) - } - - private fun readAndResetCredentialHelper(scope: ConfigScope): String { - val value = git("config ${scope.param()} --get-all credential.helper", true) - git("config ${scope.param()} --unset-all credential.helper", true) - return value - } - - private fun restoreCredentialHelpers() { - credentialHelpers.forEach { scope, value -> - if (value.isNotBlank()) git("config ${scope.param()} credential.helper ${value}", true) - } - } - private fun assertCloneSuccessful(cloneCompleted: CountDownLatch) { assertTrue("Clone didn't complete during the reasonable period of time", cloneCompleted.await(30, TimeUnit.SECONDS)) assertTrue("Repository directory was not found", File(testRoot, projectName).exists()) @@ -204,11 +189,4 @@ class GitRemoteTest : GitPlatformTest() { return usernameAsked } } - - private enum class ConfigScope { - SYSTEM, - GLOBAL; - - fun param() = "--${name.toLowerCase()}" - } } \ No newline at end of file diff --git a/plugins/git4idea/tests/git4idea/repo/GitWorkTreeBaseTest.kt b/plugins/git4idea/tests/git4idea/repo/GitWorkTreeBaseTest.kt index c86f1653a5f6..300191ed9503 100644 --- a/plugins/git4idea/tests/git4idea/repo/GitWorkTreeBaseTest.kt +++ b/plugins/git4idea/tests/git4idea/repo/GitWorkTreeBaseTest.kt @@ -23,6 +23,7 @@ import git4idea.config.GitVersion import git4idea.test.GitPlatformTest import git4idea.test.git import git4idea.test.registerRepo +import git4idea.test.setupDefaultUsername import org.junit.Assume.assumeTrue import java.io.File @@ -44,6 +45,7 @@ abstract class GitWorkTreeBaseTest : GitPlatformTest() { val gitDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath, GitUtil.DOT_GIT)) assertNotNull(gitDir) myRepo = registerRepo(project, projectPath) + setupDefaultUsername() assertEquals(1, repositoryManager.repositories.size) assertNotNull(repositoryManager.getRepositoryForRoot(projectRoot)) } diff --git a/plugins/git4idea/tests/git4idea/test/GitExecutor.kt b/plugins/git4idea/tests/git4idea/test/GitExecutor.kt index 44736edc5646..cdd263ad8e1e 100644 --- a/plugins/git4idea/tests/git4idea/test/GitExecutor.kt +++ b/plugins/git4idea/tests/git4idea/test/GitExecutor.kt @@ -122,7 +122,7 @@ private fun last(project: Project) = git(project, "log -1 --pretty=%H") fun GitRepository.lastMessage() = cd { lastMessage(project) } fun GitPlatformTest.lastMessage() = lastMessage(project) -private fun lastMessage(project: Project) = git(project, "log -1 --pretty=%B") +private fun lastMessage(project: Project) = git(project, "log -1 --pretty=${getPrettyFormatTagForFullCommitMessage(project)}") fun GitRepository.log(vararg params: String) = cd { log(project, *params) } fun GitPlatformTest.log(vararg params: String) = log(project, *params) diff --git a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.kt b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.kt index 634e5d0e756a..dd7b5160471d 100644 --- a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.kt +++ b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.kt @@ -22,7 +22,9 @@ import com.intellij.openapi.vcs.Executor import com.intellij.openapi.vcs.Executor.cd import com.intellij.openapi.vcs.VcsConfiguration import com.intellij.openapi.vcs.VcsShowConfirmationOption +import com.intellij.testFramework.RunAll import com.intellij.testFramework.vcs.AbstractVcsTestCase +import com.intellij.util.ThrowableRunnable import com.intellij.vcs.log.VcsFullCommitDetails import com.intellij.vcs.log.impl.VcsLogUtil import com.intellij.vcs.test.VcsPlatformTest @@ -36,6 +38,8 @@ import git4idea.config.GitVcsSettings import git4idea.log.GitLogProvider import git4idea.repo.GitRepository import git4idea.repo.GitRepositoryManager +import git4idea.test.GitPlatformTest.ConfigScope.GLOBAL +import git4idea.test.GitPlatformTest.ConfigScope.SYSTEM import java.io.File abstract class GitPlatformTest : VcsPlatformTest() { @@ -48,6 +52,8 @@ abstract class GitPlatformTest : VcsPlatformTest() { protected lateinit var vcsHelper: MockVcsHelper protected lateinit var logProvider: GitLogProvider + private lateinit var credentialHelpers: Map + @Throws(Exception::class) override fun setUp() { super.setUp() @@ -69,18 +75,19 @@ abstract class GitPlatformTest : VcsPlatformTest() { assumeSupportedGitVersion(vcs) addSilently() removeSilently() + + credentialHelpers = if (hasRemoteGitOperation()) readAndResetCredentialHelpers() else emptyMap() } @Throws(Exception::class) override fun tearDown() { - try { - if (wasInit { dialogManager }) dialogManager.cleanup() - if (wasInit { git }) git.reset() - if (wasInit { settings }) settings.appSettings.setPathToGit(null) - } - finally { - super.tearDown() - } + RunAll() + .append(ThrowableRunnable { restoreCredentialHelpers() }) + .append(ThrowableRunnable { if (wasInit { dialogManager }) dialogManager.cleanup() }) + .append(ThrowableRunnable { if (wasInit { git }) git.reset() }) + .append(ThrowableRunnable { if (wasInit { settings }) settings.appSettings.setPathToGit(null) }) + .append(ThrowableRunnable { super.tearDown() }) + .run() } override fun getDebugLogCategories(): Collection { @@ -89,6 +96,8 @@ abstract class GitPlatformTest : VcsPlatformTest() { "#output." + GitHandler::class.java.name)) } + protected open fun hasRemoteGitOperation() = false + protected open fun createRepository(rootDir: String): GitRepository { return createRepository(project, rootDir) } @@ -160,6 +169,24 @@ abstract class GitPlatformTest : VcsPlatformTest() { hookFile.setExecutable(true, false) } + private fun readAndResetCredentialHelpers(): Map { + val system = readAndResetCredentialHelper(SYSTEM) + val global = readAndResetCredentialHelper(GLOBAL) + return mapOf(SYSTEM to system, GLOBAL to global) + } + + private fun readAndResetCredentialHelper(scope: ConfigScope): String { + val value = git("config ${scope.param()} --get-all credential.helper", true) + git("config ${scope.param()} --unset-all credential.helper", true) + return value + } + + private fun restoreCredentialHelpers() { + credentialHelpers.forEach { scope, value -> + if (value.isNotBlank()) git("config ${scope.param()} credential.helper ${value}", true) + } + } + protected fun readDetails(hashes: List): List = VcsLogUtil.getDetails(logProvider, projectRoot, hashes) protected fun readDetails(hash: String) = readDetails(listOf(hash)).first() @@ -182,4 +209,11 @@ abstract class GitPlatformTest : VcsPlatformTest() { protected data class ReposTrinity(val projectRepo: GitRepository, val parent: File, val bro: File) + + private enum class ConfigScope { + SYSTEM, + GLOBAL; + + fun param() = "--${name.toLowerCase()}" + } } diff --git a/plugins/git4idea/tests/git4idea/test/GitTestAssertions.kt b/plugins/git4idea/tests/git4idea/test/GitTestAssertions.kt index daaed92240c4..7fdbf0a69341 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestAssertions.kt +++ b/plugins/git4idea/tests/git4idea/test/GitTestAssertions.kt @@ -103,7 +103,7 @@ fun GitPlatformTest.assertMessage(actual: String, expected: String, failMessage: fun GitPlatformTest.assertLogMessages(vararg messages: String) { val separator = "\u0001" - val actualMessages = git("log -${messages.size} --pretty=%B${separator}").split(separator) + val actualMessages = git("log -${messages.size} --pretty=${getPrettyFormatTagForFullCommitMessage(project)}${separator}").split(separator) for ((index, message) in messages.withIndex()) { Assertions.assertThat(actualMessages[index].trim()).isEqualToIgnoringWhitespace(message.trimIndent()) } diff --git a/plugins/git4idea/tests/git4idea/test/GitTestUtil.kt b/plugins/git4idea/tests/git4idea/test/GitTestUtil.kt index 6f4539ee0d74..983a10c95ada 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestUtil.kt +++ b/plugins/git4idea/tests/git4idea/test/GitTestUtil.kt @@ -32,6 +32,7 @@ import git4idea.GitRemoteBranch import git4idea.GitStandardRemoteBranch import git4idea.GitUtil import git4idea.GitVcs +import git4idea.config.GitVersionSpecialty import git4idea.log.GitLogProvider import git4idea.push.GitPushSource import git4idea.push.GitPushTarget @@ -91,11 +92,12 @@ fun GitPlatformTest.cloneRepo(source: String, destination: String, bare: Boolean else { git("clone -- . $destination") } + cd(destination) + setupDefaultUsername() } -fun setupDefaultUsername(project: Project) { - setupUsername(project, USER_NAME, USER_EMAIL) -} +fun setupDefaultUsername(project: Project) = setupUsername(project, USER_NAME, USER_EMAIL) +fun GitPlatformTest.setupDefaultUsername() = setupDefaultUsername(project) fun setupUsername(project: Project, name: String, email: String) { assertFalse("Can not set empty user name ", name.isEmpty()) @@ -176,3 +178,5 @@ fun GitRepository.resolveConflicts() { this.git("add -u .") } +fun getPrettyFormatTagForFullCommitMessage(project: Project) = + if (GitVersionSpecialty.STARTED_USING_RAW_BODY_IN_FORMAT.existsIn(GitVcs.getInstance(project).version)) "%B" else "%s%n%n%-b" diff --git a/plugins/git4idea/tests/git4idea/tests/GitCommitTest.kt b/plugins/git4idea/tests/git4idea/tests/GitCommitTest.kt index 3d7fc6933f93..7f5367d8744c 100644 --- a/plugins/git4idea/tests/git4idea/tests/GitCommitTest.kt +++ b/plugins/git4idea/tests/git4idea/tests/GitCommitTest.kt @@ -22,7 +22,9 @@ import com.intellij.openapi.vcs.changes.Change import com.intellij.util.containers.ContainerUtil import git4idea.GitUtil import git4idea.checkin.GitCheckinEnvironment +import git4idea.config.GitVersion import git4idea.test.* +import org.junit.Assume.assumeTrue import java.io.File import java.util.* @@ -133,6 +135,8 @@ class GitCommitTest : GitSingleRepoTest() { } fun `test commit case rename & don't commit one staged file`() { + `assume version where git reset returns 0 exit code on success `() + tac("s.java") generateCaseRename("a.java", "A.java") echo("s.java", "staged") @@ -157,6 +161,8 @@ class GitCommitTest : GitSingleRepoTest() { } fun `test commit case rename & don't commit one staged simple rename, then rename should remain staged`() { + `assume version where git reset returns 0 exit code on success `() + echo("before.txt", "some\ncontent\nere") addCommit("created before.txt") generateCaseRename("a.java", "A.java") @@ -181,6 +187,8 @@ class GitCommitTest : GitSingleRepoTest() { } fun `test commit case rename + one unstaged file & don't commit one staged file`() { + `assume version where git reset returns 0 exit code on success `() + tac("s.java") tac("m.java") generateCaseRename("a.java", "A.java") @@ -209,6 +217,8 @@ class GitCommitTest : GitSingleRepoTest() { } fun `test commit case rename & don't commit a file which is both staged and unstaged, should reset and restore`() { + `assume version where git reset returns 0 exit code on success `() + tac("c.java") generateCaseRename("a.java", "A.java") echo("c.java", "staged") @@ -267,6 +277,11 @@ class GitCommitTest : GitSingleRepoTest() { assertEquals(initialContent + additionalContent, git("show HEAD:A.java")) } + private fun `assume version where git reset returns 0 exit code on success `() { + assumeTrue("Not testing: git reset returns 1 and fails the commit process in ${vcs.version}", + vcs.version.isLaterOrEqual(GitVersion(1, 8, 2, 0))) + } + private fun generateCaseRename(from: String, to: String) { tac(from) git("mv -f $from $to") diff --git a/plugins/git4idea/tests/git4idea/update/GitSubmoduleTest.kt b/plugins/git4idea/tests/git4idea/update/GitSubmoduleTest.kt index bc6c52e96c34..7ddbb75e3342 100644 --- a/plugins/git4idea/tests/git4idea/update/GitSubmoduleTest.kt +++ b/plugins/git4idea/tests/git4idea/update/GitSubmoduleTest.kt @@ -18,10 +18,12 @@ package git4idea.update import com.intellij.dvcs.DvcsUtil.getPushSupport import com.intellij.dvcs.DvcsUtil.getShortRepositoryName import com.intellij.openapi.progress.EmptyProgressIndicator +import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil.getRelativePath import com.intellij.openapi.vcs.Executor.cd import com.intellij.openapi.vcs.update.UpdatedFiles import com.intellij.openapi.vfs.VfsUtilCore.virtualToIoFile +import git4idea.config.GitVersion import git4idea.config.UpdateMethod import git4idea.push.GitPushOperation import git4idea.push.GitPushSupport @@ -29,6 +31,7 @@ import git4idea.repo.GitRepository import git4idea.repo.GitRepositoryManager import git4idea.repo.GitSubmoduleInfo import git4idea.test.* +import org.junit.Assume.assumeTrue import java.io.File import java.util.* @@ -59,7 +62,7 @@ class GitSubmoduleTest : GitPlatformTest() { override fun setUp() { super.setUp() - + setUpRepositoryStructure() repositoryManager.updateAllRepositories() } @@ -72,6 +75,8 @@ class GitSubmoduleTest : GitPlatformTest() { } fun `test submodules are updated before superprojects`() { + assumeTrue("Not testing: no --recurse-submodules flag in ${vcs.version}", vcs.version.isLaterOrEqual(GitVersion(1, 7, 4, 0))) + val bro = prepareSecondClone() commitAndPushFromSecondClone(bro) // remote commit to overcome "nothing to do" @@ -139,14 +144,18 @@ class GitSubmoduleTest : GitPlatformTest() { youngerRepo = addSubmoduleInProject(younger.remote, younger.name, "alib/younger") mainRepo.git("submodule update --init --recursive") // this initializes the grandchild submodule grandchildRepo = registerRepo(project, "${projectPath}/elder/grandchild") + cd(grandchildRepo) + setupDefaultUsername() grandchildRepo.git("checkout master") // git submodule is initialized in detached HEAD state by default } private fun addSubmodule(superProject: File, submoduleUrl: File, relativePath: String? = null) { cd(superProject) - git("submodule add ${submoduleUrl.path} ${relativePath ?: ""}") + git("submodule add ${FileUtil.toSystemIndependentName(submoduleUrl.path)} ${relativePath ?: ""}") git("commit -m 'Added submodule lib'") git("push origin master") + cd(File(submoduleUrl.path)) + setupDefaultUsername() } /** @@ -164,7 +173,7 @@ class GitSubmoduleTest : GitPlatformTest() { git("init $moduleName") val child = File(testRoot, moduleName) cd(child) - setupDefaultUsername(project) + setupDefaultUsername() tac("initial.txt", "initial") val parent = "$moduleName.git" git("remote add origin ${testRoot}/$parent") @@ -180,7 +189,10 @@ class GitSubmoduleTest : GitPlatformTest() { private fun prepareSecondClone(): File { cd(testRoot) git("clone --recurse-submodules parent.git bro") - return File(testRoot, "bro") + val broDir = File(testRoot, "bro") + cd(broDir) + setupDefaultUsername() + return broDir } private fun commitAndPushFromSecondClone(bro: File) { @@ -199,7 +211,7 @@ class GitSubmoduleTest : GitPlatformTest() { private fun assertSubmodulesInfo(repo: GitRepository, expectedSubmodules: List) { val expectedInfos = expectedSubmodules.map { val url = it.remotes.first().firstUrl!! - GitSubmoduleInfo(getRelativePath(virtualToIoFile(repo.root), virtualToIoFile(it.root))!!, url) + GitSubmoduleInfo(FileUtil.toSystemIndependentName(getRelativePath(virtualToIoFile(repo.root), virtualToIoFile(it.root))!!), url) } assertSameElements("Submodules were read incorrectly for ${getShortRepositoryName(repo)}", repo.submodules, expectedInfos) } diff --git a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java index 7d91830a1abb..f4d572626bcc 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java @@ -75,6 +75,11 @@ public abstract class GithubTest extends GitPlatformTest { VfsTestUtil.createDir (projectRoot, "folder/empty_folder"); } + @Override + protected boolean hasRemoteGitOperation() { + return true; + } + protected void checkNotification(@NotNull NotificationType type, @Nullable String title, @Nullable String content) { Notification actualNotification = vcsNotifier.getLastNotification(); assertNotNull("No notification was shown", actualNotification); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 25a454c65816..cb0baebb1955 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -34,7 +34,10 @@ import com.intellij.openapi.externalSystem.service.notification.NotificationData import com.intellij.openapi.externalSystem.service.notification.NotificationSource; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.Order; -import com.intellij.openapi.module.*; +import com.intellij.openapi.module.EmptyModuleType; +import com.intellij.openapi.module.JavaModuleType; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.DependencyScope; import com.intellij.openapi.util.Pair; @@ -52,7 +55,6 @@ import com.intellij.util.text.CharArrayUtil; import groovy.lang.GroovyObject; import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling; import org.gradle.internal.impldep.com.google.common.collect.Multimap; -import org.gradle.internal.impldep.com.google.common.io.InputSupplier; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.model.DomainObjectSet; import org.gradle.tooling.model.GradleModuleVersion; @@ -521,6 +523,12 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver if (dependencies == null) return; List orphanModules = ContainerUtil.newArrayList(); + Map modulesIndex = ContainerUtil.newHashMap(); + + for (DataNode dataNode : ExternalSystemApiUtil.getChildren(ideProject, ProjectKeys.MODULE)) { + modulesIndex.put(dataNode.getData().getExternalName(), dataNode.getData()); + } + for (int i = 0; i < dependencies.size(); i++) { IdeaDependency dependency = dependencies.get(i); if (dependency == null) { @@ -529,7 +537,7 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver DependencyScope scope = parseScope(dependency.getScope()); if (dependency instanceof IdeaModuleDependency) { - ModuleDependencyData d = buildDependency(resolverCtx, ideModule, (IdeaModuleDependency)dependency, ideProject); + ModuleDependencyData d = buildDependency(resolverCtx, ideModule, (IdeaModuleDependency)dependency, modulesIndex); d.setExported(dependency.getExported()); if (scope != null) { d.setScope(scope); @@ -870,7 +878,7 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver private static ModuleDependencyData buildDependency(@NotNull ProjectResolverContext resolverContext, @NotNull DataNode ownerModule, @NotNull IdeaModuleDependency dependency, - @NotNull DataNode ideProject) + @NotNull Map registeredModulesIndex) throws IllegalStateException { IdeaModule module = dependency.getDependencyModule(); if (module == null) { @@ -904,18 +912,14 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver )); } - Set registeredModuleNames = ContainerUtilRt.newHashSet(); - Collection> modulesDataNode = ExternalSystemApiUtil.getChildren(ideProject, ProjectKeys.MODULE); - for (DataNode moduleDataNode : modulesDataNode) { - String name = moduleDataNode.getData().getExternalName(); - registeredModuleNames.add(name); - if (name.equals(moduleName)) { - return new ModuleDependencyData(ownerModule.getData(), moduleDataNode.getData()); - } + ModuleData moduleData = registeredModulesIndex.get(moduleName); + if (moduleData != null) { + return new ModuleDependencyData(ownerModule.getData(), moduleData); } + throw new IllegalStateException(String.format( "Can't parse gradle module dependency '%s'. Reason: no module with such name (%s) is found. Registered modules: %s", - dependency, moduleName, registeredModuleNames + dependency, moduleName, registeredModulesIndex.keySet() )); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index ee5ad2982bbf..354688f4fefb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -151,6 +151,12 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver= 1.10 """ try: - from distutils.version import StrictVersion + from distutils.version import StrictVersion, LooseVersion import django - return StrictVersion(django.get_version()) >= StrictVersion("1.10") + try: + return StrictVersion(django.get_version()) >= StrictVersion("1.10") + except ValueError: + return LooseVersion(django.get_version()) >= LooseVersion("1.10") except (ImportError, AttributeError): return False diff --git a/python/python-terminal/src/com/jetbrains/python/sdk/PyVirtualEnvTerminalCustomizer.kt b/python/python-terminal/src/com/jetbrains/python/sdk/PyVirtualEnvTerminalCustomizer.kt index c24baa6d1eec..56db5220da6e 100644 --- a/python/python-terminal/src/com/jetbrains/python/sdk/PyVirtualEnvTerminalCustomizer.kt +++ b/python/python-terminal/src/com/jetbrains/python/sdk/PyVirtualEnvTerminalCustomizer.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.sdk import com.intellij.openapi.components.PersistentStateComponent @@ -69,7 +55,7 @@ class PyVirtualEnvTerminalCustomizer : LocalTerminalCustomizer() { reader.activate?.let { // we add only envs that are setup by the activate script, because adding other variables from the different shell // can break the actual shell - envs.putAll(reader.readShellEnv().mapKeys { k -> k.key.toUpperCase() }.filterKeys { k -> + envs.putAll(reader.readPythonEnv().mapKeys { k -> k.key.toUpperCase() }.filterKeys { k -> k in PyVirtualEnvReader.virtualEnvVars }) } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index 1c109ccd105c..05cc114e47ee 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -178,12 +178,12 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl */ public synchronized void close() { sendCloseMessageToScript(); + PyDebugValueExecutionService.getInstance(myProject).sessionStopped(this); if (myWebServer != null) { myWebServer.shutdown(); myWebServer = null; } - PyDebugValueExecutionService.getInstance(myProject).sessionStopped(this); } /** @@ -195,6 +195,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl @NotNull public synchronized Future closeAsync() { sendCloseMessageToScript(); + PyDebugValueExecutionService.getInstance(myProject).sessionStopped(this); if (myWebServer != null) { Future shutdownFuture = myWebServer.shutdownAsync(); diff --git a/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt b/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt index a65651449e27..c5d56e419d10 100644 --- a/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt +++ b/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt @@ -1,21 +1,8 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.highlighting import com.intellij.codeInsight.daemon.RainbowVisitor +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile @@ -30,6 +17,10 @@ class PyRainbowVisitor : RainbowVisitor() { companion object { private val IGNORED_NAMES = setOf(PyNames.NONE, PyNames.TRUE, PyNames.FALSE) + private val DEFAULT_HIGHLIGHTING_KEY = DefaultLanguageHighlighterColors.LOCAL_VARIABLE + + @JvmStatic + val HIGHLIGHTING_KEYS = setOf(PyHighlighter.PY_PARAMETER, DEFAULT_HIGHLIGHTING_KEY) } override fun suitableForFile(file: PsiFile) = file is PyFile @@ -132,8 +123,8 @@ class PyRainbowVisitor : RainbowVisitor() { } } - private fun addInfo(context: PsiElement, rainbowElement: PsiElement, name: String, colorKey: TextAttributesKey? = null) { - addInfo(getInfo(context, rainbowElement, name, colorKey)) + private fun addInfo(context: PsiElement, rainbowElement: PsiElement, name: String, key: TextAttributesKey? = DEFAULT_HIGHLIGHTING_KEY) { + addInfo(getInfo(context, rainbowElement, name, key)) } private fun getLeastCommonScope(elements: Collection): ScopeOwner? { diff --git a/python/src/com/jetbrains/python/highlighting/PythonColorsPage.java b/python/src/com/jetbrains/python/highlighting/PythonColorsPage.java index 2c40f3ac96db..4aa6da82e7e3 100644 --- a/python/src/com/jetbrains/python/highlighting/PythonColorsPage.java +++ b/python/src/com/jetbrains/python/highlighting/PythonColorsPage.java @@ -1,34 +1,25 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.highlighting; import com.google.common.collect.ImmutableMap; import com.intellij.application.options.colors.InspectionColorSettingsPage; +import com.intellij.codeHighlighting.RainbowHighlighter; +import com.intellij.lang.Language; +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; import com.intellij.openapi.options.colors.AttributesDescriptor; import com.intellij.openapi.options.colors.ColorDescriptor; -import com.intellij.openapi.options.colors.ColorSettingsPage; +import com.intellij.openapi.options.colors.RainbowColorSettingsPage; import com.intellij.psi.codeStyle.DisplayPriority; import com.intellij.psi.codeStyle.DisplayPrioritySortable; import com.intellij.util.PlatformUtils; import com.jetbrains.python.PythonFileType; +import com.jetbrains.python.PythonLanguage; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Map; @@ -36,7 +27,7 @@ import java.util.Map; /** * @author yole */ -public class PythonColorsPage implements ColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable { +public class PythonColorsPage implements RainbowColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable { private static final AttributesDescriptor[] ATTRS = new AttributesDescriptor[] { new AttributesDescriptor("Keyword", PyHighlighter.PY_KEYWORD), new AttributesDescriptor("String (bytes)", PyHighlighter.PY_BYTE_STRING), @@ -82,27 +73,34 @@ public class PythonColorsPage implements ColorSettingsPage, InspectionColorSetti .put("call", PyHighlighter.PY_FUNCTION_CALL) .put("mcall", PyHighlighter.PY_METHOD_CALL) .put("annotation", PyHighlighter.PY_ANNOTATION) + .put("localVar", DefaultLanguageHighlighterColors.LOCAL_VARIABLE) + .putAll(RainbowHighlighter.createRainbowHLM()) .build(); + @Override @NotNull public String getDisplayName() { return "Python"; } + @Override public Icon getIcon() { return PythonFileType.INSTANCE.getIcon(); } + @Override @NotNull public AttributesDescriptor[] getAttributeDescriptors() { return ATTRS; } + @Override @NotNull public ColorDescriptor[] getColorDescriptors() { return ColorDescriptor.EMPTY_ARRAY; } + @Override @NotNull public SyntaxHighlighter getHighlighter() { final SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(PythonFileType.INSTANCE, null, null); @@ -110,31 +108,35 @@ public class PythonColorsPage implements ColorSettingsPage, InspectionColorSetti return highlighter; } + @Override @NotNull public String getDemoText() { return - "@decorator(param=1)\n" + + "@decorator(param=1)\n" + "def f(x):\n" + " \"\"\" Syntax Highlighting Demo\n" + - " @param x Parameter\"\"\"\n" + - " s = (\"Test\", 2+3, {'a': 'b'}, x) # Comment\n" + - " f(s[0].lower())\n"+ + " @param x Parameter\n" + + RainbowHighlighter.generatePaletteExample("\n ") + "\n" + + " \"\"\"\n" + + " s = (\"Test\", 2+3, {'a': 'b'}, x) # Comment\n" + + " f(s[0].lower())\n"+ "\n"+ "class Foo:\n"+ " tags: List[str]\n" + " def __init__(self: Foo):\n" + - " byte_string: str = 'newline:\\n also newline:\\x0a'\n" + - " text_string = u\"Cyrillic \u042f is \\u042f. Oops: \\u042g\"\n"+ + " byte_string: str = 'newline:\\n also newline:\\x0a'\n" + + " text_string = u\"Cyrillic \u042f is \\u042f. Oops: \\u042g\"\n"+ " self.makeSense(whatever=1)\n" + " \n" + " def makeSense(self, whatever):\n"+ " self.sense = whatever\n"+ "\n"+ - "x = len('abc')\n"+ + "x = len('abc')\n"+ "print(f.__doc__)" ; } + @Override public Map getAdditionalHighlightingTagToDescriptorMap() { return ourTagToDescriptorMap; } @@ -143,4 +145,15 @@ public class PythonColorsPage implements ColorSettingsPage, InspectionColorSetti public DisplayPriority getPriority() { return PlatformUtils.isPyCharm() ? DisplayPriority.KEY_LANGUAGE_SETTINGS : DisplayPriority.LANGUAGE_SETTINGS; } + + @Override + public boolean isRainbowType(TextAttributesKey type) { + return PyRainbowVisitor.getHIGHLIGHTING_KEYS().contains(type); + } + + @Nullable + @Override + public Language getLanguage() { + return PythonLanguage.INSTANCE; + } } diff --git a/python/src/com/jetbrains/python/run/PyVirtualEnvReader.kt b/python/src/com/jetbrains/python/run/PyVirtualEnvReader.kt index 9a4be523d65e..3e402cb7c2cd 100644 --- a/python/src/com/jetbrains/python/run/PyVirtualEnvReader.kt +++ b/python/src/com/jetbrains/python/run/PyVirtualEnvReader.kt @@ -1,25 +1,10 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.run import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.SystemInfo -import com.intellij.openapi.util.io.FileUtil import com.intellij.util.EnvironmentUtil -import com.intellij.util.LineSeparator +import com.intellij.util.containers.ContainerUtil import com.jetbrains.python.sdk.PythonSdkType import java.io.File @@ -52,14 +37,15 @@ class PyVirtualEnvReader(val virtualEnvSdkPath: String) : EnvironmentUtil.ShellE } } - override fun readShellEnv(): MutableMap { + fun readPythonEnv(): MutableMap { try { if (SystemInfo.isUnix) { - return super.readShellEnv() + // pass shell environment for correct virtualenv environment setup (virtualenv expects to be executed from the terminal) + return super.readShellEnv(EnvironmentUtil.getEnvironmentMap()) } else { if (activate != null) { - return readVirtualEnvOnWindows(activate); + return readBatEnv(File(activate.first), ContainerUtil.createMaybeSingletonList(activate.second)) } else { LOG.error("Can't find activate script for $virtualEnvSdkPath") @@ -72,30 +58,6 @@ class PyVirtualEnvReader(val virtualEnvSdkPath: String) : EnvironmentUtil.ShellE return mutableMapOf() } - override fun dumpProcessEnvToFile(command: MutableList, envFile: File, lineSeparator: String?): MutableMap { - // pass shell environment for correct virtualenv environment setup (virtualenv expects to be executed from the terminal) - return runProcessAndReadEnvs(command, null, EnvironmentUtil.getEnvironmentMap(), envFile, lineSeparator) - } - - private fun readVirtualEnvOnWindows(activate: Pair): MutableMap { - val activateFile = FileUtil.createTempFile("pycharm-virualenv-activate.", ".bat", false) - val envFile = FileUtil.createTempFile("pycharm-virualenv-envs.", ".tmp", false) - try { - FileUtil.copy(File(activate.first), activateFile); - FileUtil.appendToFile(activateFile, "\n\nset >" + envFile.absoluteFile) - - val command = if (activate.second != null) listOf(activateFile.path, activate.second!!) - else listOf(activateFile.path) - - return runProcessAndReadEnvs(command, envFile, LineSeparator.CRLF.separatorString) - } - finally { - FileUtil.delete(activateFile) - FileUtil.delete(envFile) - } - - } - override fun getShellProcessCommand(): MutableList { val shellPath = shell diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index 8d48be50e085..1404e5c88efb 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.sdk; import com.google.common.collect.ImmutableMap; @@ -949,7 +935,7 @@ public final class PythonSdkType extends SdkType { PyVirtualEnvReader reader = new PyVirtualEnvReader(sdkHome); if (reader.getActivate() != null) { try { - env.putAll(reader.readShellEnv().entrySet().stream() + env.putAll(reader.readPythonEnv().entrySet().stream() .filter((entry) -> PyVirtualEnvReader.Companion.getVirtualEnvVars().contains(entry.getKey()) ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } diff --git a/resources/src/componentSets/Compiler.xml b/resources/src/componentSets/Compiler.xml index 4350344eb250..0bb2c4f67d0d 100644 --- a/resources/src/componentSets/Compiler.xml +++ b/resources/src/componentSets/Compiler.xml @@ -13,6 +13,10 @@ com.intellij.packaging.artifacts.ArtifactManager com.intellij.packaging.impl.artifacts.ArtifactManagerImpl + + com.intellij.compiler.ExternalCompilerConfigurationStorage + + com.intellij.compiler.CompilerConfiguration com.intellij.compiler.CompilerConfigurationImpl diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlNSDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlNSDescriptorImpl.java index 1acfdc353b08..790e14d4e0bd 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlNSDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlNSDescriptorImpl.java @@ -90,7 +90,7 @@ public class HtmlNSDescriptorImpl implements XmlNSDescriptor, DumbAware, XmlNSTy } @Nullable - private static XmlElementDescriptor guessTagForCommonAttributes(@Nullable final XmlTag context) { + public static XmlElementDescriptor guessTagForCommonAttributes(@Nullable final XmlTag context) { if (context == null) return null; final XmlNSDescriptor nsDescriptor = context.getNSDescriptor(context.getNamespace(), false); if (nsDescriptor instanceof HtmlNSDescriptorImpl) {