Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Michael Golubev
2014-03-17 15:35:00 +01:00
52 changed files with 505 additions and 444 deletions
@@ -227,7 +227,7 @@ public abstract class QuickFixFactory {
public abstract IntentionAction createCreateAnnotationMethodFromUsageFix(@NotNull PsiNameValuePair pair);
@NotNull
public abstract IntentionAction createOptimizeImportsFix();
public abstract IntentionAction createOptimizeImportsFix(boolean onTheFly);
public abstract void registerFixesForUnusedParameter(@NotNull PsiParameter parameter, @NotNull Object highlightInfo);
@@ -187,7 +187,7 @@ public class PostHighlightingPass extends ProgressableTextEditorHighlightingPass
private void optimizeImportsOnTheFly(@NotNull final Editor editor) {
if (myHasRedundantImports || myHasMissortedImports) {
IntentionAction optimizeImportsFix = QuickFixFactory.getInstance().createOptimizeImportsFix();
IntentionAction optimizeImportsFix = QuickFixFactory.getInstance().createOptimizeImportsFix(true);
if (optimizeImportsFix.isAvailable(myProject, editor, myFile) && myFile.isWritable()) {
optimizeImportsFix.invoke(myProject, editor, myFile);
}
@@ -793,7 +793,7 @@ public class PostHighlightingPass extends ProgressableTextEditorHighlightingPass
HighlightInfo.newHighlightInfo(JavaHighlightInfoTypes.UNUSED_IMPORT).range(importStatement).descriptionAndTooltip(description)
.create();
QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createOptimizeImportsFix(), unusedImportKey);
QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createOptimizeImportsFix(false), unusedImportKey);
QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createEnableOptimizeImportsOnTheFlyFix(), unusedImportKey);
myHasRedundantImports = true;
return info;
@@ -600,7 +600,7 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
@NotNull
@Override
public IntentionAction createOptimizeImportsFix() {
public IntentionAction createOptimizeImportsFix(final boolean onTheFly) {
final OptimizeImportsFix fix = new OptimizeImportsFix();
return new IntentionAction() {
@@ -618,7 +618,7 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return timeToOptimizeImports(file) && fix.isAvailable(project, editor, file);
return (!onTheFly || timeToOptimizeImports(file)) && fix.isAvailable(project, editor, file);
}
@Override
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -124,7 +124,8 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
myNewVirtualFile.setOriginalFile(origFile.getVirtualFile());
assert myNewFile != null : "PSI file is null";
assert myNewFile.getTextLength() == myNewVirtualFile.getLength() : "PSI / Virtual file text mismatch";
assert myNewFile.getTextLength() == myNewVirtualFile.getContent().length() : "PSI / Virtual file text mismatch";
myNewVirtualFile.setOriginalFile(origFile.getVirtualFile());
// suppress possible errors as in injected mode
myNewFile.putUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION,
@@ -182,7 +182,7 @@ class EventLogConsole {
lineColors.add(lineHighlighter);
}
myProjectModel.removeHandlers.put(notification, new Runnable() {
final Runnable removeHandler = new Runnable() {
@Override
public void run() {
for (RangeHighlighter color : lineColors) {
@@ -202,7 +202,13 @@ class EventLogConsole {
}
}
}
});
};
if (!notification.isExpired()) {
myProjectModel.removeHandlers.put(notification, removeHandler);
}
else {
removeHandler.run();
}
}
public Editor getConsoleEditor() {
@@ -0,0 +1,25 @@
package com.intellij.vcs.log;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* <p>Full details of a commit: all metadata (commit message, author, committer, etc.) but without changes.</p>
* <p>These details will be shown in dedicated panels displayed near the log, and can be used for in-memory filtering.</p>
* <p>An instance of this object can be obtained via
* {@link VcsLogObjectsFactory#createCommitMetadata(Hash, List, long, VirtualFile, String, String, String, String, String, String,long)
* VcsLogObjectsFactory#createMediumDetails}</p>
*/
public interface VcsCommitMetadata extends VcsShortCommitDetails {
@NotNull
String getFullMessage();
@NotNull
VcsUser getCommitter();
long getAuthorTime();
}
@@ -1,32 +1,31 @@
/*
* 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.
*/
package com.intellij.vcs.log;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
/**
* <p>Full details of a commit: all metadata (commit message, author, committer, etc.) and the changes.</p>
* <p>These details will be shown in dedicated panels displayed near the log.</p>
* <p>An instance of this object can be obtained via
* {@link VcsLogObjectsFactory#createFullDetails(Hash, List, long, VirtualFile, String, String, String, String, String, String, long,
* List, ContentRevisionFactory) VcsLogObjectsFactory#createFullDetails}</p>
*
* @author Kirill Likhodedov
* All metadata + changes.
*/
public interface VcsFullCommitDetails extends VcsShortCommitDetails {
@NotNull
String getFullMessage();
public interface VcsFullCommitDetails extends VcsCommitMetadata {
@NotNull
Collection<Change> getChanges();
@NotNull
VcsUser getCommitter();
long getAuthorTime();
}
@@ -3,12 +3,12 @@ package com.intellij.vcs.log;
import org.jetbrains.annotations.NotNull;
/**
* Filter which needs {@link VcsFullCommitDetails} to work.
* Filter which needs {@link VcsCommitMetadata} to work.
*
* @see VcsLogGraphFilter
*/
public interface VcsLogDetailsFilter extends VcsLogFilter {
boolean matches(@NotNull VcsFullCommitDetails details);
boolean matches(@NotNull VcsCommitMetadata details);
}
@@ -1,9 +1,11 @@
package com.intellij.vcs.log;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
/**
@@ -26,13 +28,18 @@ public interface VcsLogObjectsFactory {
VcsShortCommitDetails createShortDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long timeStamp,
VirtualFile root, @NotNull String subject, @NotNull String authorName, String authorEmail);
@NotNull
VcsCommitMetadata createCommitMetadata(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
@NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
@NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
long authorTime);
@NotNull
VcsFullCommitDetails createFullDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
@NotNull String subject,
@NotNull String authorName, @NotNull String authorEmail, @NotNull String message,
@NotNull String committerName,
@NotNull String committerEmail, long authorTime, @NotNull List<Change> changes,
@NotNull ContentRevisionFactory contentRevisionFactory);
@NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
@NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
long authorTime,
@NotNull ThrowableComputable<Collection<Change>, ? extends Exception> changesGetter);
@NotNull
VcsUser createUser(@NotNull String name, @NotNull String email);
@@ -22,7 +22,7 @@ public interface VcsLogProvider {
* Reads the given number of the most recent commits from the log.
*/
@NotNull
List<? extends VcsFullCommitDetails> readFirstBlock(@NotNull VirtualFile root, boolean ordered, int commitCount) throws VcsException;
List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root, boolean ordered, int commitCount) throws VcsException;
/**
* <p>Reads the whole history, but only hashes & parents.</p>
@@ -11,11 +11,12 @@ import java.util.List;
* <p>These details will be displayed in the log table.</p>
*
* <p>An instance of this object can be obtained via
* {@link VcsLogObjectsFactory#createShortDetails(Hash, List, long, VirtualFile, String, String, String) VcsLogObjectsFactory#createShortDetails}
* {@link VcsLogObjectsFactory#createShortDetails(Hash, List, long, VirtualFile, String, String, String)
* VcsLogObjectsFactory#createShortDetails}
* </p>
*
* @see VcsCommitMetadata
* @see VcsFullCommitDetails
* @author Kirill Likhodedov
*/
public interface VcsShortCommitDetails {
@@ -2,17 +2,17 @@ package com.intellij.vcs.log.data;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLogProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* The CommitDetailsGetter is responsible for getting {@link VcsFullCommitDetails complete commit details} from the cache or from the VCS.
*
* @author Kirill Likhodedov
*/
public class CommitDetailsGetter extends DataGetter<VcsFullCommitDetails> {
@@ -20,6 +20,12 @@ public class CommitDetailsGetter extends DataGetter<VcsFullCommitDetails> {
super(dataHolder, logProviders, new VcsCommitCache<VcsFullCommitDetails>());
}
@Nullable
@Override
protected VcsFullCommitDetails getFromAdditionalCache(@NotNull Hash hash) {
return null;
}
@NotNull
@Override
protected List<? extends VcsFullCommitDetails> readDetails(@NotNull VcsLogProvider logProvider, @NotNull VirtualFile root,
@@ -81,7 +81,7 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
}
@Nullable
public <CommitId> T getCommitData(int row, @NotNull AbstractVcsLogTableModel<?> tableModel) {
public T getCommitData(int row, @NotNull AbstractVcsLogTableModel<?> tableModel) {
assert EventQueue.isDispatchThread();
Hash hash = tableModel.getHashAtRow(row);
if (hash == null) {
@@ -113,10 +113,16 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
}
return details;
}
return (T)myDataHolder.getTopCommitDetails(hash);
return getFromAdditionalCache(hash);
}
private <CommitId> void runLoadAroundCommitData(int row, @NotNull AbstractVcsLogTableModel<?> tableModel) {
/**
* Lookup somewhere else but the standard cache.
*/
@Nullable
protected abstract T getFromAdditionalCache(@NotNull Hash hash);
private void runLoadAroundCommitData(int row, @NotNull AbstractVcsLogTableModel<?> tableModel) {
long taskNumber = myCurrentTaskIndex++;
MultiMap<VirtualFile, Hash> commits = getCommitsAround(row, tableModel, UP_PRELOAD_COUNT, DOWN_PRELOAD_COUNT);
for (Map.Entry<VirtualFile, Collection<Hash>> hashesByRoots : commits.entrySet()) {
@@ -137,9 +143,8 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
}
@NotNull
private static <CommitId> MultiMap<VirtualFile, Hash> getCommitsAround(int selectedRow,
@NotNull AbstractVcsLogTableModel<?> model,
int above, int below) {
private static MultiMap<VirtualFile, Hash> getCommitsAround(int selectedRow, @NotNull AbstractVcsLogTableModel<?> model,
int above, int below) {
MultiMap<VirtualFile, Hash> commits = MultiMap.create();
for (int row = Math.max(0, selectedRow - above); row < selectedRow + below && row < model.getRowCount(); row++) {
Hash hash = model.getHashAtRow(row);
@@ -1,26 +1,23 @@
package com.intellij.vcs.log.data;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.SimpleContentRevision;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.ContentRevisionFactory;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.impl.VcsFullCommitDetailsImpl;
import com.intellij.vcs.log.impl.VcsChangesLazilyParsedDetails;
import com.intellij.vcs.log.impl.VcsUserImpl;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
/**
* Fake {@link VcsFullCommitDetailsImpl} implementation that is used to indicate that details are not ready for the moment,
* Fake {@link com.intellij.vcs.log.impl.VcsCommitMetadataImpl} implementation that is used to indicate that details are not ready for the moment,
* they are being retrieved from the VCS.
*
* @author Kirill Likhodedov
*/
public class LoadingDetails extends VcsFullCommitDetailsImpl {
public class LoadingDetails extends VcsChangesLazilyParsedDetails {
private static final VcsUserImpl STUB_USER = new VcsUserImpl("", "");
@@ -28,19 +25,12 @@ public class LoadingDetails extends VcsFullCommitDetailsImpl {
public LoadingDetails(@NotNull Hash hash, long loadingTaskIndex, @NotNull VirtualFile root) {
super(hash, Collections.<Hash>emptyList(), -1, root, "Loading...", STUB_USER, "", STUB_USER, -1,
Collections.<Change>emptyList(), new ContentRevisionFactory() {
@NotNull
@Override
public ContentRevision createRevision(@NotNull VirtualFile file, @NotNull Hash hash) {
return new SimpleContentRevision("", new FilePathImpl(file), hash.asString());
}
@NotNull
@Override
public ContentRevision createRevision(@NotNull VirtualFile root, @NotNull String path, @NotNull Hash hash) {
return new SimpleContentRevision("", new FilePathImpl(new File(path), false), hash.asString());
}
});
new ThrowableComputable<Collection<Change>, Exception>() {
@Override
public Collection<Change> compute() throws Exception {
return Collections.emptyList();
}
});
myLoadingTaskIndex = loadingTaskIndex;
}
@@ -2,22 +2,27 @@ package com.intellij.vcs.log.data;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcs.log.VcsShortCommitDetails;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* @author Kirill Likhodedov
*/
public class MiniDetailsGetter extends DataGetter<VcsShortCommitDetails> {
MiniDetailsGetter(@NotNull VcsLogDataHolder dataHolder, @NotNull Map<VirtualFile, VcsLogProvider> logProviders) {
super(dataHolder, logProviders, new VcsCommitCache<VcsShortCommitDetails>());
}
@Nullable
@Override
protected VcsShortCommitDetails getFromAdditionalCache(@NotNull Hash hash) {
return myDataHolder.getTopCommitDetails(hash);
}
@NotNull
@Override
protected List<? extends VcsShortCommitDetails> readDetails(@NotNull VcsLogProvider logProvider, @NotNull VirtualFile root,
@@ -127,7 +127,7 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
* which is important because these details will be constantly visible to the user,
* thus it would be annoying to re-load them from VCS if the cache overflows.
*/
@NotNull private final Map<Hash, VcsFullCommitDetails> myTopCommitsDetailsCache = ContainerUtil.newConcurrentMap();
@NotNull private final Map<Hash, VcsCommitMetadata> myTopCommitsDetailsCache = ContainerUtil.newConcurrentMap();
/**
* Checks if "load more commit details" process is already in progress to avoid scheduling multiple similar processes.
@@ -488,7 +488,7 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
boolean orderedForRepo = ordered && !logProvider.supportsFastUnorderedCommits(); // will order manually
int commitCountForRepo = orderedForRepo ? commitsCount : commitsCount * 2; // but need to request more commits
List<? extends VcsFullCommitDetails> firstBlockDetails = logProvider.readFirstBlock(root, orderedForRepo, commitCountForRepo);
List<? extends VcsCommitMetadata> firstBlockDetails = logProvider.readFirstBlock(root, orderedForRepo, commitCountForRepo);
sw.report();
sw = StopWatch.start("readAllRefs for" + root.getName());
Collection<VcsRef> newRefs = logProvider.readAllRefs(root);
@@ -503,8 +503,8 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
return infoByRoot.entrySet();
}
private void storeUsers(@NotNull List<? extends VcsFullCommitDetails> details) {
for (VcsFullCommitDetails detail : details) {
private void storeUsers(@NotNull List<? extends VcsCommitMetadata> details) {
for (VcsCommitMetadata detail : details) {
myUserRegistry.addUser(detail.getAuthor());
myUserRegistry.addUser(detail.getCommitter());
}
@@ -634,18 +634,18 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
});
}
private void storeTopCommitsDetailsInCache(List<? extends VcsFullCommitDetails> firstBlockDetails) {
private void storeTopCommitsDetailsInCache(List<? extends VcsCommitMetadata> firstBlockDetails) {
// some commits may be no longer available (e.g. rewritten after rebase), but let them stay in the cache:
// they won't occupy too much place, while checking & removing them is not easy.
for (VcsFullCommitDetails detail : firstBlockDetails) {
for (VcsCommitMetadata detail : firstBlockDetails) {
myTopCommitsDetailsCache.put(detail.getHash(), detail);
}
}
private List<TimedVcsCommit> getCommitsFromDetails(List<? extends VcsFullCommitDetails> firstBlockDetails) {
List<TimedVcsCommit> commits = ContainerUtil.map(firstBlockDetails, new Function<VcsFullCommitDetails, TimedVcsCommit>() {
private List<TimedVcsCommit> getCommitsFromDetails(List<? extends VcsCommitMetadata> firstBlockDetails) {
List<TimedVcsCommit> commits = ContainerUtil.map(firstBlockDetails, new Function<VcsCommitMetadata, TimedVcsCommit>() {
@Override
public TimedVcsCommit fun(VcsFullCommitDetails details) {
public TimedVcsCommit fun(VcsCommitMetadata details) {
return new CompactCommit(details.getHash(), details.getParents(), details.getTime());
}
});
@@ -724,7 +724,7 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
}
@Nullable
public VcsFullCommitDetails getTopCommitDetails(@NotNull Hash hash) {
public VcsCommitMetadata getTopCommitDetails(@NotNull Hash hash) {
return myTopCommitsDetailsCache.get(hash);
}
@@ -15,7 +15,7 @@
*/
package com.intellij.vcs.log.data;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsCommitMetadata;
import com.intellij.vcs.log.VcsLogDateFilter;
import com.intellij.vcs.log.VcsLogDetailsFilter;
import org.jetbrains.annotations.NotNull;
@@ -34,7 +34,7 @@ public class VcsLogDateFilterImpl implements VcsLogDateFilter, VcsLogDetailsFilt
}
@Override
public boolean matches(@NotNull VcsFullCommitDetails details) {
public boolean matches(@NotNull VcsCommitMetadata details) {
Date date = new Date(details.getTime()); // Git itself also filters by commit time, not author time
boolean matches = true;
if (myAfter != null) {
@@ -49,7 +49,7 @@ public class VcsLogFilterer {
private AbstractVcsLogTableModel applyDetailsFilter(DataPack dataPack, List<VcsLogDetailsFilter> detailsFilters) {
if (!detailsFilters.isEmpty()) {
List<Hash> filteredCommits = filterByDetails(dataPack, detailsFilters);
List<Hash> filteredCommits = filterInMemory(dataPack, detailsFilters);
if (filteredCommits.isEmpty()) {
return new EmptyTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.INITIAL);
}
@@ -154,44 +154,42 @@ public class VcsLogFilterer {
}
@NotNull
private List<Hash> filterByDetails(@NotNull DataPack dataPack, @NotNull List<VcsLogDetailsFilter> detailsFilters) {
private List<Hash> filterInMemory(@NotNull DataPack dataPack, @NotNull List<VcsLogDetailsFilter> detailsFilters) {
List<Hash> result = ContainerUtil.newArrayList();
int topCommits = myLogDataHolder.getSettings().getRecentCommitsCount();
List<Integer> visibleCommits = VcsLogUtil.getVisibleCommits(dataPack.getGraphFacade());
for (int i = 0; i < topCommits && i < visibleCommits.size(); i++) {
int commitIndex = visibleCommits.get(i);
final VcsFullCommitDetails details = getDetailsFromCache(commitIndex);
if (details == null) {
// Details for recent commits should be available in the cache.
// However if they are not there for some reason, we stop filtering.
// If we continue, if this commit without details matches filters,
// if details of an older commit are found in the cache, and if this older commit matches the filter,
// then we will return the list which incorrectly misses some matching commit in the middle.
// => Instead we rather will return a smaller list: this is not a problem,
// because the VCS will be requested for filtered details if there are not enough of them.
LOG.debug("No details found for a recent commit " + myLogDataHolder.getHash(commitIndex));
for (int visibleCommit : VcsLogUtil.getVisibleCommits(dataPack.getGraphFacade())) {
VcsCommitMetadata data = getDetailsFromCache(visibleCommit);
if (data == null) {
// no more continuous details in the cache
break;
}
boolean allFiltersMatch = !ContainerUtil.exists(detailsFilters, new Condition<VcsLogDetailsFilter>() {
@Override
public boolean value(VcsLogDetailsFilter filter) {
return !filter.matches(details);
}
});
if (allFiltersMatch) {
result.add(details.getHash());
if (matchesAllFilters(data, detailsFilters)) {
result.add(data.getHash());
}
}
return result;
}
private static boolean matchesAllFilters(@NotNull final VcsCommitMetadata commit, @NotNull List<VcsLogDetailsFilter> detailsFilters) {
return !ContainerUtil.exists(detailsFilters, new Condition<VcsLogDetailsFilter>() {
@Override
public boolean value(VcsLogDetailsFilter filter) {
return !filter.matches(commit);
}
});
}
@Nullable
private VcsFullCommitDetails getDetailsFromCache(final int commitIndex) {
final Ref<VcsFullCommitDetails> ref = Ref.create();
private VcsCommitMetadata getDetailsFromCache(final int commitIndex) {
final Hash hash = myLogDataHolder.getHash(commitIndex);
VcsCommitMetadata details = myLogDataHolder.getTopCommitDetails(hash);
if (details != null) {
return details;
}
final Ref<VcsCommitMetadata> ref = Ref.create();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
ref.set(myLogDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(myLogDataHolder.getHash(commitIndex)));
ref.set(myLogDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash));
}
});
return ref.get();
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.vcs.log.VcsCommitMetadata;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLogDetailsFilter;
import com.intellij.vcs.log.VcsLogStructureFilter;
@@ -68,18 +69,23 @@ public class VcsLogStructureFilterImpl implements VcsLogDetailsFilter, VcsLogStr
}
@Override
public boolean matches(@NotNull VcsFullCommitDetails details) {
for (Change change : details.getChanges()) {
ContentRevision before = change.getBeforeRevision();
if (before != null && matches(before.getFile().getPath())) {
return true;
}
ContentRevision after = change.getAfterRevision();
if (after != null && matches(after.getFile().getPath())) {
return true;
public boolean matches(@NotNull VcsCommitMetadata details) {
if ((details instanceof VcsFullCommitDetails)) {
for (Change change : ((VcsFullCommitDetails)details).getChanges()) {
ContentRevision before = change.getBeforeRevision();
if (before != null && matches(before.getFile().getPath())) {
return true;
}
ContentRevision after = change.getAfterRevision();
if (after != null && matches(after.getFile().getPath())) {
return true;
}
}
return false;
}
else {
return false;
}
return false;
}
private boolean matches(@NotNull final String path) {
@@ -31,9 +31,9 @@ import java.util.List;
/**
* Allows to postpone changes parsing, which might take long for a large amount of commits,
* because {@link Change} holds {@link FilePathImpl} which makes costly refreshes and type detections
* because {@link Change} holds {@link FilePathImpl} which makes costly refreshes and type detections.
*/
public class VcsChangesLazilyParsedDetails extends VcsCommitDetailsExceptChanges implements VcsFullCommitDetails {
public class VcsChangesLazilyParsedDetails extends VcsCommitMetadataImpl implements VcsFullCommitDetails {
private static final Logger LOG = Logger.getInstance(VcsChangesLazilyParsedDetails.class);
@@ -17,35 +17,30 @@ package com.intellij.vcs.log.impl;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsCommitMetadata;
import com.intellij.vcs.log.VcsUser;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Holds all information about commit, except {@link #getChanges() the changes}
* To allow to reuse common getters in implementations of different getChanges() laziness level.
*/
abstract class VcsCommitDetailsExceptChanges extends VcsShortCommitDetailsImpl implements VcsFullCommitDetails {
public class VcsCommitMetadataImpl extends VcsShortCommitDetailsImpl implements VcsCommitMetadata {
@NotNull private final String myFullMessage;
@NotNull private final VcsUser myCommitter;
private final long myAuthorTime;
public VcsCommitDetailsExceptChanges(@NotNull Hash hash, @NotNull List<Hash> parents, long timeStamp, @NotNull VirtualFile root,
@NotNull String subject, @NotNull VcsUser author, @NotNull String message,
@NotNull VcsUser committer, long authorTime) {
public VcsCommitMetadataImpl(@NotNull Hash hash, @NotNull List<Hash> parents, long timeStamp, @NotNull VirtualFile root,
@NotNull String subject, @NotNull VcsUser author, @NotNull String message,
@NotNull VcsUser committer, long authorTime) {
super(hash, parents, timeStamp, root, subject, author);
myCommitter = committer;
myAuthorTime = authorTime;
myFullMessage = message;
}
@Override
@NotNull
public final String getFullMessage() {
public String getFullMessage() {
return myFullMessage;
}
@@ -1,120 +0,0 @@
package com.intellij.vcs.log.impl;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.ContentRevisionFactory;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsUser;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
public class VcsFullCommitDetailsImpl extends VcsCommitDetailsExceptChanges implements VcsFullCommitDetails {
@NotNull private final Collection<LightChange> myChanges;
public VcsFullCommitDetailsImpl(@NotNull Hash hash, @NotNull List<Hash> parents, long time, @NotNull VirtualFile root,
@NotNull String subject, @NotNull VcsUser author, @NotNull String message,
@NotNull VcsUser committer, long authorTime,
@NotNull List<Change> changes, @NotNull final ContentRevisionFactory contentRevisionFactory) {
super(hash, parents, time, root, subject, author, message, committer, authorTime);
myChanges = ContainerUtil.map(changes, new Function<Change, LightChange>() {
@Override
public LightChange fun(Change change) {
return LightChange.create(contentRevisionFactory, VcsFullCommitDetailsImpl.this, change);
}
});
}
@Override
@NotNull
public final Collection<Change> getChanges() {
return ContainerUtil.map(myChanges, new Function<LightChange, Change>() {
@Override
public Change fun(LightChange change) {
return change.toChange();
}
});
}
private static class LightChange {
private ContentRevisionFactory myContentRevisionFactory;
private VcsFullCommitDetails myDetails;
private boolean myModification;
private VirtualFile myBeforeFile;
private VirtualFile myAfterFile;
private String myBeforePath;
private String myAfterPath;
private static LightChange create(ContentRevisionFactory contentRevisionFactory, VcsFullCommitDetails details, Change change) {
LightChange lc = new LightChange();
Change.Type type = change.getType();
lc.myModification = type == Change.Type.MODIFICATION;
lc.myContentRevisionFactory = contentRevisionFactory;
ContentRevision before = change.getBeforeRevision();
if (before != null && !lc.myModification) { // don't store the same path twice (for modification store only after path)
FilePath filePath = before.getFile();
if (filePath.getVirtualFile() == null) {
lc.myBeforePath = filePath.getIOFile().getPath();
}
else {
lc.myBeforeFile = filePath.getVirtualFile();
}
}
ContentRevision after = change.getAfterRevision();
if (after != null) {
FilePath filePath = after.getFile();
if (filePath.getVirtualFile() == null) {
lc.myAfterPath = filePath.getIOFile().getPath();
}
else {
lc.myAfterFile = filePath.getVirtualFile();
}
}
lc.myDetails = details;
return lc;
}
Change toChange() {
List<Hash> parents = myDetails.getParents();
Hash parentHash = parents.isEmpty() ? null : parents.get(0); // no parents for the initial commit
ContentRevision before = null;
if (parentHash != null) {
if (myBeforeFile != null) {
before = myContentRevisionFactory.createRevision(myBeforeFile, parentHash);
}
else if (myBeforePath != null) {
before = myContentRevisionFactory.createRevision(myDetails.getRoot(), myBeforePath, parentHash);
}
}
ContentRevision after = null;
if (myAfterFile != null) {
after = myContentRevisionFactory.createRevision(myAfterFile, myDetails.getHash());
if (myModification && parentHash != null) { // we didn't store myBeforeFile/Path to avoid duplicate path
before = myContentRevisionFactory.createRevision(myAfterFile, parentHash);
}
}
else if (myAfterPath != null) {
after = myContentRevisionFactory.createRevision(myDetails.getRoot(), myAfterPath, myDetails.getHash());
if (myModification && parentHash != null) {
before = myContentRevisionFactory.createRevision(myDetails.getRoot(), myAfterPath, parentHash);
}
}
return new Change(before, after);
}
}
}
@@ -12,6 +12,7 @@ import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ex.ToolWindowManagerListener;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
@@ -31,6 +32,7 @@ import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VcsLogUiProperties;
import com.intellij.vcs.log.ui.VcsLogColorManagerImpl;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
import com.intellij.vcs.log.ui.frame.VcsLogGraphTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -80,6 +82,15 @@ public class VcsLogManager implements Disposable {
myLogDataHolder = vcsLogDataHolder;
myUi = logUI;
mainPanel.init(logUI.getMainFrame().getMainComponent());
final VcsLogGraphTable graphTable = logUI.getTable();
if (graphTable.getRowCount() > 0) {
IdeFocusManager.getInstance(myProject).requestFocus(graphTable, true).doWhenProcessed(new Runnable() {
@Override
public void run() {
graphTable.setRowSelectionInterval(0, 0);
}
});
}
myLogRefresher = new PostponeableLogRefresher(myProject, vcsLogDataHolder);
refreshLogOnVcsEvents(logProviders);
}
@@ -1,6 +1,7 @@
package com.intellij.vcs.log.impl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.NotNullFunction;
@@ -8,6 +9,7 @@ import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
/**
@@ -52,15 +54,25 @@ public class VcsLogObjectsFactoryImpl implements VcsLogObjectsFactory {
@NotNull
@Override
public VcsFullCommitDetails createFullDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long time, @NotNull VirtualFile root,
public VcsCommitMetadata createCommitMetadata(@NotNull Hash hash, @NotNull List<Hash> parents, long time, @NotNull VirtualFile root,
@NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
@NotNull String message, @NotNull String committerName,
@NotNull String committerEmail, long authorTime, @NotNull List<Change> changes,
@NotNull ContentRevisionFactory contentRevisionFactory) {
@NotNull String committerEmail, long authorTime) {
VcsUser author = createUser(authorName, authorEmail);
VcsUser committer = createUser(committerName, committerEmail);
return new VcsFullCommitDetailsImpl(hash, parents, time, root, subject, author, message, committer, authorTime,
changes, contentRevisionFactory);
return new VcsCommitMetadataImpl(hash, parents, time, root, subject, author, message, committer, authorTime);
}
@NotNull
@Override
public VcsFullCommitDetails createFullDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
@NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
@NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
long authorTime,
@NotNull ThrowableComputable<Collection<Change>, ? extends Exception> changesGetter) {
VcsUser author = createUser(authorName, authorEmail);
VcsUser committer = createUser(committerName, committerEmail);
return new VcsChangesLazilyParsedDetails(hash, parents, time, root, subject, author, message, committer, authorTime, changesGetter);
}
@NotNull
@@ -137,7 +137,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
@Override
public void run() {
final GraphAnswer answer = myDataPack.getGraphFacade().performAction(LinearBranchesExpansionAction.EXPAND);
UIUtil.invokeLaterIfNeeded(new Runnable() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
handleAnswer(answer);
@@ -153,7 +153,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
@Override
public void run() {
final GraphAnswer answer = myDataPack.getGraphFacade().performAction(LinearBranchesExpansionAction.COLLAPSE);
UIUtil.invokeLaterIfNeeded(new Runnable() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
handleAnswer(answer);
@@ -297,7 +297,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
public void run() {
final TIntHashSet previouslySelected = getSelectedCommits();
final AbstractVcsLogTableModel newModel = myFilterer.applyFiltersAndUpdateUi(dataPack, getFilters());
UIUtil.invokeLaterIfNeeded(new Runnable() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
myDataPack = dataPack;
@@ -21,7 +21,7 @@ import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsCommitMetadata;
import com.intellij.vcs.log.VcsLogUserFilter;
import com.intellij.vcs.log.VcsUser;
import com.intellij.vcs.log.data.VcsLogDataHolder;
@@ -117,7 +117,7 @@ class UserFilterPopupComponent extends MultipleValueFilterPopupComponent<VcsLogU
}
@Override
public boolean matches(@NotNull final VcsFullCommitDetails commit) {
public boolean matches(@NotNull final VcsCommitMetadata commit) {
return ContainerUtil.exists(getUserNames(commit.getRoot()), new Condition<String>() {
@Override
public boolean value(String user) {
@@ -15,7 +15,7 @@
*/
package com.intellij.vcs.log.ui.filter;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsCommitMetadata;
import com.intellij.vcs.log.VcsLogTextFilter;
import com.intellij.vcs.log.VcsLogDetailsFilter;
import org.jetbrains.annotations.NotNull;
@@ -29,7 +29,7 @@ public class VcsLogTextFilterImpl implements VcsLogDetailsFilter, VcsLogTextFilt
}
@Override
public boolean matches(@NotNull VcsFullCommitDetails details) {
public boolean matches(@NotNull VcsCommitMetadata details) {
return details.getFullMessage().toLowerCase().contains(myText.toLowerCase());
}
+1 -1
View File
@@ -47,7 +47,7 @@
<highlightErrorFilter implementation="org.intellij.plugins.intelliLang.inject.FrankensteinErrorFilter"/>
<daemon.highlightInfoFilter implementation="org.intellij.plugins.intelliLang.inject.FrankensteinErrorFilter"/>
<projectConfigurable displayName="Language Injections" instance="org.intellij.plugins.intelliLang.InjectionsSettingsUI" nonDefaultProject="true"/>
<projectConfigurable displayName="Language Injections" dynamic="true" instance="org.intellij.plugins.intelliLang.InjectionsSettingsUI" nonDefaultProject="true"/>
<multiHostInjector implementation="org.intellij.plugins.intelliLang.inject.CommentLanguageInjector"/>
<multiHostInjector implementation="org.intellij.plugins.intelliLang.inject.TemporaryPlacesInjector"/>
@@ -25,6 +25,8 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
@@ -36,7 +38,6 @@ import git4idea.config.GitVcsSettings;
import git4idea.history.browser.GitHeavyCommit;
import git4idea.history.wholeTree.AbstractHash;
import git4idea.history.wholeTree.GitCommitDetailsProvider;
import git4idea.log.GitContentRevisionFactory;
import git4idea.repo.GitRepository;
import icons.Git4ideaIcons;
import org.jetbrains.annotations.NotNull;
@@ -212,10 +213,16 @@ public class GitCherryPickAction extends DumbAwareAction {
return factory.createHash(hashValue);
}
});
final List<Change> changes = commit.getChanges();
return factory.createFullDetails(
factory.createHash(commit.getHash().getValue()), parents, commit.getAuthorTime(), commit.getRoot(), commit.getSubject(),
commit.getAuthor(), commit.getAuthorEmail(), commit.getDescription(), commit.getCommitter(), commit.getCommitterEmail(),
commit.getDate().getTime(), commit.getChanges(), GitContentRevisionFactory.getInstance(project)
commit.getDate().getTime(), new ThrowableComputable<Collection<Change>, Exception>() {
@Override
public Collection<Change> compute() throws Exception {
return changes;
}
}
);
}
});
@@ -35,10 +35,7 @@ import com.intellij.openapi.vcs.history.VcsRevisionDescription;
import com.intellij.openapi.vcs.history.VcsRevisionDescriptionImpl;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.AsynchConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.*;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
@@ -615,12 +612,7 @@ public class GitHistoryUtils {
@NotNull
private static TimedVcsCommit convert(@NotNull GitLogRecord rec, @NotNull VcsLogObjectsFactory factory) {
List<Hash> parents = ContainerUtil.map(rec.getParentsHashes(), new Function<String, Hash>() {
@Override
public Hash fun(String s) {
return HashImpl.build(s);
}
});
List<Hash> parents = getParentHashes(factory, rec);
return factory.createTimedCommit(HashImpl.build(rec.getHash()), parents, rec.getCommitTime());
}
@@ -743,6 +735,26 @@ public class GitHistoryUtils {
return rc;
}
@NotNull
public static List<? extends VcsCommitMetadata> loadMetadata(@NotNull Project project, @NotNull final VirtualFile root,
@NotNull String... parameters) throws VcsException {
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
if (factory == null) {
return Collections.emptyList();
}
return loadDetails(project, root, false, new NullableFunction<GitLogRecord, VcsCommitMetadata>() {
@Nullable
@Override
public VcsCommitMetadata fun(GitLogRecord record) {
return factory.createCommitMetadata(factory.createHash(record.getHash()), getParentHashes(factory, record), record.getCommitTime(),
root, record.getSubject(), record.getAuthorName(), record.getAuthorEmail(),
record.getFullMessage(), record.getCommitterName(), record.getCommitterEmail(),
record.getAuthorTimeStamp());
}
}, parameters);
}
/**
* <p>Get & parse git log detailed output with commits, their parents and their changes.</p>
*
@@ -756,27 +768,9 @@ public class GitHistoryUtils {
if (factory == null) {
return Collections.emptyList();
}
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.STATUS, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME,
AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, PARENTS, SUBJECT, BODY, RAW_BODY);
h.setStdoutSuppressed(true);
h.addParameters(parameters);
h.addParameters("-M", "--name-status", parser.getPretty(), "--encoding=UTF-8");
h.addParameters("--full-history", "--sparse");
h.endOptions();
StopWatch sw = StopWatch.start("git log --all-details");
String output = h.run();
sw.report();
sw = StopWatch.start("parsing");
List<GitLogRecord> records = parser.parse(output);
sw.report();
sw = StopWatch.start("Creating GitCommit objects");
List<GitCommit> gitCommits = ContainerUtil.mapNotNull(records, new Function<GitLogRecord, GitCommit>() {
return loadDetails(project, root, true, new NullableFunction<GitLogRecord, GitCommit>() {
@Override
@Nullable
public GitCommit fun(GitLogRecord record) {
try {
return createCommit(project, root, record, factory);
@@ -786,25 +780,59 @@ public class GitHistoryUtils {
return null;
}
}
});
}, parameters);
}
@NotNull
public static <T> List<T> loadDetails(@NotNull final Project project, @NotNull final VirtualFile root, boolean withChanges,
@NotNull NullableFunction<GitLogRecord, T> converter, String... parameters)
throws VcsException {
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
GitLogParser.NameStatus status = withChanges ? GitLogParser.NameStatus.STATUS : GitLogParser.NameStatus.NONE;
GitLogParser parser = new GitLogParser(project, status, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME,
AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, PARENTS, SUBJECT, BODY, RAW_BODY);
h.setStdoutSuppressed(true);
h.addParameters(parameters);
h.addParameters(parser.getPretty(), "--encoding=UTF-8");
h.addParameters("--full-history", "--sparse");
if (withChanges) {
h.addParameters("-M", "--name-status");
}
h.endOptions();
StopWatch sw = StopWatch.start("loading details");
String output = h.run();
sw.report();
return gitCommits;
sw = StopWatch.start("parsing");
List<GitLogRecord> records = parser.parse(output);
sw.report();
sw = StopWatch.start("Creating objects");
List<T> commits = ContainerUtil.mapNotNull(records, converter);
sw.report();
return commits;
}
private static GitCommit createCommit(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLogRecord record,
@NotNull VcsLogObjectsFactory factory) throws VcsException {
List<Hash> parents = ContainerUtil.map(record.getParentsHashes(), new Function<String, Hash>() {
@Override
public Hash fun(String hash) {
return HashImpl.build(hash);
}
});
List<Hash> parents = getParentHashes(factory, record);
return new GitCommit(project, HashImpl.build(record.getHash()), parents, record.getCommitTime(), root, record.getSubject(),
factory.createUser(record.getAuthorName(), record.getAuthorEmail()), record.getFullMessage(),
factory.createUser(record.getCommitterName(), record.getCommitterEmail()), record.getAuthorTimeStamp(),
record.getStatusInfos());
}
@NotNull
private static List<Hash> getParentHashes(@NotNull final VcsLogObjectsFactory factory, @NotNull GitLogRecord record) {
return ContainerUtil.map(record.getParentsHashes(), new Function<String, Hash>() {
@Override
public Hash fun(String hash) {
return factory.createHash(hash);
}
});
}
/**
* <p>Returns the history queried by {@code git log}} command with a possibility to asynchronously process each log record
* returned by Git.</p>
@@ -66,8 +66,7 @@ public class GitLogProvider implements VcsLogProvider {
@NotNull
@Override
public List<? extends VcsFullCommitDetails> readFirstBlock(@NotNull VirtualFile root,
boolean ordered, int commitCount) throws VcsException {
public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root, boolean ordered, int commitCount) throws VcsException {
if (!isRepositoryReady(root)) {
return Collections.emptyList();
}
@@ -77,7 +76,7 @@ public class GitLogProvider implements VcsLogProvider {
if (ordered) {
params = ArrayUtil.append(params, "--date-order");
}
return GitHistoryUtils.history(myProject, root, params);
return GitHistoryUtils.loadMetadata(myProject, root, params);
}
@NotNull
@@ -92,7 +91,8 @@ public class GitLogProvider implements VcsLogProvider {
@NotNull
@Override
public List<? extends VcsShortCommitDetails> readShortDetails(@NotNull VirtualFile root, @NotNull List<String> hashes) throws VcsException {
public List<? extends VcsShortCommitDetails> readShortDetails(@NotNull VirtualFile root,
@NotNull List<String> hashes) throws VcsException {
return GitHistoryUtils.readMiniDetails(myProject, root, hashes);
}
@@ -286,5 +286,4 @@ public class GitLogProvider implements VcsLogProvider {
}
return true;
}
}
@@ -122,7 +122,7 @@ public class GitBranchWidget extends EditorBasedWidget implements StatusBarWidge
}
@Override
// have to effect since the click opens a list popup, and the consumer is not called for the MultipleTextValuesPresentation
// have no effect since the click opens a list popup, and the consumer is not called for the MultipleTextValuesPresentation
public Consumer<MouseEvent> getClickConsumer() {
return new Consumer<MouseEvent>() {
public void consume(MouseEvent mouseEvent) {
@@ -20,6 +20,7 @@ import com.google.common.collect.Collections2;
import com.intellij.dvcs.test.MockVcsHelper;
import com.intellij.dvcs.test.MockVirtualFile;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.changes.Change;
@@ -39,7 +40,6 @@ import cucumber.annotation.en.Then;
import cucumber.annotation.en.When;
import git4idea.cherrypick.GitCherryPicker;
import git4idea.config.GitVersionSpecialty;
import git4idea.log.GitContentRevisionFactory;
import java.util.*;
@@ -260,11 +260,17 @@ public class GitCherryPickStepdefs {
}
private static VcsFullCommitDetails mockCommit(String hash, String message) {
List<Change> changes = new ArrayList<Change>();
final List<Change> changes = new ArrayList<Change>();
changes.add(new Change(null, new MockContentRevision(new FilePathImpl(new MockVirtualFile("name")), VcsRevisionNumber.NULL)));
return ServiceManager.getService(myProject, VcsLogObjectsFactory.class).createFullDetails(
HashImpl.build(hash), Collections.<Hash>emptyList(), 0, NullVirtualFile.INSTANCE, message, "John Smith", "john@mail.com", message,
"John Smith", "john@mail.com", 0, changes, GitContentRevisionFactory.getInstance(myProject));
"John Smith", "john@mail.com", 0, new ThrowableComputable<Collection<Change>, Exception>() {
@Override
public Collection<Change> compute() throws Exception {
return changes;
}
}
);
}
}
@@ -1,5 +1,6 @@
package git4idea.log;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile;
@@ -9,6 +10,7 @@ import com.intellij.vcs.log.impl.VcsRefImpl;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.Collection;
import java.util.List;
import static junit.framework.Assert.assertEquals;
@@ -70,7 +72,7 @@ public class RefParserTest {
runTest("787ec72f340d740433ba068d4d58a6e58f6226bf", "");
}
private class TestLogObjectsFactory implements VcsLogObjectsFactory {
private static class TestLogObjectsFactory implements VcsLogObjectsFactory {
@NotNull
@Override
public Hash createHash(@NotNull String stringHash) {
@@ -96,13 +98,22 @@ public class RefParserTest {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public VcsFullCommitDetails createCommitMetadata(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
@NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
@NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
long authorTime) {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public VcsFullCommitDetails createFullDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
@NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
@NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
long authorTime, @NotNull List<Change> changes,
@NotNull ContentRevisionFactory contentRevisionFactory) {
long authorTime,
@NotNull ThrowableComputable<Collection<Change>, ? extends Exception> changesGetter) {
throw new UnsupportedOperationException();
}
+3
View File
@@ -217,6 +217,9 @@
<extensions defaultExtensionNs="com.intellij">
<navbar implementation="org.jetbrains.plugins.groovy.navbar.GrNavBarModelExtension" order="after defaultNavbar"/>
<fileTypeDetector implementation="org.jetbrains.plugins.groovy.GroovyHashBangFileTypeDetector"/>
<declarationRangeHandler key="org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod"
implementationClass="org.jetbrains.plugins.groovy.codeInsight.hint.GrMethodDeclarationRangeHandler"/>
<declarationRangeHandler key="org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition"
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* 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.
@@ -119,7 +119,7 @@ public class GrConcatenation2InjectorAdapter extends JavaConcatenationInjectorMa
else if (right instanceof GrString) {
processGString((GrString)right, operands);
}
else {
else if (right != null) {
operands.add(right);
}
}
@@ -0,0 +1,39 @@
/*
* 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.
*/
package org.jetbrains.plugins.groovy;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Created by Max Medvedev on 17/03/14
*/
public class GroovyHashBangFileTypeDetector implements FileTypeRegistry.FileTypeDetector {
@Nullable
@Override
public FileType detect(@NotNull VirtualFile file, @NotNull ByteSequence firstBytes, @Nullable CharSequence firstCharsIfText) {
if (FileUtil.isHashBangLine(firstCharsIfText, "groovy")) {
return GroovyFileType.GROOVY_FILE_TYPE;
}
return null;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* 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.
@@ -105,4 +105,15 @@ public class GrLabeledStatementImpl extends GroovyPsiElementImpl implements GrLa
public PsiElement getNameIdentifier() {
return getNameIdentifierGroovy();
}
@Override
public void deleteChildInternal(@NotNull ASTNode child) {
GrStatement statement = getStatement();
if (statement != null && child == statement.getNode()) {
delete();
}
else {
super.deleteChildInternal(child);
}
}
}
@@ -1070,6 +1070,7 @@ public class PsiUtil {
final PsiElement parent = expr.getParent();
if (parent instanceof GrControlFlowOwner || parent instanceof GrCaseSection) return true;
if (parent instanceof GrLabeledStatement) return true;
if (parent instanceof GrIfStatement &&
(expr == ((GrIfStatement)parent).getThenBranch() || expr == ((GrIfStatement)parent).getElseBranch())) {
return true;
@@ -162,57 +162,15 @@ public abstract class GrAbstractInplaceIntroducer<Settings extends GrIntroduceSe
return var;
}
@Override
protected void moveOffsetAfter(boolean success) {
super.moveOffsetAfter(success);
}
@Override
protected void performIntroduce() {
GrIntroduceContext context = new GrIntroduceContext() {
@NotNull
@Override
public Project getProject() {
return myProject;
}
@Override
public Editor getEditor() {
return myEditor;
}
@Nullable
@Override
public GrExpression getExpression() {
return (GrExpression)getExpr();
}
@Nullable
@Override
public GrVariable getVar() {
return getLocalVariable();
}
@Nullable
@Override
public StringPartInfo getStringPart() {
return null;
}
@NotNull
@Override
public PsiElement[] getOccurrences() {
return restoreOccurrences();
}
@Override
public PsiElement getScope() {
return myScope;
}
@NotNull
@Override
public PsiElement getPlace() {
GrExpression expression = getExpression();
return expression != null ? expression : getLocalVariable();
}
};
runRefactoring(context, getSettings(), true);
runRefactoring(new IntroduceContextAdapter(), getSettings(), true);
}
@NotNull
@@ -278,4 +236,53 @@ public abstract class GrAbstractInplaceIntroducer<Settings extends GrIntroduceSe
protected PsiType getSelectedType() {
return myTypePointer != null ? myTypePointer.getType() : null;
}
private class IntroduceContextAdapter implements GrIntroduceContext {
@NotNull
@Override
public Project getProject() {
return myProject;
}
@Override
public Editor getEditor() {
return myEditor;
}
@Nullable
@Override
public GrExpression getExpression() {
return (GrExpression)getExpr();
}
@Nullable
@Override
public GrVariable getVar() {
return getLocalVariable();
}
@Nullable
@Override
public StringPartInfo getStringPart() {
return null;
}
@NotNull
@Override
public PsiElement[] getOccurrences() {
return restoreOccurrences();
}
@Override
public PsiElement getScope() {
return myScope;
}
@NotNull
@Override
public PsiElement getPlace() {
GrExpression expression = getExpression();
return expression != null ? expression : getLocalVariable();
}
}
}
@@ -1,57 +0,0 @@
/*
* Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.introduce;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.introduce.inplace.InplaceVariableIntroducer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import java.util.LinkedHashSet;
import java.util.List;
/**
* @author Max Medvedev
*/
public abstract class GrInplaceIntroducer extends InplaceVariableIntroducer<PsiElement> {
public GrInplaceIntroducer(@NotNull GrVariable elementToRename,
@NotNull Editor editor,
@NotNull Project project,
@NotNull String title,
@NotNull List<RangeMarker> occurrences,
@Nullable PsiElement elementToIntroduce) {
super(elementToRename, editor, project, title, PsiElement.EMPTY_ARRAY, elementToIntroduce);
setOccurrenceMarkers(occurrences);
}
@Nullable
@Override
protected PsiElement getNameIdentifier() {
return getVariable().getNameIdentifierGroovy();
}
@Nullable
@Override
protected GrVariable getVariable() {
return (GrVariable)super.getVariable();
}
public abstract LinkedHashSet<String> suggestNames(GrIntroduceContext context);
}
@@ -738,7 +738,7 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
@Nullable
private static PsiElement findContainingStatement(@Nullable PsiElement candidate) {
while (candidate != null && !PsiUtil.isExpressionStatement(candidate)) {
while (candidate != null && (candidate.getParent() instanceof GrLabeledStatement || !(PsiUtil.isExpressionStatement(candidate)))) {
candidate = candidate.getParent();
if (candidate instanceof GrCaseLabel) candidate = candidate.getParent();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* 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.
@@ -141,11 +141,17 @@ public abstract class GrIntroduceLocalVariableProcessor {
}
@NotNull
private GrVariable insertVariableDefinition(@NotNull GrVariableDeclaration declaration, @NotNull GrStatement anchor, PsiElement expression) throws IncorrectOperationException {
boolean deleteExpression = expression != null && PsiUtil.isExpressionStatement(expression) && !isSingleGStringInjectionExpr(expression);
boolean anchorEqualsExpression = anchor == expression;
private GrVariable insertVariableDefinition(@NotNull GrVariableDeclaration declaration,
@NotNull GrStatement anchor,
@Nullable PsiElement expression) throws IncorrectOperationException {
GrLabeledStatement labeledStatement = expression != null && expression.getParent() instanceof GrLabeledStatement ? (GrLabeledStatement)expression.getParent() : null;
if (deleteExpression && !anchorEqualsExpression) {
boolean expressionMustBeDeleted = expression != null && PsiUtil.isExpressionStatement(expression) && !isSingleGStringInjectionExpr(expression);
boolean anchorEqualsExpression = anchor == expression || labeledStatement == anchor;
String usedLabel = labeledStatement != null ? labeledStatement.getName() : null;
if (expressionMustBeDeleted && !anchorEqualsExpression) {
expression.delete();
}
@@ -158,18 +164,20 @@ public abstract class GrIntroduceLocalVariableProcessor {
GrStatementOwner block = (GrStatementOwner)anchor.getParent();
if (deleteExpression && anchorEqualsExpression) {
declaration = (GrVariableDeclaration)anchor.replace(declaration);
if (usedLabel != null && expressionMustBeDeleted && anchorEqualsExpression) {
GrLabeledStatement definitionWithLabel = (GrLabeledStatement)GroovyPsiElementFactory.getInstance(anchor.getProject()).createStatementFromText(usedLabel + ": foo()");
GrLabeledStatement inserted = insertStatement(definitionWithLabel, anchor, block, true);
declaration = inserted.getStatement().replaceWithStatement(declaration);
}
else {
declaration = (GrVariableDeclaration)block.addStatementBefore(declaration, anchor);
declaration = insertStatement(declaration, anchor, block, expressionMustBeDeleted && anchorEqualsExpression);
}
final GrVariable variable = declaration.getVariables()[0];
JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
PsiElement markerPlace = deleteExpression ? variable :
PsiElement markerPlace = expressionMustBeDeleted ? variable :
isInsideControlStatement ? declaration.getParent()
: expression;
refreshPositionMarker(markerPlace);
@@ -177,6 +185,18 @@ public abstract class GrIntroduceLocalVariableProcessor {
return variable;
}
private static <T extends GrStatement> T insertStatement(T declaration,
GrStatement anchor,
GrStatementOwner block,
boolean replaceAnchor) {
if (replaceAnchor) {
return (T)anchor.replace(declaration);
}
else {
return (T)block.addStatementBefore(declaration, anchor);
}
}
@NotNull
static GrStatement insertBraces(@NotNull GrStatement anchor) {
GrBlockStatement blockStatement = GroovyPsiElementFactory.getInstance(anchor.getProject()).createBlockStatement();
@@ -124,14 +124,17 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
// Generating variable declaration
GrVariable insertedVar = processExpression(context, settings);
if (context.getEditor() != null && getPositionMarker() != null) {
context.getEditor().getCaretModel().moveToOffset(getPositionMarker().getEndOffset());
context.getEditor().getSelectionModel().removeSelection();
}
moveOffsetToPositionMarker(context.getEditor());
return insertedVar;
}
private void moveOffsetToPositionMarker(Editor editor) {
if (editor != null && getPositionMarker() != null) {
editor.getSelectionModel().removeSelection();
editor.getCaretModel().moveToOffset(getPositionMarker().getEndOffset());
}
}
@Override
protected GrInplaceVariableIntroducer getIntroducer(@NotNull GrIntroduceContext context, OccurrencesChooser.ReplaceChoice choice) {
@@ -159,6 +162,12 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
return addVariable(context, settings);
}
}
@Override
protected void performPostIntroduceTasks() {
super.performPostIntroduceTasks();
moveOffsetToPositionMarker(contextRef.get().getEditor());
}
};
}
@@ -58,6 +58,9 @@ public class IntroduceVariableTest extends LightCodeInsightFixtureTestCase {
public void testLoop8() { doTest() }
public void testInCase() { doTest() }
public void testCaseLabel() { doTest() }
public void testLabel1() { doTest() }
public void testLabel2() { doTest() }
public void testLabel3() { doTest() }
public void testDuplicatesInsideIf() { doTest() }
public void testFromGString() { doTest() }
@@ -0,0 +1,3 @@
label: <begin>123<end>
-----
label: def preved = 123<caret>
@@ -0,0 +1,7 @@
l:<all>123<end>
print 123
-----
l: def preved = 123
print preved
@@ -0,0 +1,11 @@
print 123
l:<all>123<end>
print 123
-----
def preved = 123
print preved
print preved
@@ -59,7 +59,7 @@ public class HgLogProvider implements VcsLogProvider {
@NotNull
@Override
public List<? extends VcsFullCommitDetails> readFirstBlock(@NotNull VirtualFile root,
public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root,
boolean ordered, int commitCount) throws VcsException {
return HgHistoryUtil.history(myProject, root, commitCount, ordered ? Collections.<String>emptyList() : Arrays.asList("-r", "0:tip"));
}
@@ -17,6 +17,7 @@ package org.zmlx.hg4idea.util;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.VcsException;
@@ -35,7 +36,6 @@ import org.zmlx.hg4idea.action.HgCommandResultNotifier;
import org.zmlx.hg4idea.command.HgLogCommand;
import org.zmlx.hg4idea.execution.HgCommandException;
import org.zmlx.hg4idea.execution.HgCommandResult;
import org.zmlx.hg4idea.log.HgContentRevisionFactory;
import org.zmlx.hg4idea.provider.HgCommittedChangeList;
import java.io.File;
@@ -177,7 +177,7 @@ public class HgHistoryUtil {
@NotNull
private static VcsFullCommitDetails createCommit(@NotNull Project project, @NotNull VirtualFile root,
@NotNull HgCommittedChangeList record) {
@NotNull final HgCommittedChangeList record) {
final VcsLogObjectsFactory factory = ServiceManager.getService(project, VcsLogObjectsFactory.class);
HgRevisionNumber revNumber = (HgRevisionNumber)record.getRevisionNumber();
@@ -188,11 +188,17 @@ public class HgHistoryUtil {
return factory.createHash(parent.getChangeset());
}
});
final Collection<Change> changes = record.getChanges();
return factory.createFullDetails(factory.createHash(revNumber.getChangeset()), parents, record.getCommitDate().getTime(), root,
revNumber.getSubject(),
revNumber.getAuthor(), revNumber.getEmail(), revNumber.getCommitMessage(), record.getCommitterName(),
"", record.getCommitDate().getTime(),
ContainerUtil.newArrayList(record.getChanges()), HgContentRevisionFactory.getInstance(project));
"", record.getCommitDate().getTime(), new ThrowableComputable<Collection<Change>, Exception>() {
@Override
public Collection<Change> compute() throws Exception {
return changes;
}
}
);
}
@Nullable