diff --git a/platform/lang-impl/src/com/intellij/find/impl/TextSearchContributor.kt b/platform/lang-impl/src/com/intellij/find/impl/TextSearchContributor.kt index 1ed983ca7651..2a88012ae2a8 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/TextSearchContributor.kt +++ b/platform/lang-impl/src/com/intellij/find/impl/TextSearchContributor.kt @@ -13,6 +13,7 @@ import com.intellij.ide.actions.searcheverywhere.* import com.intellij.ide.actions.searcheverywhere.SETabSwitcherListener.Companion.SE_TAB_TOPIC import com.intellij.ide.actions.searcheverywhere.SETabSwitcherListener.SETabSwitchedEvent import com.intellij.ide.actions.searcheverywhere.footer.createTextExtendedInfo +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector.wrapEventWithActionStartData import com.intellij.ide.util.scopeChooser.ScopeDescriptor import com.intellij.ide.util.scopeChooser.ScopeOption import com.intellij.ide.util.scopeChooser.ScopeService @@ -287,7 +288,7 @@ class TextSearchContributor(val event: AnActionEvent) : WeightedSearchEverywhere } override fun actionPerformed(e: AnActionEvent) { - showInSearchEverywherePopup(ID, e, true, true) + showInSearchEverywherePopup(ID, wrapEventWithActionStartData(e), true, true) } } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 15310d346f2f..c5d1b2306be6 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -3,6 +3,7 @@ package com.intellij.ide.actions; import com.intellij.ide.DataManager; import com.intellij.ide.actions.searcheverywhere.ActionSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector; import com.intellij.ide.lightEdit.LightEditCompatible; import com.intellij.ide.ui.search.OptionDescription; import com.intellij.ide.util.gotoByName.GotoActionModel; @@ -23,6 +24,7 @@ import java.awt.event.InputEvent; public class GotoActionAction extends SearchEverywhereBaseAction implements DumbAware, LightEditCompatible { @Override public void actionPerformed(@NotNull AnActionEvent e) { + e = SearchFieldStatisticsCollector.wrapEventWithActionStartData(e); String tabID = ActionSearchEverywhereContributor.class.getSimpleName(); showInSearchEverywherePopup(tabID, e, false, true); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index d30f0cd61732..4a16f1595b44 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -3,6 +3,7 @@ package com.intellij.ide.actions; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.searcheverywhere.ClassSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector; import com.intellij.ide.util.gotoByName.GotoClassModel2; import com.intellij.navigation.ChooseByNameRegistry; import com.intellij.openapi.actionSystem.*; @@ -29,6 +30,7 @@ public final class GotoClassAction extends SearchEverywhereBaseAction implements @Override public void actionPerformed(@NotNull AnActionEvent e) { + e = SearchFieldStatisticsCollector.wrapEventWithActionStartData(e); Project project = e.getProject(); if (project == null) return; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index 566bfe2238e0..c77bb328180c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -2,6 +2,7 @@ package com.intellij.ide.actions; import com.intellij.ide.actions.searcheverywhere.FileSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.DumbAware; import org.jetbrains.annotations.NotNull; @@ -17,6 +18,7 @@ public class GotoFileAction extends SearchEverywhereBaseAction implements DumbAw @Override public void actionPerformed(@NotNull AnActionEvent e) { + e = SearchFieldStatisticsCollector.wrapEventWithActionStartData(e); String tabID = FileSearchEverywhereContributor.class.getSimpleName(); showInSearchEverywherePopup(tabID, e, true, true); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java index 2a2057192506..c6f7c58b5f9c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java @@ -2,6 +2,7 @@ package com.intellij.ide.actions; import com.intellij.ide.actions.searcheverywhere.SymbolSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector; import com.intellij.navigation.ChooseByNameRegistry; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; @@ -14,6 +15,7 @@ public final class GotoSymbolAction extends SearchEverywhereBaseAction implement @Override public void actionPerformed(@NotNull AnActionEvent e) { + e = SearchFieldStatisticsCollector.wrapEventWithActionStartData(e); Project project = e.getProject(); if (project == null) return; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index df2aac080d59..b8225910e8fa 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -5,6 +5,7 @@ import com.intellij.codeWithMe.ClientId; import com.intellij.ide.HelpTooltip; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManagerImpl; +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector; import com.intellij.ide.lightEdit.LightEdit; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.*; @@ -105,15 +106,16 @@ public class SearchEverywhereAction extends SearchEverywhereBaseAction @Override public void actionPerformed(@NotNull AnActionEvent e) { - if (LightEdit.owns(e.getProject())) return; + AnActionEvent newEvent = SearchFieldStatisticsCollector.wrapEventWithActionStartData(e); + if (LightEdit.owns(newEvent.getProject())) return; - if (AdvancedSettings.getBoolean("ide.suppress.double.click.handler") && e.getInputEvent() instanceof KeyEvent) { - if (((KeyEvent)e.getInputEvent()).getKeyCode() == KeyEvent.VK_SHIFT) { + if (AdvancedSettings.getBoolean("ide.suppress.double.click.handler") && newEvent.getInputEvent() instanceof KeyEvent) { + if (((KeyEvent)newEvent.getInputEvent()).getKeyCode() == KeyEvent.VK_SHIFT) { return; } } - ReadAction.run(() -> showInSearchEverywherePopup(SearchEverywhereManagerImpl.ALL_CONTRIBUTORS_GROUP_ID, e, true, true)); + ReadAction.run(() -> showInSearchEverywherePopup(SearchEverywhereManagerImpl.ALL_CONTRIBUTORS_GROUP_ID, newEvent, true, true)); } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index c4b1a2b0f6fe..33afe25df9e7 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -4,8 +4,10 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.codeWithMe.ClientId; import com.intellij.ide.actions.BigPopupUI; import com.intellij.ide.actions.OpenInRightSplitAction; +import com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector; import com.intellij.ide.lightEdit.LightEdit; import com.intellij.ide.lightEdit.LightEditCompatible; +import com.intellij.internal.statistic.utils.StartMoment; import com.intellij.lang.LangBundle; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; @@ -41,7 +43,7 @@ import java.util.function.Predicate; import java.util.stream.Collector; import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; -import static com.intellij.ide.actions.searcheverywhere.statistics.SearchEverywhereUsageTriggerCollector.DIALOG_CLOSED; +import static com.intellij.ide.actions.searcheverywhere.statistics.SearchEverywhereUsageTriggerCollector.*; public final class SearchEverywhereManagerImpl implements SearchEverywhereManager { public static final String ALL_CONTRIBUTORS_GROUP_ID = "SearchEverywhereContributor.All"; @@ -83,7 +85,7 @@ public final class SearchEverywhereManagerImpl implements SearchEverywhereManage List> contributors = createContributors(initEvent, project); SearchEverywhereContributorValidationRule.updateContributorsMap(contributors); SearchEverywhereSpellingCorrector spellingCorrector = SearchEverywhereSpellingCorrector.getInstance(project); - mySearchEverywhereUI = createView(myProject, contributors, spellingCorrector); + mySearchEverywhereUI = createView(myProject, contributors, spellingCorrector, SearchFieldStatisticsCollector.getStartMoment(initEvent)); contributors.forEach(c -> Disposer.register(mySearchEverywhereUI, c)); mySearchEverywhereUI.switchToTab(tabID); @@ -269,11 +271,12 @@ public final class SearchEverywhereManagerImpl implements SearchEverywhereManage } private SearchEverywhereUI createView(Project project, List> contributors, - @Nullable SearchEverywhereSpellingCorrector spellingCorrector) { + @Nullable SearchEverywhereSpellingCorrector spellingCorrector, + @Nullable StartMoment startMoment) { if (LightEdit.owns(project)) { contributors = ContainerUtil.filter(contributors, (contributor) -> contributor instanceof LightEditCompatible); } - SearchEverywhereUI view = new SearchEverywhereUI(project, contributors, myTabsShortcutsMap::get, spellingCorrector); + SearchEverywhereUI view = new SearchEverywhereUI(project, contributors, myTabsShortcutsMap::get, spellingCorrector, startMoment); view.setSearchFinishedHandler(() -> { if (isShown()) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index b71a140ee4ae..38b3fc66cc09 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -30,6 +30,7 @@ import com.intellij.ide.util.treeView.smartTree.TreeElement; import com.intellij.internal.statistic.eventLog.events.EventFields; import com.intellij.internal.statistic.eventLog.events.EventPair; import com.intellij.internal.statistic.local.ContributorsLocalSummary; +import com.intellij.internal.statistic.utils.StartMoment; import com.intellij.lang.LanguageStructureViewBuilder; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; @@ -178,6 +179,14 @@ public final class SearchEverywhereUI extends BigPopupUI implements UiDataProvid public SearchEverywhereUI(@Nullable Project project, List> contributors, @NotNull Function shortcutSupplier, @Nullable SearchEverywhereSpellingCorrector spellingCorrector) { + this(project, contributors, shortcutSupplier, spellingCorrector, null); + } + + @ApiStatus.Internal + public SearchEverywhereUI(@Nullable Project project, List> contributors, + @NotNull Function shortcutSupplier, + @Nullable SearchEverywhereSpellingCorrector spellingCorrector, + @Nullable StartMoment startMoment) { super(project); mySpellingCorrector = spellingCorrector; @@ -257,7 +266,8 @@ public final class SearchEverywhereUI extends BigPopupUI implements UiDataProvid SearchPerformanceTracker performanceTracker = new SearchPerformanceTracker(() -> myHeader.getSelectedTab().getID()); addSearchListener(performanceTracker); - Disposer.register(this, SearchFieldStatisticsCollector.createAndStart(mySearchField, performanceTracker, myMlService, myProject)); + Disposer.register(this, SearchFieldStatisticsCollector.createAndStart(mySearchField, performanceTracker, myMlService, myProject, + startMoment)); } public void addSearchListener(SearchListener listener) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java index fe596435a516..b7d8109d1435 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java @@ -17,7 +17,7 @@ import java.util.List; @ApiStatus.Internal public final class SearchEverywhereUsageTriggerCollector extends CounterUsagesCollector { - private static final EventLogGroup GROUP = new EventLogGroup("searchEverywhere", 17); + private static final EventLogGroup GROUP = new EventLogGroup("searchEverywhere", 18); // this string will be used as ID for contributors from private // plugins that mustn't be sent in statistics @@ -89,11 +89,12 @@ public final class SearchEverywhereUsageTriggerCollector extends CounterUsagesCo public static final LongEventField TIME_TO_FIRST_RESULT_LAST_QUERY = EventFields.Long("timeToFirstResultLastQuery"); public static final StringEventField LAST_TAB_ID = EventFields.String("lastTabId", ourTabs); public static final LongEventField DURATION_MS = EventFields.Long("durationMs"); + public static final LongEventField DURATION_FROM_ACTION_START_MS = EventFields.Long("durationFromActionStartMs"); public static final IntEventField ML_EXPERIMENT_VERSION = EventFields.Int("mlExperimentVersion"); public static final IntEventField ML_EXPERIMENT_GROUP = EventFields.Int("mlExperimentGroup"); public static final VarargEventId SESSION_FINISHED = GROUP.registerVarargEvent( "sessionFinished", TYPED_NAVIGATION_KEYS, TYPED_SYMBOL_KEYS, - TIME_TO_FIRST_RESULT, FIRST_TAB_ID, TIME_TO_FIRST_RESULT_LAST_QUERY, LAST_TAB_ID, DURATION_MS, + TIME_TO_FIRST_RESULT, FIRST_TAB_ID, TIME_TO_FIRST_RESULT_LAST_QUERY, LAST_TAB_ID, DURATION_MS, DURATION_FROM_ACTION_START_MS, ML_EXPERIMENT_GROUP, ML_EXPERIMENT_VERSION ); @@ -106,6 +107,7 @@ public final class SearchEverywhereUsageTriggerCollector extends CounterUsagesCo } public static @NotNull String getReportableContributorID(@NotNull SearchEverywhereContributor contributor) { + //noinspection rawtypes Class clazz = contributor.getClass(); PluginInfo pluginInfo = PluginInfoDetectorKt.getPluginInfo(clazz); return pluginInfo.isDevelopedByJetBrains() ? contributor.getSearchProviderId() : NOT_REPORTABLE_CONTRIBUTOR_ID; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchFieldStatisticsCollector.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchFieldStatisticsCollector.java index 29f541f8eea1..dde8504de458 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchFieldStatisticsCollector.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchFieldStatisticsCollector.java @@ -2,9 +2,13 @@ package com.intellij.ide.actions.searcheverywhere.statistics; import com.intellij.ide.actions.searcheverywhere.SearchEverywhereMlService; +import com.intellij.internal.statistic.utils.StartMoment; import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.KeyAdapter; @@ -17,6 +21,7 @@ public final class SearchFieldStatisticsCollector implements Disposable { private final Project myProject; private final JTextField myTextField; + private final StartMoment myStartMoment; private final SearchEverywhereMlService myMlService; private final SearchPerformanceTracker myPerformanceTracker; @@ -24,18 +29,20 @@ public final class SearchFieldStatisticsCollector implements Disposable { private int myNavKeysTyped; private SearchFieldStatisticsCollector(JTextField field, SearchPerformanceTracker performanceTracker, - SearchEverywhereMlService mlService, Project project) { + SearchEverywhereMlService mlService, Project project, @Nullable StartMoment startMoment) { myProject = project; myPerformanceTracker = performanceTracker; myMlService = mlService; myTextField = field; + myStartMoment = startMoment; } public static SearchFieldStatisticsCollector createAndStart(JTextField field, SearchPerformanceTracker performanceTracker, SearchEverywhereMlService mlService, - Project project) { - SearchFieldStatisticsCollector res = new SearchFieldStatisticsCollector(field, performanceTracker, mlService, project); + Project project, + @Nullable StartMoment startMoment) { + SearchFieldStatisticsCollector res = new SearchFieldStatisticsCollector(field, performanceTracker, mlService, project, startMoment); res.initListeners(); return res; } @@ -59,6 +66,9 @@ public final class SearchFieldStatisticsCollector implements Disposable { pairs.add(TYPED_NAVIGATION_KEYS.with(myNavKeysTyped)); pairs.add(TYPED_SYMBOL_KEYS.with(mySymbolKeysTyped)); pairs.add(DURATION_MS.with(info.getDuration())); + if (myStartMoment != null) { + pairs.add(DURATION_FROM_ACTION_START_MS.with(myStartMoment.getCurrentDuration().toMillis())); + } if (myMlService != null) { pairs.add(ML_EXPERIMENT_VERSION.with(myMlService.getExperimentVersion())); @@ -84,4 +94,30 @@ public final class SearchFieldStatisticsCollector implements Disposable { } }); } + + private static final DataKey START_MOMENT_KEY = DataKey.create("start_moment_of_search_everywhere"); + + public static StartMoment getStartMoment(AnActionEvent event) { + return event.getData(START_MOMENT_KEY); + } + + @NotNull + public static AnActionEvent wrapEventWithActionStartData(@NotNull AnActionEvent event) { + StartMoment startMoment = StartMoment.Companion.now(); + DataContext initialDataContext = event.getDataContext(); + DataContext wrappedDataContext = wrapDataContextWithActionStartData(initialDataContext, startMoment); + if (wrappedDataContext == initialDataContext) return event; + return event.withDataContext(wrappedDataContext); + } + + @NotNull + private static DataContext wrapDataContextWithActionStartData(@NotNull DataContext dataContext, @NotNull StartMoment startMoment) { + if (dataContext.getData(START_MOMENT_KEY) != null) return dataContext; + return CustomizedDataContext.withSnapshot(dataContext, sink -> sink.set(START_MOMENT_KEY, startMoment)); + } + + @NotNull + public static DataContext wrapDataContextWithActionStartData(@NotNull DataContext dataContext) { + return wrapDataContextWithActionStartData(dataContext, StartMoment.Companion.now()); + } } diff --git a/platform/statistics/src/com/intellij/internal/statistic/utils/StartMoment.kt b/platform/statistics/src/com/intellij/internal/statistic/utils/StartMoment.kt new file mode 100644 index 000000000000..f78fb3405e4f --- /dev/null +++ b/platform/statistics/src/com/intellij/internal/statistic/utils/StartMoment.kt @@ -0,0 +1,27 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.internal.statistic.utils + +import org.jetbrains.annotations.ApiStatus + +/** + * Is used to track durations for reporting to FUS + */ +@ApiStatus.Internal +@ApiStatus.Experimental +interface StartMoment { + companion object { + fun now(): StartMoment { + return InstantStartMoment() + } + + + private class InstantStartMoment(private val now: Long = System.nanoTime()) : StartMoment { + override fun getCurrentDuration(): java.time.Duration { + return java.time.Duration.ofNanos(System.nanoTime() - now) + } + } + } + + fun getCurrentDuration(): java.time.Duration +} + diff --git a/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java b/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java index 07a326d90e0e..08c4c52734e1 100644 --- a/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java +++ b/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java @@ -40,6 +40,7 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; import static com.intellij.openapi.ui.playback.commands.ActionCommand.getInputEvent; +import static com.intellij.ide.actions.searcheverywhere.statistics.SearchFieldStatisticsCollector.wrapDataContextWithActionStartData; import static com.intellij.openapi.ui.playback.commands.AlphaNumericTypeCommand.findTarget; /** @@ -103,11 +104,12 @@ public class SearchEverywhereCommand extends AbstractCommand { DataContext dataContext = CustomizedDataContext.withSnapshot( DataManager.getInstance().getDataContext(component), sink -> sink.set(CommonDataKeys.PROJECT, context.getProject())); + DataContext wrappedDataContext = wrapDataContextWithActionStartData(dataContext); IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); TraceKt.use(PerformanceTestSpan.getTracer(warmup).spanBuilder("searchEverywhere_dialog_shown"), dialogSpan -> { var manager = SearchEverywhereManager.getInstance(project); AnActionEvent event = AnActionEvent.createEvent( - dataContext, null, ActionPlaces.EDITOR_POPUP, ActionUiKind.POPUP, null); + wrappedDataContext, null, ActionPlaces.EDITOR_POPUP, ActionUiKind.POPUP, null); manager.show(tabId.get(), "", event); attachSearchListeners(manager.getCurrentlyShownUI()); return null;