Coverage for sources / vibelinter / rules / context.py: 62%

22 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-04 00:00 +0000

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

4#============================================================================# 

5# # 

6# Licensed under the Apache License, Version 2.0 (the "License"); # 

7# you may not use this file except in compliance with the License. # 

8# You may obtain a copy of the License at # 

9# # 

10# http://www.apache.org/licenses/LICENSE-2.0 # 

11# # 

12# Unless required by applicable law or agreed to in writing, software # 

13# distributed under the License is distributed on an "AS IS" BASIS, # 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

15# See the License for the specific language governing permissions and # 

16# limitations under the License. # 

17# # 

18#============================================================================# 

19 

20 

21''' Context extraction utilities for enhanced violation reporting. ''' 

22 

23 

24from . import __ 

25from . import violations as _violations 

26 

27 

28class ContextExtractor: 

29 ''' Extracts source code context around violations. ''' 

30 

31 def __init__( 

32 self, 

33 source_lines: __.typx.Annotated[ 

34 tuple[ str, ... ], 

35 __.ddoc.Doc( 'Source file lines for context extraction.' ) ] 

36 ) -> None: 

37 self.source_lines = source_lines 

38 

39 def extract_violation_context( 

40 self, 

41 violation: __.typx.Annotated[ 

42 _violations.Violation, 

43 __.ddoc.Doc( 'Violation to extract context for.' ) ], 

44 context_size: __.typx.Annotated[ 

45 int, 

46 __.ddoc.Doc( 

47 'Number of lines to show before and after violation.' 

48 ) ] = 2, 

49 ) -> __.typx.Annotated[ 

50 _violations.ViolationContext, 

51 __.ddoc.Doc( 'Violation with surrounding source context.' ) ]: 

52 ''' Extracts source code context around a violation. ''' 

53 line = violation.line 

54 start_line = max( 1, line - context_size ) 

55 end_line = min( len( self.source_lines ), line + context_size ) 

56 # Extract context lines (convert to 0-indexed for array access) 

57 context_lines = tuple( 

58 self.source_lines[ i ] 

59 for i in range( start_line - 1, end_line ) 

60 ) 

61 return _violations.ViolationContext( 

62 violation = violation, 

63 context_lines = context_lines, 

64 context_start_line = start_line, 

65 ) 

66 

67 def format_context_display( 

68 self, 

69 context: __.typx.Annotated[ 

70 _violations.ViolationContext, 

71 __.ddoc.Doc( 'Violation context to format for display.' ) ], 

72 highlight_line: __.typx.Annotated[ 

73 bool, 

74 __.ddoc.Doc( 'Whether to highlight the violation line.' ) ] = ( 

75 True ), 

76 ) -> __.typx.Annotated[ 

77 tuple[ str, ... ], 

78 __.ddoc.Doc( 

79 'Formatted context lines with line numbers and highlighting.' 

80 ) ]: 

81 ''' Formats violation context for display. ''' 

82 formatted_lines: list[ str ] = [ ] 

83 violation_line = context.violation.line 

84 for i, line in enumerate( context.context_lines ): 

85 line_number = context.context_start_line + i 

86 prefix = ( 

87 '→ ' if highlight_line and line_number == violation_line 

88 else ' ' ) 

89 formatted_lines.append( f'{line_number:4d}{prefix}{line}' ) 

90 return tuple( formatted_lines ) 

91 

92 

93def extract_contexts_for_violations( 

94 violations: __.typx.Annotated[ 

95 _violations.ViolationSequence, 

96 __.ddoc.Doc( 'Sequence of violations to extract contexts for.' ) ], 

97 source_lines: __.typx.Annotated[ 

98 __.cabc.Sequence[ str ], 

99 __.ddoc.Doc( 'Source file lines for context extraction.' ) ], 

100 context_size: __.typx.Annotated[ 

101 int, 

102 __.ddoc.Doc( 

103 'Number of lines to show before and after each violation.' 

104 ) ] = 2, 

105) -> tuple[ _violations.ViolationContext, ... ]: 

106 ''' Extracts contexts for multiple violations efficiently. ''' 

107 extractor = ContextExtractor( tuple( source_lines ) ) 

108 return tuple( 

109 extractor.extract_violation_context( violation, context_size ) 

110 for violation in violations 

111 )