11import io
22from typing import TYPE_CHECKING , Any , List , Optional
3+ from weakref import WeakKeyDictionary
34
45from robotcode .core .language import language_id
56from robotcode .core .lsp .types import (
2021from .robocop_tidy_mixin import RoboCopTidyMixin
2122
2223if TYPE_CHECKING :
24+ from robocop .linter .runner import RobocopLinter
25+
2326 from ..protocol import RobotLanguageServerProtocol
2427
2528
@@ -30,8 +33,9 @@ def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
3033 super ().__init__ (parent )
3134
3235 self .source_name = "robocop"
36+ self ._robocop_linters : WeakKeyDictionary [WorkspaceFolder , "RobocopLinter" ] = WeakKeyDictionary ()
3337
34- if self .robocop_installed and self . robocop_version < ( 6 , 0 ) :
38+ if self .robocop_installed :
3539 parent .diagnostics .collect .add (self .collect_diagnostics )
3640
3741 def get_config (self , document : TextDocument ) -> Optional [RoboCopConfig ]:
@@ -45,25 +49,96 @@ def get_config(self, document: TextDocument) -> Optional[RoboCopConfig]:
4549 @_logger .call
4650 def collect_diagnostics (
4751 self , sender : Any , document : TextDocument , diagnostics_type : DiagnosticsCollectType
48- ) -> DiagnosticsResult :
49- workspace_folder = self .parent .workspace .get_workspace_folder (document .uri )
50- if workspace_folder is not None :
51- extension_config = self .get_config (document )
52-
53- if extension_config is not None and extension_config .enabled :
54- return DiagnosticsResult (
55- self .collect_diagnostics ,
56- self .collect (document , workspace_folder , extension_config ),
57- )
52+ ) -> Optional [DiagnosticsResult ]:
53+ if self .robocop_installed :
54+ workspace_folder = self .parent .workspace .get_workspace_folder (document .uri )
55+ if workspace_folder is not None :
56+ config = self .get_config (document )
57+
58+ if config is not None and config .enabled :
59+ if self .robocop_version >= (6 , 0 ):
60+ # In Robocop 6.0, the diagnostics are collected in a different way
61+ return DiagnosticsResult (
62+ self .collect_diagnostics ,
63+ self .collect (document , workspace_folder , config ),
64+ )
5865
59- return DiagnosticsResult (self .collect_diagnostics , [])
66+ return DiagnosticsResult (
67+ self .collect_diagnostics ,
68+ self .collect_old (document , workspace_folder , config ),
69+ )
70+
71+ return None
6072
6173 @_logger .call
6274 def collect (
6375 self ,
6476 document : TextDocument ,
6577 workspace_folder : WorkspaceFolder ,
6678 extension_config : RoboCopConfig ,
79+ ) -> List [Diagnostic ]:
80+ from robocop .config import ConfigManager
81+ from robocop .linter .rules import RuleSeverity
82+ from robocop .linter .runner import RobocopLinter
83+
84+ linter = self ._robocop_linters .get (workspace_folder , None )
85+
86+ if linter is None :
87+ config_manager = ConfigManager (
88+ [],
89+ root = workspace_folder .uri .to_path (),
90+ config = extension_config .config_file ,
91+ ignore_git_dir = extension_config .ignore_git_dir ,
92+ ignore_file_config = extension_config .ignore_file_config ,
93+ )
94+ linter = RobocopLinter (config_manager )
95+ self ._robocop_linters [workspace_folder ] = linter
96+
97+ source = document .uri .to_path ()
98+
99+ config = linter .config_manager .get_config_for_source_file (source )
100+ model = self .parent .documents_cache .get_model (document , False )
101+ diagnostics = linter .run_check (model , source , config )
102+
103+ return [
104+ Diagnostic (
105+ range = Range (
106+ start = Position (
107+ line = diagnostic .range .start .line - 1 ,
108+ character = diagnostic .range .start .character - 1 ,
109+ ),
110+ end = Position (
111+ line = max (0 , diagnostic .range .end .line - 1 ),
112+ character = max (0 , diagnostic .range .end .character - 1 ),
113+ ),
114+ ),
115+ message = diagnostic .message ,
116+ severity = (
117+ DiagnosticSeverity .INFORMATION
118+ if diagnostic .severity == RuleSeverity .INFO
119+ else (
120+ DiagnosticSeverity .WARNING
121+ if diagnostic .severity == RuleSeverity .WARNING
122+ else (
123+ DiagnosticSeverity .ERROR
124+ if diagnostic .severity == RuleSeverity .ERROR
125+ else DiagnosticSeverity .HINT
126+ )
127+ )
128+ ),
129+ source = self .source_name ,
130+ code = f"{ diagnostic .rule .rule_id } -{ diagnostic .rule .name } " ,
131+ code_description = self .get_code_description (self .robocop_version , diagnostic ),
132+ )
133+ for diagnostic in diagnostics
134+ ]
135+
136+ @_logger .call
137+ def collect_old (
138+ self ,
139+ document : TextDocument ,
140+ workspace_folder : WorkspaceFolder ,
141+ extension_config : RoboCopConfig ,
67142 ) -> List [Diagnostic ]:
68143 from robocop import __version__
69144 from robocop .config import Config
@@ -174,7 +249,9 @@ def get_code_description(self, version: Version, issue: Any) -> Optional[CodeDes
174249 if version < (3 , 0 ):
175250 return None
176251
177- base = f"https://robocop.readthedocs.io/en/{ version .major } .{ version .minor } .{ version .patch } "
252+ version_letter = "v" if version .major >= 6 else ""
253+
254+ base = f"https://robocop.readthedocs.io/en/{ version_letter } { version .major } .{ version .minor } .{ version .patch } "
178255
179256 if version < (4 , 0 ):
180257 return CodeDescription (href = f"{ base } /rules.html#{ issue .name } " .lower ())
@@ -187,4 +264,7 @@ def get_code_description(self, version: Version, issue: Any) -> Optional[CodeDes
187264 href = f"{ base } /rules_list.html#{ issue .name } -{ issue .severity .value } { issue .rule_id } " .lower ()
188265 )
189266
190- return CodeDescription (href = f"{ base } /rules_list.html#{ issue .name } " .lower ())
267+ if version < (6 , 0 ):
268+ return CodeDescription (href = f"{ base } /rules_list.html#{ issue .name } " .lower ())
269+
270+ return CodeDescription (href = f"{ base } /rules/rules_list.html#{ issue .rule .rule_id } -{ issue .rule .name } " .lower ())
0 commit comments