/* * Copyright 2015-present Facebook, Inc. * * 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.facebook.buck.intellij.ideabuck.actions.choosetargets; import com.facebook.buck.intellij.ideabuck.actions.BuckQueryAction; import com.facebook.buck.intellij.ideabuck.build.BuckBuildTargetAliasParser; import com.facebook.buck.intellij.ideabuck.file.BuckFileUtil; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; import com.intellij.navigation.ChooseByNameContributor; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; public class ChooseTargetContributor implements ChooseByNameContributor { private static final String ALIAS_SEPARATOR = "::"; private static final String TARGET_NAME_SEPARATOR = ":"; private static final String BUILD_DIR_SEPARATOR = "/"; @Override public String[] getNames(Project project, boolean includeNonProjectItems) { List<String> names = new ArrayList<>(); names.addAll(getNamesFromPathSuggestions(project)); names.addAll(getNamesFromBuildTargetAlias(project)); return names.toArray(new String[names.size()]); } private List<String> getNamesFromBuildTargetAlias(Project project) { List<String> names = new ArrayList<>(); BuckBuildTargetAliasParser.parseAlias(project.getBasePath()); for (Map.Entry<String, Set<String>> entry : BuckBuildTargetAliasParser.sTargetAlias.entrySet()) { String target = entry.getKey(); Set<String> alias = entry.getValue(); target += ALIAS_SEPARATOR + Joiner.on(',').join(alias); names.add(target); } return names; } private List<String> getNamesFromPathSuggestions(Project project) { CurrentInputText currentInputText = new CurrentInputText(project); if (currentInputText.buildDir == null) { return Collections.emptyList(); } List<String> names = new ArrayList<>(); names.addAll(getAllBuildTargetsUnderDirectory(project, currentInputText.buildDir)); names.addAll(getNameSuggestionUnderPath(project, currentInputText.buildDir)); if (!currentInputText.hasBuildRule) { names.addAll(getNameSuggestionUnderPath(project, getParentDir(currentInputText.buildDir))); } return names; } private List<String> getAllBuildTargetsUnderDirectory(Project project, String buildDir) { List<String> names = new ArrayList<>(); // Try to get the relative path to the current input folder VirtualFile baseDir = project .getBaseDir() .findFileByRelativePath(appendSuffixIfNotEmpty(buildDir, File.separator)); if (baseDir == null) { return names; } names.add("//" + appendSuffixIfNotEmpty(buildDir, BUILD_DIR_SEPARATOR) + "..."); return names; } private static class CurrentInputText { public final String buildDir; public final boolean hasBuildRule; CurrentInputText(Project project) { ChooseByNamePopup chooseByNamePopup = project.getUserData(ChooseByNamePopup.CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY); if (chooseByNamePopup == null) { buildDir = null; hasBuildRule = false; return; } String currentText = chooseByNamePopup .getEnteredText() // Remove the begining // .replaceFirst("^/*", ""); // check if we have as input a proper target int targetSeparatorIndex = currentText.lastIndexOf(TARGET_NAME_SEPARATOR); if (targetSeparatorIndex != -1) { hasBuildRule = true; buildDir = currentText.substring(0, targetSeparatorIndex); } else { hasBuildRule = false; buildDir = currentText; } } } private String getParentDir(String currentDir) { int lastDirSeparatorPosition = currentDir.lastIndexOf(File.separator); if (lastDirSeparatorPosition == -1) { return ""; } else { return currentDir.substring(0, lastDirSeparatorPosition); } } private List<String> getNameSuggestionUnderPath(Project project, String buildDir) { List<String> names = new ArrayList<>(); // Try to get the relative path to the current input folder VirtualFile baseDir = project .getBaseDir() .findFileByRelativePath(appendSuffixIfNotEmpty(buildDir, File.separator)); if (baseDir == null) { return names; } // get the files under the base folder VirtualFile[] files = baseDir.getChildren(); for (VirtualFile file : files) { names.addAll(getNameSuggestionForVirtualFile(project, file, buildDir)); } return names; } private String appendSuffixIfNotEmpty(String source, String suffix) { if (!source.isEmpty()) { source += suffix; } return source; } private List<String> getNameSuggestionForVirtualFile( Project project, VirtualFile file, String buildDir) { // if the file is a directory we add it to the targets if (file.isDirectory()) { return new ArrayList<String>( Collections.singletonList( "//" + appendSuffixIfNotEmpty(buildDir, BUILD_DIR_SEPARATOR) + file.getName())); } else if (file.getName().equals(BuckFileUtil.getBuildFileName(project.getBasePath()))) { //if the file is a buck file we parse it and add its target names to the list return getBuildTargetFromBuildProjectFile(project, buildDir); } return Collections.emptyList(); } private List<String> getBuildTargetFromBuildProjectFile(Project project, String buildDir) { List<String> names = new ArrayList<>(); names.add(getAllBuildTargetsInSameDirectory(buildDir)); names.addAll( BuckQueryAction.execute( project, "//" + buildDir + TARGET_NAME_SEPARATOR, new Function<List<String>, Void>() { @Nullable @Override public Void apply(@Nullable List<String> strings) { ApplicationManager.getApplication() .invokeLater( new Runnable() { public void run() { ChooseByNamePopup chooseByNamePopup = project.getUserData( ChooseByNamePopup.CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY); // the user might have closed the window if (chooseByNamePopup != null) { // if we don't have them, just refresh the view when we do, if the // window is still open chooseByNamePopup.rebuildList(true); } } }); return null; } })); return names; } private String getAllBuildTargetsInSameDirectory(String buildDir) { return "//" + buildDir + TARGET_NAME_SEPARATOR; } @Override public NavigationItem[] getItemsByName( String name, String pattern, Project project, boolean includeNonProjectItems) { String alias = null; int index = name.lastIndexOf(ALIAS_SEPARATOR); if (index > 0) { alias = name.substring(index + ALIAS_SEPARATOR.length()); name = name.substring(0, index); } return new NavigationItem[] {new ChooseTargetItem(name, alias)}; } }