@@ -37,6 +37,16 @@ private Disposable SetPrediction(PredictionSource source, PredictionViewStyle vi
37
37
new SetPSReadLineOption { PredictionSource = oldSource , PredictionViewStyle = oldView } ) ) ;
38
38
}
39
39
40
+ private Disposable SetHistorySearchCaseSensitive ( bool caseSensitive )
41
+ {
42
+ var options = PSConsoleReadLine . GetOptions ( ) ;
43
+ var oldValue = options . HistorySearchCaseSensitive ;
44
+
45
+ PSConsoleReadLine . SetOptions ( new SetPSReadLineOption { HistorySearchCaseSensitive = caseSensitive } ) ;
46
+ return new Disposable ( ( ) => PSConsoleReadLine . SetOptions (
47
+ new SetPSReadLineOption { HistorySearchCaseSensitive = oldValue } ) ) ;
48
+ }
49
+
40
50
private void AssertDisplayedSuggestions ( int count , Guid predictorId , uint session , int countOrIndex )
41
51
{
42
52
Assert . Equal ( count , _mockedMethods . displayedSuggestions . Count ) ;
@@ -1711,6 +1721,131 @@ public void List_HistoryAndPluginSource_Acceptance()
1711
1721
Assert . Equal ( "SOME NEW TEX SOME TEXT AFTER" , _mockedMethods . commandHistory [ 3 ] ) ;
1712
1722
}
1713
1723
1724
+ [ SkippableFact ]
1725
+ public void List_HistoryAndPluginSource_Deduplication ( )
1726
+ {
1727
+ TestSetup ( KeyMode . Cmd ) ;
1728
+ int listWidth = CheckWindowSize ( ) ;
1729
+ var emphasisColors = Tuple . Create ( PSConsoleReadLineOptions . DefaultEmphasisColor , _console . BackgroundColor ) ;
1730
+
1731
+ // Using the 'HistoryAndPlugin' source will make PSReadLine get prediction from both history and plugin.
1732
+ using var disp1 = SetPrediction ( PredictionSource . HistoryAndPlugin , PredictionViewStyle . ListView ) ;
1733
+ _mockedMethods . ClearPredictionFields ( ) ;
1734
+
1735
+ // The 1st result from 'predictorId_1' is the same as the 1st entry in history with case-insensitive comparison,
1736
+ // which is the default comparison. So, that result will be filtered out due to the de-duplication logic.
1737
+ SetHistory ( "some TEXT BEFORE de-dup" , "de-dup -of" ) ;
1738
+ Test ( "de-dup" , Keys (
1739
+ "de-dup" , CheckThat ( ( ) => AssertScreenIs ( 6 ,
1740
+ TokenClassification . Command , "de-dup" ,
1741
+ NextLine ,
1742
+ TokenClassification . ListPrediction , '>' ,
1743
+ TokenClassification . None , ' ' ,
1744
+ emphasisColors , "de-dup" ,
1745
+ TokenClassification . None , " -of" ,
1746
+ TokenClassification . None , new string ( ' ' , listWidth - 21 ) , // 21 is the length of '> de-dup -of' plus '[History]'.
1747
+ TokenClassification . None , '[' ,
1748
+ TokenClassification . ListPrediction , "History" ,
1749
+ TokenClassification . None , ']' ,
1750
+ NextLine ,
1751
+ TokenClassification . ListPrediction , '>' ,
1752
+ TokenClassification . None , " some TEXT BEFORE " ,
1753
+ emphasisColors , "de-dup" ,
1754
+ TokenClassification . None , new string ( ' ' , listWidth - 34 ) , // 34 is the length of '> SOME TEXT BEFORE de-dup' plus '[History]'.
1755
+ TokenClassification . None , '[' ,
1756
+ TokenClassification . ListPrediction , "History" ,
1757
+ TokenClassification . None , ']' ,
1758
+ NextLine ,
1759
+ TokenClassification . ListPrediction , '>' ,
1760
+ TokenClassification . None , ' ' ,
1761
+ emphasisColors , "de-dup" ,
1762
+ TokenClassification . None , " SOME TEXT AFTER" ,
1763
+ TokenClassification . None , new string ( ' ' , listWidth - 39 ) , // 35 is the length of '> de-dup SOME TEXT AFTER' plus '[TestPredictor]'.
1764
+ TokenClassification . None , '[' ,
1765
+ TokenClassification . ListPrediction , "TestPredictor" ,
1766
+ TokenClassification . None , ']' ,
1767
+ NextLine ,
1768
+ TokenClassification . ListPrediction , '>' ,
1769
+ TokenClassification . None , " SOME NEW TEXT" ,
1770
+ TokenClassification . None , new string ( ' ' , listWidth - 32 ) , // 32 is the length of '> SOME NEW TEXT' plus '[LongNamePred...]'
1771
+ TokenClassification . None , '[' ,
1772
+ TokenClassification . ListPrediction , "LongNamePred..." ,
1773
+ TokenClassification . None , ']' ,
1774
+ // List view is done, no more list item following.
1775
+ NextLine ,
1776
+ NextLine
1777
+ ) ) ,
1778
+ // `OnSuggestionDisplayed` should be fired for both predictors.
1779
+ // For 'predictorId_1', the reported 'countOrIndex' from feedback is still 2 even though its 1st result was filtered out due to duplication.
1780
+ CheckThat ( ( ) => AssertDisplayedSuggestions ( count : 2 , predictorId_1 , MiniSessionId , 2 ) ) ,
1781
+ CheckThat ( ( ) => AssertDisplayedSuggestions ( count : 2 , predictorId_2 , MiniSessionId , 1 ) ) ,
1782
+ CheckThat ( ( ) => _mockedMethods . ClearPredictionFields ( ) ) ,
1783
+ // Once accepted, the list should be cleared.
1784
+ _ . Enter , CheckThat ( ( ) => AssertScreenIs ( 2 ,
1785
+ TokenClassification . Command , "de-dup" ,
1786
+ NextLine ,
1787
+ NextLine ) )
1788
+ ) ) ;
1789
+
1790
+ // Change the setting to be case sensitive, and check the list view content.
1791
+ using var disp2 = SetHistorySearchCaseSensitive ( caseSensitive : true ) ;
1792
+ _mockedMethods . ClearPredictionFields ( ) ;
1793
+
1794
+ // The 1st result from 'predictorId_1' is not the same as the 2nd entry in history with the case-sensitive comparison.
1795
+ // But the 2nd result from 'predictorId_1' is the same as teh 1st entry in history with the case-sensitive comparison,
1796
+ // so, that result will be filtered out due to the de-duplication logic.
1797
+ SetHistory ( "de-dup SOME TEXT AFTER" , "some TEXT BEFORE de-dup" ) ;
1798
+ Test ( "de-dup" , Keys (
1799
+ "de-dup" , CheckThat ( ( ) => AssertScreenIs ( 6 ,
1800
+ TokenClassification . Command , "de-dup" ,
1801
+ NextLine ,
1802
+ TokenClassification . ListPrediction , '>' ,
1803
+ TokenClassification . None , ' ' ,
1804
+ emphasisColors , "de-dup" ,
1805
+ TokenClassification . None , " SOME TEXT AFTER" ,
1806
+ TokenClassification . None , new string ( ' ' , listWidth - 33 ) , // 33 is the length of '> de-dup SOME TEXT AFTER' plus '[History]'.
1807
+ TokenClassification . None , '[' ,
1808
+ TokenClassification . ListPrediction , "History" ,
1809
+ TokenClassification . None , ']' ,
1810
+ NextLine ,
1811
+ TokenClassification . ListPrediction , '>' ,
1812
+ TokenClassification . None , " some TEXT BEFORE " ,
1813
+ emphasisColors , "de-dup" ,
1814
+ TokenClassification . None , new string ( ' ' , listWidth - 34 ) , // 34 is the length of '> some TEXT BEFORE de-dup' plus '[History]'.
1815
+ TokenClassification . None , '[' ,
1816
+ TokenClassification . ListPrediction , "History" ,
1817
+ TokenClassification . None , ']' ,
1818
+ NextLine ,
1819
+ TokenClassification . ListPrediction , '>' ,
1820
+ TokenClassification . None , " SOME TEXT BEFORE " ,
1821
+ emphasisColors , "de-dup" ,
1822
+ TokenClassification . None , new string ( ' ' , listWidth - 40 ) , // 40 is the length of '> SOME TEXT BEFORE de-dup' plus '[TestPredictor]'.
1823
+ TokenClassification . None , '[' ,
1824
+ TokenClassification . ListPrediction , "TestPredictor" ,
1825
+ TokenClassification . None , ']' ,
1826
+ NextLine ,
1827
+ TokenClassification . ListPrediction , '>' ,
1828
+ TokenClassification . None , " SOME NEW TEXT" ,
1829
+ TokenClassification . None , new string ( ' ' , listWidth - 32 ) , // 32 is the length of '> SOME NEW TEXT' plus '[LongNamePred...]'
1830
+ TokenClassification . None , '[' ,
1831
+ TokenClassification . ListPrediction , "LongNamePred..." ,
1832
+ TokenClassification . None , ']' ,
1833
+ // List view is done, no more list item following.
1834
+ NextLine ,
1835
+ NextLine
1836
+ ) ) ,
1837
+ // `OnSuggestionDisplayed` should be fired for both predictors.
1838
+ // For 'predictorId_1', the reported 'countOrIndex' from feedback is still 2 even though its 2nd result was filtered out due to duplication.
1839
+ CheckThat ( ( ) => AssertDisplayedSuggestions ( count : 2 , predictorId_1 , MiniSessionId , 2 ) ) ,
1840
+ CheckThat ( ( ) => AssertDisplayedSuggestions ( count : 2 , predictorId_2 , MiniSessionId , 1 ) ) ,
1841
+ // Once accepted, the list should be cleared.
1842
+ _ . Enter , CheckThat ( ( ) => AssertScreenIs ( 2 ,
1843
+ TokenClassification . Command , "de-dup" ,
1844
+ NextLine ,
1845
+ NextLine ) )
1846
+ ) ) ;
1847
+ }
1848
+
1714
1849
[ SkippableFact ]
1715
1850
public void List_NoneSource_ExecutionStatus ( )
1716
1851
{
0 commit comments