@@ -91,10 +91,14 @@ def add(self, value: T, score: float, is_exact_match: bool = True) -> None:
9191 )
9292 )
9393 else :
94+ # New related-only match: hit_count stays 0 because
95+ # only exact matches count as direct hits. This matters
96+ # for select_with_hit_count / _matches_with_min_hit_count
97+ # which filter on hit_count to weed out noise.
9498 self .set_match (
9599 Match (
96100 value ,
97- hit_count = 1 ,
101+ hit_count = 0 ,
98102 score = 0.0 ,
99103 related_hit_count = 1 ,
100104 related_score = score ,
@@ -250,9 +254,11 @@ def smooth_match_score[T](match: Match[T]) -> None:
250254
251255
252256class SemanticRefAccumulator (MatchAccumulator [SemanticRefOrdinal ]):
253- def __init__ (self , search_term_matches : set [str ] = set () ):
257+ def __init__ (self , search_term_matches : set [str ] | None = None ):
254258 super ().__init__ ()
255- self .search_term_matches = search_term_matches
259+ self .search_term_matches = (
260+ search_term_matches if search_term_matches is not None else set ()
261+ )
256262
257263 def add_term_matches (
258264 self ,
@@ -330,8 +336,7 @@ async def group_matches_by_type(
330336 semantic_ref = await semantic_refs .get_item (match .value )
331337 group = groups .get (semantic_ref .knowledge .knowledge_type )
332338 if group is None :
333- group = SemanticRefAccumulator ()
334- group .search_term_matches = self .search_term_matches
339+ group = SemanticRefAccumulator (self .search_term_matches )
335340 groups [semantic_ref .knowledge .knowledge_type ] = group
336341 group .set_match (match )
337342 return groups
@@ -513,11 +518,10 @@ def add_ranges(self, text_ranges: "list[TextRange] | TextRangeCollection") -> No
513518 for text_range in text_ranges ._ranges :
514519 self .add_range (text_range )
515520
516- def is_in_range (self , inner_range : TextRange ) -> bool :
517- if len (self ._ranges ) == 0 :
518- return False
519- i = bisect .bisect_left (self ._ranges , inner_range )
520- for outer_range in self ._ranges [i :]:
521+ def contains_range (self , inner_range : TextRange ) -> bool :
522+ # Since ranges are sorted by start, once we pass inner_range's start
523+ # no further range can contain it.
524+ for outer_range in self ._ranges :
521525 if outer_range .start > inner_range .start :
522526 break
523527 if inner_range in outer_range :
@@ -544,7 +548,7 @@ def is_range_in_scope(self, inner_range: TextRange) -> bool:
544548 # We have a very simple impl: we don't intersect/union ranges yet.
545549 # Instead, we ensure that the inner range is not rejected by any outer ranges.
546550 for outer_ranges in self .text_ranges :
547- if not outer_ranges .is_in_range (inner_range ):
551+ if not outer_ranges .contains_range (inner_range ):
548552 return False
549553 return True
550554
0 commit comments