@@ -70,7 +70,7 @@ import { createEditorFromSearchResult } from '../../searchEditor/browser/searchE
70
70
import { ACTIVE_GROUP , IEditorService , SIDE_GROUP } from '../../../services/editor/common/editorService.js' ;
71
71
import { IPreferencesService , ISettingsEditorOptions } from '../../../services/preferences/common/preferences.js' ;
72
72
import { ITextQueryBuilderOptions , QueryBuilder } from '../../../services/search/common/queryBuilder.js' ;
73
- import { SemanticSearchBehavior , IPatternInfo , ISearchComplete , ISearchConfiguration , ISearchConfigurationProperties , ISearchService , ITextQuery , SearchCompletionExitCode , SearchSortOrder , TextSearchCompleteMessageType , ViewMode } from '../../../services/search/common/search.js' ;
73
+ import { SemanticSearchBehavior , IPatternInfo , ISearchComplete , ISearchConfiguration , ISearchConfigurationProperties , ISearchService , ITextQuery , SearchCompletionExitCode , SearchSortOrder , TextSearchCompleteMessageType , ViewMode , isAIKeyword } from '../../../services/search/common/search.js' ;
74
74
import { AISearchKeyword , TextSearchCompleteMessage } from '../../../services/search/common/searchExtTypes.js' ;
75
75
import { ITextFileService } from '../../../services/textfile/common/textfiles.js' ;
76
76
import { INotebookService } from '../../notebook/common/notebookService.js' ;
@@ -174,6 +174,7 @@ export class SearchView extends ViewPane {
174
174
private refreshTreeController : RefreshTreeController ;
175
175
176
176
private _cachedResults : ISearchComplete | undefined ;
177
+ private _cachedKeywords : string [ ] = [ ] ;
177
178
public _pendingSemanticSearchPromise : Promise < ISearchComplete > | undefined ;
178
179
constructor (
179
180
options : IViewPaneOptions ,
@@ -1715,9 +1716,6 @@ export class SearchView extends ViewPane {
1715
1716
return ;
1716
1717
}
1717
1718
1718
- if ( this . configurationService . getValue < ISearchConfigurationProperties > ( 'search' ) . searchView . keywordSuggestions ) {
1719
- this . updateKeywordSuggestion ( keywords ) ;
1720
- }
1721
1719
1722
1720
if ( this . shouldShowAIResults ( ) && ! allResults ) {
1723
1721
const messageEl = this . clearMessage ( ) ;
@@ -1847,6 +1845,7 @@ export class SearchView extends ViewPane {
1847
1845
this . model . searchResult . aiTextSearchResult . hidden = true ;
1848
1846
if ( ! this . _pendingSemanticSearchPromise ) {
1849
1847
this . _cachedResults = undefined ;
1848
+ this . _cachedKeywords = [ ] ;
1850
1849
this . model . cancelAISearch ( true ) ;
1851
1850
this . model . clearAiSearchResults ( ) ;
1852
1851
}
@@ -1927,6 +1926,10 @@ export class SearchView extends ViewPane {
1927
1926
this . viewModel . searchResult . setAIQueryUsingTextQuery ( query ) ;
1928
1927
}
1929
1928
1929
+ if ( this . configurationService . getValue < ISearchConfigurationProperties > ( 'search' ) . searchView . keywordSuggestions ) {
1930
+ this . getKeywordSuggestions ( ) ;
1931
+ }
1932
+
1930
1933
return result . asyncResults . then ( ( complete ) => {
1931
1934
clearTimeout ( slowTimer ) ;
1932
1935
const config = this . configurationService . getValue < ISearchConfigurationProperties > ( 'search' ) . searchView . semanticSearchBehavior ;
@@ -1976,6 +1979,9 @@ export class SearchView extends ViewPane {
1976
1979
}
1977
1980
1978
1981
private updateSearchResultCount ( disregardExcludesAndIgnores ?: boolean , onlyOpenEditors ?: boolean , clear : boolean = false ) : void {
1982
+ if ( this . _cachedKeywords . length > 0 ) {
1983
+ return ;
1984
+ }
1979
1985
const fileCount = this . viewModel . searchResult . fileCount ( this . viewModel . searchResult . aiTextSearchResult . hidden ) ;
1980
1986
const resultCount = this . viewModel . searchResult . count ( this . viewModel . searchResult . aiTextSearchResult . hidden ) ;
1981
1987
this . hasSearchResultsKey . set ( fileCount > 0 ) ;
@@ -2017,7 +2023,7 @@ export class SearchView extends ViewPane {
2017
2023
}
2018
2024
}
2019
2025
2020
- private handleKeywordClick ( keyword : string , index : number , maxKeywords : number ) {
2026
+ private handleKeywordClick ( keyword : string , index : number ) {
2021
2027
this . searchWidget . searchInput ?. setValue ( keyword ) ;
2022
2028
this . triggerQueryChange ( { preserveFocus : false , triggeredOnType : false , shouldKeepAIResults : false } ) ;
2023
2029
type KeywordClickClassification = {
@@ -2032,54 +2038,60 @@ export class SearchView extends ViewPane {
2032
2038
} ;
2033
2039
this . telemetryService . publicLog2 < KeywordClickEvent , KeywordClickClassification > ( 'searchKeywordClick' , {
2034
2040
index,
2035
- maxKeywords
2041
+ maxKeywords : this . _cachedKeywords . length
2036
2042
} ) ;
2037
2043
}
2038
2044
2039
- private async updateKeywordSuggestion ( keywords ?: AISearchKeyword [ ] ) {
2040
- if ( ! keywords || keywords . length === 0 ) {
2041
- this . viewModel . replaceString = this . searchWidget . getReplaceValue ( ) ;
2042
- // Reuse pending aiSearch if available
2043
- let aiSearchPromise = this . _pendingSemanticSearchPromise ;
2044
- if ( ! aiSearchPromise ) {
2045
- this . viewModel . searchResult . setAIQueryUsingTextQuery ( ) ;
2046
- aiSearchPromise = this . _pendingSemanticSearchPromise = this . viewModel . aiSearch ( ( ) => {
2047
- // Clear pending promise when first result comes in
2048
- if ( this . _pendingSemanticSearchPromise === aiSearchPromise ) {
2049
- this . _pendingSemanticSearchPromise = undefined ;
2050
- }
2051
- } ) ;
2052
- }
2053
- this . _cachedResults = await aiSearchPromise ;
2054
- keywords = this . _cachedResults . aiKeywords ;
2055
- if ( ! keywords || keywords . length === 0 ) {
2045
+ private updateKeywordSuggestionUI ( keyword : AISearchKeyword ) {
2046
+ const element = this . messagesElement . firstChild as HTMLDivElement ;
2047
+ if ( this . _cachedKeywords . length > 0 ) {
2048
+ if ( this . _cachedKeywords . length >= 3 ) {
2049
+ // If we already have 3 keywords, just return
2056
2050
return ;
2057
2051
}
2058
- }
2059
- const messageEl = this . clearMessage ( ) ;
2060
- messageEl . classList . add ( 'ai-keywords' ) ;
2061
-
2062
- if ( keywords . length === 0 ) {
2063
- // Do not display anything if there are no keywords
2064
- return ;
2065
- }
2052
+ dom . append ( element , ', ' ) ;
2053
+ const index = this . _cachedKeywords . length ;
2054
+ const button = this . messageDisposables . add ( new SearchLinkButton (
2055
+ keyword . keyword ,
2056
+ ( ) => this . handleKeywordClick ( keyword . keyword , index ) ,
2057
+ this . hoverService
2058
+ ) ) ;
2059
+ dom . append ( element , button . element ) ;
2060
+ } else {
2061
+ const messageEl = this . clearMessage ( ) ;
2062
+ messageEl . classList . add ( 'ai-keywords' ) ;
2066
2063
2067
- // Add unclickable message
2068
- const resultMsg = nls . localize ( 'keywordSuggestion.message' , "Search instead for: " ) ;
2069
- dom . append ( messageEl , resultMsg ) ;
2064
+ // Add unclickable message
2065
+ const resultMsg = nls . localize ( 'keywordSuggestion.message' , "Search instead for: " ) ;
2066
+ dom . append ( messageEl , resultMsg ) ;
2070
2067
2071
- const topKeywords = keywords . slice ( 0 , 3 ) ;
2072
- topKeywords . forEach ( ( keyword , index ) => {
2073
- if ( index > 0 && index < topKeywords . length ) {
2074
- dom . append ( messageEl , ', ' ) ;
2075
- }
2076
2068
const button = this . messageDisposables . add ( new SearchLinkButton (
2077
2069
keyword . keyword ,
2078
- ( ) => this . handleKeywordClick ( keyword . keyword , index , topKeywords . length ) ,
2070
+ ( ) => this . handleKeywordClick ( keyword . keyword , 0 ) ,
2079
2071
this . hoverService
2080
2072
) ) ;
2081
2073
dom . append ( messageEl , button . element ) ;
2082
- } ) ;
2074
+ }
2075
+ this . _cachedKeywords . push ( keyword . keyword ) ;
2076
+ }
2077
+
2078
+ private async getKeywordSuggestions ( ) {
2079
+ // Reuse pending aiSearch if available
2080
+ let aiSearchPromise = this . _pendingSemanticSearchPromise ;
2081
+ if ( ! aiSearchPromise ) {
2082
+ this . viewModel . searchResult . setAIQueryUsingTextQuery ( ) ;
2083
+ aiSearchPromise = this . _pendingSemanticSearchPromise = this . viewModel . aiSearch ( result => {
2084
+ if ( isAIKeyword ( result ) ) {
2085
+ this . updateKeywordSuggestionUI ( result ) ;
2086
+ return ;
2087
+ }
2088
+ // Clear pending promise when first result comes in
2089
+ if ( this . _pendingSemanticSearchPromise === aiSearchPromise ) {
2090
+ this . _pendingSemanticSearchPromise = undefined ;
2091
+ }
2092
+ } ) ;
2093
+ }
2094
+ this . _cachedResults = await aiSearchPromise ;
2083
2095
}
2084
2096
2085
2097
private addMessage ( message : TextSearchCompleteMessage ) {
0 commit comments