diff --git a/src/HeuristicCompletion-Model/CoBeginsWithFilter.class.st b/src/HeuristicCompletion-Model/CoBeginsWithFilter.class.st index 318eb0981b5..e1b2ae61880 100644 --- a/src/HeuristicCompletion-Model/CoBeginsWithFilter.class.st +++ b/src/HeuristicCompletion-Model/CoBeginsWithFilter.class.st @@ -38,8 +38,73 @@ CoBeginsWithFilter >> completionString: anObject [ completionString := anObject ] +{ #category : 'testing' } +CoBeginsWithFilter >> fuzzyAcceptsContents: aString [ + + ^ (self fuzzyScoreForContents: aString) isNotNil +] + +{ #category : 'testing' } +CoBeginsWithFilter >> fuzzyScoreForContents: aString [ + + ^ CoFuzzyMatcher + scoreForCandidate: aString + token: completionString + caseSensitive: self isCaseSensitive + tolerance: CoCompletionTolerance rate +] + +{ #category : 'testing' } +CoBeginsWithFilter >> isCaseSensitive [ + + self subclassResponsibility +] + { #category : 'testing' } CoBeginsWithFilter >> isLessNarrowThanNegation: anotherFilter [ ^ false ] + +{ #category : 'testing' } +CoBeginsWithFilter >> prefixAcceptsContents: aString [ + + self subclassResponsibility +] + +{ #category : 'testing' } +CoBeginsWithFilter >> requiresFallbackEnumeration [ + + ^ CoCompletionTolerance enabled + and: [ completionString size >= CoCompletionTolerance minimumTokenSize ] +] + +{ #category : 'testing' } +CoBeginsWithFilter >> sortEntries: aCollection [ + + | exact fuzzy | + self requiresFallbackEnumeration ifFalse: [ ^ aCollection ]. + + exact := OrderedCollection new. + fuzzy := OrderedCollection new. + + aCollection do: [ :each | + (self prefixAcceptsContents: each contents) + ifTrue: [ exact add: each ] + ifFalse: [ fuzzy add: each ] ]. + + fuzzy isEmpty ifTrue: [ ^ aCollection ]. + + fuzzy sort: [ :a :b | + | scoreA scoreB | + scoreA := self fuzzyScoreForContents: a contents. + scoreB := self fuzzyScoreForContents: b contents. + scoreA = scoreB + ifTrue: [ a contents <= b contents ] + ifFalse: [ scoreA < scoreB ] ]. + + ^ OrderedCollection new + addAll: exact; + addAll: fuzzy; + yourself +] diff --git a/src/HeuristicCompletion-Model/CoCaseInsensitiveBeginsWithFilter.class.st b/src/HeuristicCompletion-Model/CoCaseInsensitiveBeginsWithFilter.class.st index 0a98a762542..6f3e99dfdc2 100644 --- a/src/HeuristicCompletion-Model/CoCaseInsensitiveBeginsWithFilter.class.st +++ b/src/HeuristicCompletion-Model/CoCaseInsensitiveBeginsWithFilter.class.st @@ -22,7 +22,15 @@ CoCaseInsensitiveBeginsWithFilter class >> filterString: aString [ { #category : 'testing' } CoCaseInsensitiveBeginsWithFilter >> accepts: aCandidate [ - ^ aCandidate contents asLowercase beginsWith: completionString asLowercase + ^ (self prefixAcceptsContents: aCandidate contents) + or: [ CoCompletionTolerance enabled + and: [ self fuzzyAcceptsContents: aCandidate contents ] ] +] + +{ #category : 'testing' } +CoCaseInsensitiveBeginsWithFilter >> isCaseSensitive [ + + ^ false ] { #category : 'testing' } @@ -42,3 +50,9 @@ CoCaseInsensitiveBeginsWithFilter >> isMoreNarrowThan: anotherFilter [ ^ anotherFilter isLessNarrowThanCaseInsensitive: self ] + +{ #category : 'testing' } +CoCaseInsensitiveBeginsWithFilter >> prefixAcceptsContents: aString [ + + ^ aString asLowercase beginsWith: completionString asLowercase +] diff --git a/src/HeuristicCompletion-Model/CoCaseSensitiveBeginsWithFilter.class.st b/src/HeuristicCompletion-Model/CoCaseSensitiveBeginsWithFilter.class.st index 5b8765540eb..307c8660fba 100644 --- a/src/HeuristicCompletion-Model/CoCaseSensitiveBeginsWithFilter.class.st +++ b/src/HeuristicCompletion-Model/CoCaseSensitiveBeginsWithFilter.class.st @@ -22,7 +22,15 @@ CoCaseSensitiveBeginsWithFilter class >> filterString: aString [ { #category : 'testing' } CoCaseSensitiveBeginsWithFilter >> accepts: aCandidate [ - ^ aCandidate contents beginsWith: completionString + ^ (self prefixAcceptsContents: aCandidate contents) + or: [ CoCompletionTolerance enabled + and: [ self fuzzyAcceptsContents: aCandidate contents ] ] +] + +{ #category : 'testing' } +CoCaseSensitiveBeginsWithFilter >> isCaseSensitive [ + + ^ true ] { #category : 'testing' } @@ -42,3 +50,9 @@ CoCaseSensitiveBeginsWithFilter >> isMoreNarrowThan: anotherFilter [ ^ anotherFilter isLessNarrowThanCaseSensitive: self ] + +{ #category : 'testing' } +CoCaseSensitiveBeginsWithFilter >> prefixAcceptsContents: aString [ + + ^ aString beginsWith: completionString +] diff --git a/src/HeuristicCompletion-Model/CoCompletionTolerance.class.st b/src/HeuristicCompletion-Model/CoCompletionTolerance.class.st new file mode 100644 index 00000000000..17683bbcbe9 --- /dev/null +++ b/src/HeuristicCompletion-Model/CoCompletionTolerance.class.st @@ -0,0 +1,53 @@ +" +Stores the runtime settings for fuzzy completion, such as the allowed typo rate and the minimum token size. + +" +Class { + #name : 'CoCompletionTolerance', + #superclass : 'Object', + #classInstVars : [ + 'minimumTokenSize', + 'rate' + ], + #category : 'HeuristicCompletion-Model-Core', + #package : 'HeuristicCompletion-Model', + #tag : 'Core' +} + +{ #category : 'accessing' } +CoCompletionTolerance class >> enabled [ + + ^ self rate > 0.0 +] + +{ #category : 'accessing' } +CoCompletionTolerance class >> minimumTokenSize [ + ^ minimumTokenSize ifNil: [ minimumTokenSize := 2 ] +] + +{ #category : 'accessing' } +CoCompletionTolerance class >> minimumTokenSize: anInteger [ + minimumTokenSize := (anInteger ifNil: [ 4 ]) max: 1 +] + +{ #category : 'accessing' } +CoCompletionTolerance class >> rate [ + + ^ rate ifNil: [ rate := 0.0 ] +] + +{ #category : 'accessing' } +CoCompletionTolerance class >> rate: aNumber [ + + | value | + value := (aNumber ifNil: [ 0.0 ]) asFloat. + rate := (value max: 0.0) min: 1.0 +] + +{ #category : 'accessing' } +CoCompletionTolerance class >> reset [ + +