robotcode-language-server 1.2.0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/PKG-INFO +5 -5
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/pyproject.toml +4 -4
- robotcode_language_server-1.3.0/src/robotcode/language_server/__version__.py +1 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/configuration.py +4 -1
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/document_symbols.py +1 -1
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/formatting.py +84 -34
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/hover.py +1 -1
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/keywords_treeview.py +122 -8
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/project_info.py +15 -12
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/robocop_diagnostics.py +96 -23
- robotcode_language_server-1.3.0/src/robotcode/language_server/robotframework/parts/robocop_tidy_mixin.py +49 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/semantic_tokens.py +8 -42
- robotcode_language_server-1.2.0/src/robotcode/language_server/__version__.py +0 -1
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/.gitignore +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/LICENSE.txt +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/README.md +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/__init__.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/cli.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/__init__.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/decorators.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/__init__.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/code_action.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/code_lens.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/commands.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/completion.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/declaration.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/definition.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/diagnostics.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/document_highlight.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/document_symbols.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/documents.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/folding_range.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/formatting.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/hover.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/implementation.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/inlay_hint.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/inline_value.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/linked_editing_ranges.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/protocol_part.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/references.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/rename.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/selection_range.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/semantic_tokens.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/signature_help.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/window.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/workspace.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/parts/workspace_symbols.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/protocol.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/common/server.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/hooks.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/py.typed +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/__init__.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/__init__.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/code_action_documentation.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/code_action_helper_mixin.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/code_action_quick_fixes.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/code_action_refactor.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/code_lens.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/completion.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/debugging_utils.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/diagnostics.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/document_highlight.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/documents_cache.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/folding_range.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/goto.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/http_server.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/inlay_hint.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/inline_value.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/protocol_part.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/references.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/rename.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/robot_workspace.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/selection_range.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/signature_help.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/parts/workspace_symbols.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/protocol.py +0 -0
- {robotcode_language_server-1.2.0 → robotcode_language_server-1.3.0}/src/robotcode/language_server/robotframework/server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robotcode-language-server
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: RobotCode Language Server for Robot Framework
|
|
5
5
|
Project-URL: Homepage, https://robotcode.io
|
|
6
6
|
Project-URL: Donate, https://opencollective.com/robotcode
|
|
@@ -25,10 +25,10 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
|
25
25
|
Classifier: Topic :: Utilities
|
|
26
26
|
Classifier: Typing :: Typed
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
|
-
Requires-Dist: robotcode-analyze==1.
|
|
29
|
-
Requires-Dist: robotcode-jsonrpc2==1.
|
|
30
|
-
Requires-Dist: robotcode-robot==1.
|
|
31
|
-
Requires-Dist: robotcode==1.
|
|
28
|
+
Requires-Dist: robotcode-analyze==1.3.0
|
|
29
|
+
Requires-Dist: robotcode-jsonrpc2==1.3.0
|
|
30
|
+
Requires-Dist: robotcode-robot==1.3.0
|
|
31
|
+
Requires-Dist: robotcode==1.3.0
|
|
32
32
|
Requires-Dist: robotframework>=4.1.0
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
|
|
@@ -27,10 +27,10 @@ classifiers = [
|
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
29
|
"robotframework>=4.1.0",
|
|
30
|
-
"robotcode-jsonrpc2==1.
|
|
31
|
-
"robotcode-robot==1.
|
|
32
|
-
"robotcode-analyze==1.
|
|
33
|
-
"robotcode==1.
|
|
30
|
+
"robotcode-jsonrpc2==1.3.0",
|
|
31
|
+
"robotcode-robot==1.3.0",
|
|
32
|
+
"robotcode-analyze==1.3.0",
|
|
33
|
+
"robotcode==1.3.0",
|
|
34
34
|
]
|
|
35
35
|
dynamic = ["version"]
|
|
36
36
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.0"
|
|
@@ -33,6 +33,9 @@ class RoboCopConfig(ConfigBase):
|
|
|
33
33
|
enabled: bool = True
|
|
34
34
|
include: List[str] = field(default_factory=list)
|
|
35
35
|
exclude: List[str] = field(default_factory=list)
|
|
36
|
+
ignore_git_dir: bool = False
|
|
37
|
+
ignore_file_config: bool = False
|
|
38
|
+
config_file: Optional[str] = None
|
|
36
39
|
configurations: List[str] = field(default_factory=list)
|
|
37
40
|
|
|
38
41
|
|
|
@@ -49,7 +52,7 @@ class RoboTidyConfig(ConfigBase):
|
|
|
49
52
|
class DocumentationServerConfig(ConfigBase):
|
|
50
53
|
start_port: int = 3100
|
|
51
54
|
end_port: int = 3199
|
|
52
|
-
start_on_demand: bool =
|
|
55
|
+
start_on_demand: bool = False
|
|
53
56
|
|
|
54
57
|
|
|
55
58
|
@config_section("robotcode.inlayHints")
|
|
@@ -6,7 +6,6 @@ from robot.errors import VariableError
|
|
|
6
6
|
from robot.parsing.lexer.tokens import Token
|
|
7
7
|
from robot.parsing.model.blocks import Keyword, Section, TestCase
|
|
8
8
|
from robot.parsing.model.statements import Statement
|
|
9
|
-
from robot.variables import search_variable
|
|
10
9
|
|
|
11
10
|
from robotcode.core.language import language_id
|
|
12
11
|
from robotcode.core.lsp.types import (
|
|
@@ -21,6 +20,7 @@ from robotcode.robot.utils.ast import (
|
|
|
21
20
|
range_from_token,
|
|
22
21
|
tokenize_variables,
|
|
23
22
|
)
|
|
23
|
+
from robotcode.robot.utils.variables import search_variable
|
|
24
24
|
from robotcode.robot.utils.visitor import Visitor
|
|
25
25
|
|
|
26
26
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import os
|
|
3
|
-
import re
|
|
4
3
|
from concurrent.futures import CancelledError
|
|
5
4
|
from typing import TYPE_CHECKING, Any, List, Optional, cast
|
|
6
5
|
|
|
@@ -14,26 +13,17 @@ from robotcode.core.lsp.types import (
|
|
|
14
13
|
)
|
|
15
14
|
from robotcode.core.text_document import TextDocument
|
|
16
15
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
17
|
-
from robotcode.core.utils.version import create_version_from_str
|
|
18
|
-
from robotcode.robot.diagnostics.model_helper import ModelHelper
|
|
19
16
|
from robotcode.robot.utils import get_robot_version
|
|
20
17
|
|
|
21
|
-
from ..configuration import RoboTidyConfig
|
|
18
|
+
from ..configuration import RoboCopConfig, RoboTidyConfig
|
|
22
19
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
20
|
+
from .robocop_tidy_mixin import RoboCopTidyMixin
|
|
23
21
|
|
|
24
22
|
if TYPE_CHECKING:
|
|
25
23
|
from ..protocol import RobotLanguageServerProtocol
|
|
26
24
|
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
try:
|
|
30
|
-
__import__("robotidy")
|
|
31
|
-
except ImportError:
|
|
32
|
-
return False
|
|
33
|
-
return True
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
26
|
+
class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, RoboCopTidyMixin):
|
|
37
27
|
_logger = LoggingDescriptor()
|
|
38
28
|
|
|
39
29
|
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
@@ -41,7 +31,7 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
41
31
|
|
|
42
32
|
parent.formatting.format.add(self.format)
|
|
43
33
|
|
|
44
|
-
if robotidy_installed():
|
|
34
|
+
if self.robotidy_installed or (self.robocop_installed and self.robocop_version >= (6, 0)):
|
|
45
35
|
parent.formatting.format_range.add(self.format_range)
|
|
46
36
|
|
|
47
37
|
self.space_count = 4
|
|
@@ -49,14 +39,22 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
49
39
|
self.line_separator = os.linesep
|
|
50
40
|
self.short_test_name_length = 18
|
|
51
41
|
self.setting_and_variable_name_length = 14
|
|
42
|
+
self.is_robocop_notification_shown = False
|
|
52
43
|
|
|
53
|
-
def
|
|
44
|
+
def get_tidy_config(self, document: TextDocument) -> RoboTidyConfig:
|
|
54
45
|
folder = self.parent.workspace.get_workspace_folder(document.uri)
|
|
55
46
|
if folder is None:
|
|
56
47
|
return RoboTidyConfig()
|
|
57
48
|
|
|
58
49
|
return self.parent.workspace.get_configuration(RoboTidyConfig, folder.uri)
|
|
59
50
|
|
|
51
|
+
def get_robocop_config(self, document: TextDocument) -> RoboCopConfig:
|
|
52
|
+
folder = self.parent.workspace.get_workspace_folder(document.uri)
|
|
53
|
+
if folder is None:
|
|
54
|
+
return RoboCopConfig()
|
|
55
|
+
|
|
56
|
+
return self.parent.workspace.get_configuration(RoboCopConfig, folder.uri)
|
|
57
|
+
|
|
60
58
|
@language_id("robotframework")
|
|
61
59
|
@_logger.call
|
|
62
60
|
def format(
|
|
@@ -66,23 +64,33 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
66
64
|
options: FormattingOptions,
|
|
67
65
|
**further_options: Any,
|
|
68
66
|
) -> Optional[List[TextEdit]]:
|
|
69
|
-
|
|
67
|
+
if self.robocop_installed and self.robocop_version >= (6, 0):
|
|
68
|
+
if not self.is_robocop_notification_shown and self.robotidy_installed:
|
|
69
|
+
self.parent.window.show_message(
|
|
70
|
+
"`robotframework-robocop >= 6.0` is installed and will be used for formatting.\n\n"
|
|
71
|
+
"`robotframework-tidy` is also detected in the workspace, but its use is redundant.\n"
|
|
72
|
+
"Robocop fully supports all formatting tasks and provides a more comprehensive solution.\n\n"
|
|
73
|
+
"Note: The use of `robotframework-tidy` is deprecated and should be avoided in favor of Robocop.",
|
|
74
|
+
MessageType.INFO,
|
|
75
|
+
)
|
|
76
|
+
self.is_robocop_notification_shown = True
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
return self.format_robocop(document, options, **further_options)
|
|
79
|
+
|
|
80
|
+
tidy_config = self.get_tidy_config(document)
|
|
81
|
+
if (tidy_config.enabled or get_robot_version() >= (5, 0)) and self.robotidy_installed:
|
|
82
|
+
return self.format_robot_tidy(document, options, config=tidy_config, **further_options)
|
|
73
83
|
|
|
74
84
|
if get_robot_version() < (5, 0):
|
|
75
85
|
return self.format_internal(document, options, **further_options)
|
|
76
86
|
|
|
77
87
|
self.parent.window.show_message(
|
|
78
|
-
"RobotFramework formatter is not available, please install 'robotframework-
|
|
88
|
+
"RobotFramework formatter is not available, please install 'robotframework-robocop'.",
|
|
79
89
|
MessageType.ERROR,
|
|
80
90
|
)
|
|
81
91
|
|
|
82
92
|
return None
|
|
83
93
|
|
|
84
|
-
RE_LINEBREAKS = re.compile(r"\r\n|\r|\n")
|
|
85
|
-
|
|
86
94
|
def format_robot_tidy(
|
|
87
95
|
self,
|
|
88
96
|
document: TextDocument,
|
|
@@ -91,28 +99,24 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
91
99
|
config: Optional[RoboTidyConfig] = None,
|
|
92
100
|
**further_options: Any,
|
|
93
101
|
) -> Optional[List[TextEdit]]:
|
|
94
|
-
from robotidy.version import __version__
|
|
95
|
-
|
|
96
102
|
try:
|
|
97
103
|
if config is None:
|
|
98
|
-
config = self.
|
|
99
|
-
|
|
100
|
-
robotidy_version = create_version_from_str(__version__)
|
|
104
|
+
config = self.get_tidy_config(document)
|
|
101
105
|
|
|
102
106
|
model = self.parent.documents_cache.get_model(document, False)
|
|
103
107
|
|
|
104
|
-
if robotidy_version >= (3, 0):
|
|
108
|
+
if self.robotidy_version >= (3, 0):
|
|
105
109
|
from robotidy.api import get_robotidy
|
|
106
110
|
from robotidy.disablers import RegisterDisablers
|
|
107
111
|
|
|
108
|
-
if robotidy_version >= (4, 2):
|
|
112
|
+
if self.robotidy_version >= (4, 2):
|
|
109
113
|
robot_tidy = get_robotidy(
|
|
110
114
|
document.uri.to_path(),
|
|
111
115
|
None,
|
|
112
116
|
ignore_git_dir=config.ignore_git_dir,
|
|
113
117
|
config=config.config,
|
|
114
118
|
)
|
|
115
|
-
elif robotidy_version >= (4, 1):
|
|
119
|
+
elif self.robotidy_version >= (4, 1):
|
|
116
120
|
robot_tidy = get_robotidy(
|
|
117
121
|
document.uri.to_path(),
|
|
118
122
|
None,
|
|
@@ -131,14 +135,14 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
131
135
|
)
|
|
132
136
|
disabler_finder.visit(model)
|
|
133
137
|
|
|
134
|
-
if robotidy_version >= (4, 11):
|
|
138
|
+
if self.robotidy_version >= (4, 11):
|
|
135
139
|
if disabler_finder.is_disabled_in_file():
|
|
136
140
|
return None
|
|
137
141
|
else:
|
|
138
142
|
if disabler_finder.file_disabled:
|
|
139
143
|
return None
|
|
140
144
|
|
|
141
|
-
if robotidy_version >= (4, 0):
|
|
145
|
+
if self.robotidy_version >= (4, 0):
|
|
142
146
|
_, _, new, _ = robot_tidy.transform_until_stable(model, disabler_finder)
|
|
143
147
|
else:
|
|
144
148
|
_, _, new = robot_tidy.transform(model, disabler_finder.disablers)
|
|
@@ -152,7 +156,7 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
152
156
|
robot_tidy.formatting_config.start_line = range.start.line + 1
|
|
153
157
|
robot_tidy.formatting_config.end_line = range.end.line + 1
|
|
154
158
|
|
|
155
|
-
if robotidy_version >= (2, 2):
|
|
159
|
+
if self.robotidy_version >= (2, 2):
|
|
156
160
|
from robotidy.disablers import RegisterDisablers
|
|
157
161
|
|
|
158
162
|
disabler_finder = RegisterDisablers(
|
|
@@ -186,6 +190,52 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
186
190
|
self.parent.window.show_message(f"Executing `robotidy` failed: {e}", MessageType.ERROR)
|
|
187
191
|
return None
|
|
188
192
|
|
|
193
|
+
def format_robocop(
|
|
194
|
+
self,
|
|
195
|
+
document: TextDocument,
|
|
196
|
+
options: FormattingOptions,
|
|
197
|
+
range: Optional[Range] = None,
|
|
198
|
+
**further_options: Any,
|
|
199
|
+
) -> Optional[List[TextEdit]]:
|
|
200
|
+
from robocop.config import ConfigManager
|
|
201
|
+
from robocop.formatter.runner import RobocopFormatter
|
|
202
|
+
|
|
203
|
+
robocop_config = self.get_robocop_config(document)
|
|
204
|
+
workspace_folder = self.parent.workspace.get_workspace_folder(document.uri)
|
|
205
|
+
|
|
206
|
+
config_manager = ConfigManager(
|
|
207
|
+
[document.uri.to_path()],
|
|
208
|
+
root=workspace_folder.uri.to_path() if workspace_folder else None,
|
|
209
|
+
config=robocop_config.config_file,
|
|
210
|
+
ignore_git_dir=robocop_config.ignore_git_dir,
|
|
211
|
+
ignore_file_config=robocop_config.ignore_file_config,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
config = config_manager.get_config_for_source_file(document.uri.to_path())
|
|
215
|
+
|
|
216
|
+
if range is not None:
|
|
217
|
+
config.formatter.start_line = range.start.line + 1
|
|
218
|
+
config.formatter.end_line = range.end.line + 1
|
|
219
|
+
|
|
220
|
+
runner = RobocopFormatter(config_manager)
|
|
221
|
+
runner.config = config
|
|
222
|
+
|
|
223
|
+
model = self.parent.documents_cache.get_model(document, False)
|
|
224
|
+
_, _, new, _ = runner.format_until_stable(model)
|
|
225
|
+
|
|
226
|
+
if new.text == document.text():
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
return [
|
|
230
|
+
TextEdit(
|
|
231
|
+
range=Range(
|
|
232
|
+
start=Position(line=0, character=0),
|
|
233
|
+
end=Position(line=len(document.get_lines()), character=0),
|
|
234
|
+
),
|
|
235
|
+
new_text=new.text,
|
|
236
|
+
)
|
|
237
|
+
]
|
|
238
|
+
|
|
189
239
|
def format_internal(
|
|
190
240
|
self,
|
|
191
241
|
document: TextDocument,
|
|
@@ -233,8 +283,8 @@ class RobotFormattingProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
233
283
|
options: FormattingOptions,
|
|
234
284
|
**further_options: Any,
|
|
235
285
|
) -> Optional[List[TextEdit]]:
|
|
236
|
-
config = self.
|
|
237
|
-
if config.enabled and robotidy_installed():
|
|
286
|
+
config = self.get_tidy_config(document)
|
|
287
|
+
if (config.enabled and self.robotidy_installed) or (self.robocop_installed and self.robocop_version >= (6, 0)):
|
|
238
288
|
return self.format_robot_tidy(document, options, range=range, config=config, **further_options)
|
|
239
289
|
|
|
240
290
|
return None
|
|
@@ -163,7 +163,7 @@ class RobotHoverProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
163
163
|
else:
|
|
164
164
|
value = ""
|
|
165
165
|
|
|
166
|
-
text = f"### {variable.type.value.title()} `{variable.
|
|
166
|
+
text = f"### {variable.type.value.title()} `{variable.convertable_name}`\n\n"
|
|
167
167
|
|
|
168
168
|
if value:
|
|
169
169
|
text += "```python\n"
|
|
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
|
|
2
2
|
from typing import TYPE_CHECKING, Any, List, Optional
|
|
3
3
|
|
|
4
4
|
from robotcode.core.lsp.types import TextDocumentIdentifier
|
|
5
|
+
from robotcode.core.uri import Uri
|
|
5
6
|
from robotcode.core.utils.dataclasses import CamelSnakeMixin
|
|
6
7
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
7
8
|
from robotcode.jsonrpc2.protocol import rpc_method
|
|
@@ -16,6 +17,26 @@ if TYPE_CHECKING:
|
|
|
16
17
|
@dataclass(repr=False)
|
|
17
18
|
class GetDocumentImportsParams(CamelSnakeMixin):
|
|
18
19
|
text_document: TextDocumentIdentifier
|
|
20
|
+
no_documentation: Optional[bool] = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(repr=False)
|
|
24
|
+
class GetDocumentKeywordsParams(CamelSnakeMixin):
|
|
25
|
+
text_document: TextDocumentIdentifier
|
|
26
|
+
no_documentation: Optional[bool] = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(repr=False)
|
|
30
|
+
class GetLibraryDocumentationParams(CamelSnakeMixin):
|
|
31
|
+
workspace_folder_uri: str
|
|
32
|
+
library_name: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(repr=False)
|
|
36
|
+
class GetKeywordDocumentationParams(CamelSnakeMixin):
|
|
37
|
+
workspace_folder_uri: str
|
|
38
|
+
library_name: str
|
|
39
|
+
keyword_name: str
|
|
19
40
|
|
|
20
41
|
|
|
21
42
|
@dataclass(repr=False)
|
|
@@ -26,6 +47,14 @@ class Keyword(CamelSnakeMixin):
|
|
|
26
47
|
documentation: Optional[str] = None
|
|
27
48
|
|
|
28
49
|
|
|
50
|
+
@dataclass(repr=False)
|
|
51
|
+
class LibraryDocumentation(CamelSnakeMixin):
|
|
52
|
+
name: str
|
|
53
|
+
documentation: Optional[str] = None
|
|
54
|
+
keywords: Optional[List[Keyword]] = None
|
|
55
|
+
initializers: Optional[List[Keyword]] = None
|
|
56
|
+
|
|
57
|
+
|
|
29
58
|
@dataclass(repr=False)
|
|
30
59
|
class DocumentImport(CamelSnakeMixin):
|
|
31
60
|
name: str
|
|
@@ -54,6 +83,7 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
54
83
|
def _get_document_imports(
|
|
55
84
|
self,
|
|
56
85
|
text_document: TextDocumentIdentifier,
|
|
86
|
+
no_documentation: Optional[bool] = None,
|
|
57
87
|
*args: Any,
|
|
58
88
|
**kwargs: Any,
|
|
59
89
|
) -> Optional[List[DocumentImport]]:
|
|
@@ -72,16 +102,18 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
72
102
|
alias=v.alias,
|
|
73
103
|
id=str(hash(v)),
|
|
74
104
|
type="library",
|
|
75
|
-
documentation=v.library_doc.to_markdown(add_signature=False),
|
|
105
|
+
documentation=v.library_doc.to_markdown(add_signature=False) if not no_documentation else None,
|
|
76
106
|
keywords=[
|
|
77
107
|
Keyword(
|
|
78
108
|
l.name,
|
|
79
109
|
str(hash(l)),
|
|
80
110
|
l.parameter_signature(),
|
|
81
|
-
l.to_markdown(add_signature=False),
|
|
111
|
+
l.to_markdown(add_signature=False) if not no_documentation else None,
|
|
82
112
|
)
|
|
83
113
|
for l in v.library_doc.keywords.values()
|
|
84
|
-
]
|
|
114
|
+
]
|
|
115
|
+
if not no_documentation
|
|
116
|
+
else None,
|
|
85
117
|
)
|
|
86
118
|
)
|
|
87
119
|
for _k, v in namespace.get_resources().items():
|
|
@@ -91,21 +123,29 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
91
123
|
alias=None,
|
|
92
124
|
id=str(hash(v)),
|
|
93
125
|
type="resource",
|
|
94
|
-
documentation=v.library_doc.to_markdown(add_signature=False),
|
|
126
|
+
documentation=v.library_doc.to_markdown(add_signature=False) if not no_documentation else None,
|
|
95
127
|
keywords=[
|
|
96
|
-
Keyword(
|
|
128
|
+
Keyword(
|
|
129
|
+
l.name,
|
|
130
|
+
str(hash(l)),
|
|
131
|
+
l.parameter_signature(),
|
|
132
|
+
l.to_markdown(add_signature=False) if not no_documentation else None,
|
|
133
|
+
)
|
|
97
134
|
for l in v.library_doc.keywords.values()
|
|
98
|
-
]
|
|
135
|
+
]
|
|
136
|
+
if not no_documentation
|
|
137
|
+
else None,
|
|
99
138
|
)
|
|
100
139
|
)
|
|
101
140
|
|
|
102
141
|
return result
|
|
103
142
|
|
|
104
|
-
@rpc_method(name="robot/keywordsview/getDocumentKeywords", param_type=
|
|
143
|
+
@rpc_method(name="robot/keywordsview/getDocumentKeywords", param_type=GetDocumentKeywordsParams, threaded=True)
|
|
105
144
|
@_logger.call
|
|
106
145
|
def _get_document_keywords(
|
|
107
146
|
self,
|
|
108
147
|
text_document: TextDocumentIdentifier,
|
|
148
|
+
no_documentation: Optional[bool] = None,
|
|
109
149
|
*args: Any,
|
|
110
150
|
**kwargs: Any,
|
|
111
151
|
) -> Optional[List[Keyword]]:
|
|
@@ -116,7 +156,12 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
116
156
|
namespace = self.parent.documents_cache.get_namespace(document)
|
|
117
157
|
|
|
118
158
|
return [
|
|
119
|
-
Keyword(
|
|
159
|
+
Keyword(
|
|
160
|
+
l.name,
|
|
161
|
+
str(hash(l)),
|
|
162
|
+
l.parameter_signature(),
|
|
163
|
+
l.to_markdown(add_signature=False) if not no_documentation else None,
|
|
164
|
+
)
|
|
120
165
|
for l in namespace.get_library_doc().keywords.values()
|
|
121
166
|
]
|
|
122
167
|
|
|
@@ -165,3 +210,72 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
165
210
|
)
|
|
166
211
|
|
|
167
212
|
return None
|
|
213
|
+
|
|
214
|
+
@rpc_method(
|
|
215
|
+
name="robot/keywordsview/getLibraryDocumentation", param_type=GetLibraryDocumentationParams, threaded=True
|
|
216
|
+
)
|
|
217
|
+
@_logger.call
|
|
218
|
+
def _get_library_documentation(
|
|
219
|
+
self,
|
|
220
|
+
workspace_folder_uri: str,
|
|
221
|
+
library_name: str,
|
|
222
|
+
*args: Any,
|
|
223
|
+
**kwargs: Any,
|
|
224
|
+
) -> Optional[LibraryDocumentation]:
|
|
225
|
+
imports_manager = self.parent.documents_cache.get_imports_manager_for_uri(Uri(workspace_folder_uri))
|
|
226
|
+
|
|
227
|
+
libdoc = imports_manager.get_libdoc_for_library_import(library_name, (), ".")
|
|
228
|
+
if libdoc.errors:
|
|
229
|
+
raise ValueError(f"Errors while loading library documentation: {libdoc.errors}")
|
|
230
|
+
|
|
231
|
+
return LibraryDocumentation(
|
|
232
|
+
name=libdoc.name,
|
|
233
|
+
documentation=libdoc.to_markdown(),
|
|
234
|
+
keywords=[
|
|
235
|
+
Keyword(
|
|
236
|
+
l.name,
|
|
237
|
+
str(hash(l)),
|
|
238
|
+
l.parameter_signature(),
|
|
239
|
+
l.to_markdown(),
|
|
240
|
+
)
|
|
241
|
+
for l in libdoc.keywords.values()
|
|
242
|
+
],
|
|
243
|
+
initializers=[
|
|
244
|
+
Keyword(
|
|
245
|
+
s.name,
|
|
246
|
+
str(hash(s)),
|
|
247
|
+
s.parameter_signature(),
|
|
248
|
+
s.to_markdown(),
|
|
249
|
+
)
|
|
250
|
+
for s in libdoc.inits.values()
|
|
251
|
+
],
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
@rpc_method(
|
|
255
|
+
name="robot/keywordsview/getKeywordDocumentation", param_type=GetKeywordDocumentationParams, threaded=True
|
|
256
|
+
)
|
|
257
|
+
@_logger.call
|
|
258
|
+
def _get_keyword_documentation(
|
|
259
|
+
self,
|
|
260
|
+
workspace_folder_uri: str,
|
|
261
|
+
library_name: str,
|
|
262
|
+
keyword_name: str,
|
|
263
|
+
*args: Any,
|
|
264
|
+
**kwargs: Any,
|
|
265
|
+
) -> Optional[Keyword]:
|
|
266
|
+
imports_manager = self.parent.documents_cache.get_imports_manager_for_uri(Uri(workspace_folder_uri))
|
|
267
|
+
|
|
268
|
+
libdoc = imports_manager.get_libdoc_for_library_import(library_name, (), ".")
|
|
269
|
+
if libdoc.errors:
|
|
270
|
+
raise ValueError(f"Errors while loading library documentation: {libdoc.errors}")
|
|
271
|
+
|
|
272
|
+
kw = libdoc.keywords.get(keyword_name, None)
|
|
273
|
+
if kw is None:
|
|
274
|
+
raise ValueError(f"Keyword '{keyword_name}' not found in library '{library_name}'.")
|
|
275
|
+
|
|
276
|
+
return Keyword(
|
|
277
|
+
name=kw.name,
|
|
278
|
+
id=str(hash(kw)),
|
|
279
|
+
signature=kw.parameter_signature(),
|
|
280
|
+
documentation=kw.to_markdown(),
|
|
281
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
from dataclasses import dataclass
|
|
2
3
|
from typing import TYPE_CHECKING, Any, Optional
|
|
3
4
|
|
|
@@ -7,9 +8,9 @@ from robotcode.core.utils.dataclasses import CamelSnakeMixin
|
|
|
7
8
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
8
9
|
from robotcode.jsonrpc2.protocol import rpc_method
|
|
9
10
|
|
|
10
|
-
from
|
|
11
|
+
from ...__version__ import __version__ as robotcode_version
|
|
11
12
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
12
|
-
from .
|
|
13
|
+
from .robocop_tidy_mixin import RoboCopTidyMixin
|
|
13
14
|
|
|
14
15
|
if TYPE_CHECKING:
|
|
15
16
|
from ..protocol import RobotLanguageServerProtocol
|
|
@@ -20,9 +21,12 @@ class ProjectInfo(CamelSnakeMixin):
|
|
|
20
21
|
robot_version_string: str
|
|
21
22
|
robocop_version_string: Optional[str]
|
|
22
23
|
tidy_version_string: Optional[str] = None
|
|
24
|
+
python_version_string: Optional[str] = None
|
|
25
|
+
python_executable: Optional[str] = None
|
|
26
|
+
robot_code_version_string: Optional[str] = None
|
|
23
27
|
|
|
24
28
|
|
|
25
|
-
class ProjectInfoPart(RobotLanguageServerProtocolPart):
|
|
29
|
+
class ProjectInfoPart(RobotLanguageServerProtocolPart, RoboCopTidyMixin):
|
|
26
30
|
_logger = LoggingDescriptor()
|
|
27
31
|
|
|
28
32
|
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
@@ -30,25 +34,24 @@ class ProjectInfoPart(RobotLanguageServerProtocolPart):
|
|
|
30
34
|
|
|
31
35
|
@rpc_method(name="robot/projectInfo", threaded=True)
|
|
32
36
|
@_logger.call
|
|
33
|
-
def
|
|
37
|
+
def _robot_project_info(
|
|
34
38
|
self,
|
|
35
39
|
*args: Any,
|
|
36
40
|
**kwargs: Any,
|
|
37
41
|
) -> ProjectInfo:
|
|
38
42
|
robocop_version_string = None
|
|
39
|
-
if robocop_installed
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
robocop_version_string = __version__
|
|
43
|
+
if self.robocop_installed:
|
|
44
|
+
robocop_version_string = self.robocop_version_str
|
|
43
45
|
|
|
44
46
|
tidy_version_string = None
|
|
45
|
-
if robotidy_installed
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
tidy_version_string = __version__
|
|
47
|
+
if self.robotidy_installed:
|
|
48
|
+
tidy_version_string = self.robotidy_version_str
|
|
49
49
|
|
|
50
50
|
return ProjectInfo(
|
|
51
51
|
robot_version_string=get_version(),
|
|
52
52
|
robocop_version_string=robocop_version_string,
|
|
53
53
|
tidy_version_string=tidy_version_string,
|
|
54
|
+
python_version_string=sys.version,
|
|
55
|
+
python_executable=sys.executable,
|
|
56
|
+
robot_code_version_string=robotcode_version,
|
|
54
57
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import io
|
|
2
2
|
from typing import TYPE_CHECKING, Any, List, Optional
|
|
3
|
+
from weakref import WeakKeyDictionary
|
|
3
4
|
|
|
4
5
|
from robotcode.core.language import language_id
|
|
5
6
|
from robotcode.core.lsp.types import (
|
|
@@ -17,28 +18,24 @@ from robotcode.core.workspace import WorkspaceFolder
|
|
|
17
18
|
from ...common.parts.diagnostics import DiagnosticsCollectType, DiagnosticsResult
|
|
18
19
|
from ..configuration import RoboCopConfig
|
|
19
20
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
21
|
+
from .robocop_tidy_mixin import RoboCopTidyMixin
|
|
20
22
|
|
|
21
23
|
if TYPE_CHECKING:
|
|
22
|
-
from
|
|
23
|
-
|
|
24
|
+
from robocop.linter.runner import RobocopLinter
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
try:
|
|
27
|
-
__import__("robocop")
|
|
28
|
-
except ImportError:
|
|
29
|
-
return False
|
|
30
|
-
return True
|
|
26
|
+
from ..protocol import RobotLanguageServerProtocol
|
|
31
27
|
|
|
32
28
|
|
|
33
|
-
class RobotRoboCopDiagnosticsProtocolPart(RobotLanguageServerProtocolPart):
|
|
29
|
+
class RobotRoboCopDiagnosticsProtocolPart(RobotLanguageServerProtocolPart, RoboCopTidyMixin):
|
|
34
30
|
_logger = LoggingDescriptor()
|
|
35
31
|
|
|
36
32
|
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
37
33
|
super().__init__(parent)
|
|
38
34
|
|
|
39
35
|
self.source_name = "robocop"
|
|
36
|
+
self._robocop_linters: WeakKeyDictionary[WorkspaceFolder, "RobocopLinter"] = WeakKeyDictionary()
|
|
40
37
|
|
|
41
|
-
if robocop_installed
|
|
38
|
+
if self.robocop_installed:
|
|
42
39
|
parent.diagnostics.collect.add(self.collect_diagnostics)
|
|
43
40
|
|
|
44
41
|
def get_config(self, document: TextDocument) -> Optional[RoboCopConfig]:
|
|
@@ -52,18 +49,26 @@ class RobotRoboCopDiagnosticsProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
52
49
|
@_logger.call
|
|
53
50
|
def collect_diagnostics(
|
|
54
51
|
self, sender: Any, document: TextDocument, diagnostics_type: DiagnosticsCollectType
|
|
55
|
-
) -> DiagnosticsResult:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
self.
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
)
|
|
65
|
+
|
|
66
|
+
return DiagnosticsResult(
|
|
67
|
+
self.collect_diagnostics,
|
|
68
|
+
self.collect_old(document, workspace_folder, config),
|
|
69
|
+
)
|
|
65
70
|
|
|
66
|
-
return
|
|
71
|
+
return None
|
|
67
72
|
|
|
68
73
|
@_logger.call
|
|
69
74
|
def collect(
|
|
@@ -71,6 +76,69 @@ class RobotRoboCopDiagnosticsProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
71
76
|
document: TextDocument,
|
|
72
77
|
workspace_folder: WorkspaceFolder,
|
|
73
78
|
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,
|
|
74
142
|
) -> List[Diagnostic]:
|
|
75
143
|
from robocop import __version__
|
|
76
144
|
from robocop.config import Config
|
|
@@ -181,7 +249,9 @@ class RobotRoboCopDiagnosticsProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
181
249
|
if version < (3, 0):
|
|
182
250
|
return None
|
|
183
251
|
|
|
184
|
-
|
|
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}"
|
|
185
255
|
|
|
186
256
|
if version < (4, 0):
|
|
187
257
|
return CodeDescription(href=f"{base}/rules.html#{issue.name}".lower())
|
|
@@ -194,4 +264,7 @@ class RobotRoboCopDiagnosticsProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
194
264
|
href=f"{base}/rules_list.html#{issue.name}-{issue.severity.value}{issue.rule_id}".lower()
|
|
195
265
|
)
|
|
196
266
|
|
|
197
|
-
|
|
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,0 +1,49 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
|
|
3
|
+
from robotcode.core.utils.version import Version, create_version_from_str
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RoboCopTidyMixin:
|
|
7
|
+
"""
|
|
8
|
+
Mixin class for handling Robocop tidy operations.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
@functools.cached_property
|
|
12
|
+
def robotidy_installed(self) -> bool:
|
|
13
|
+
try:
|
|
14
|
+
__import__("robotidy")
|
|
15
|
+
except ImportError:
|
|
16
|
+
return False
|
|
17
|
+
return True
|
|
18
|
+
|
|
19
|
+
@functools.cached_property
|
|
20
|
+
def robotidy_version(self) -> Version:
|
|
21
|
+
from robotidy.version import __version__
|
|
22
|
+
|
|
23
|
+
return create_version_from_str(__version__)
|
|
24
|
+
|
|
25
|
+
@functools.cached_property
|
|
26
|
+
def robotidy_version_str(self) -> str:
|
|
27
|
+
from robotidy.version import __version__
|
|
28
|
+
|
|
29
|
+
return str(__version__)
|
|
30
|
+
|
|
31
|
+
@functools.cached_property
|
|
32
|
+
def robocop_installed(self) -> bool:
|
|
33
|
+
try:
|
|
34
|
+
__import__("robocop")
|
|
35
|
+
except ImportError:
|
|
36
|
+
return False
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
@functools.cached_property
|
|
40
|
+
def robocop_version(self) -> Version:
|
|
41
|
+
from robocop import __version__
|
|
42
|
+
|
|
43
|
+
return create_version_from_str(__version__)
|
|
44
|
+
|
|
45
|
+
@functools.cached_property
|
|
46
|
+
def robocop_version_str(self) -> str:
|
|
47
|
+
from robocop import __version__
|
|
48
|
+
|
|
49
|
+
return str(__version__)
|
|
@@ -70,7 +70,7 @@ from robotcode.robot.utils.ast import (
|
|
|
70
70
|
iter_over_keyword_names_and_owners,
|
|
71
71
|
token_in_range,
|
|
72
72
|
)
|
|
73
|
-
from robotcode.robot.utils.variables import
|
|
73
|
+
from robotcode.robot.utils.variables import split_from_equals
|
|
74
74
|
|
|
75
75
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
76
76
|
|
|
@@ -116,6 +116,8 @@ class RobotSemTokenTypes(Enum):
|
|
|
116
116
|
FOR_SEPARATOR = "forSeparator"
|
|
117
117
|
VARIABLE_BEGIN = "variableBegin"
|
|
118
118
|
VARIABLE_END = "variableEnd"
|
|
119
|
+
EXPRESSION_BEGIN = "expressionBegin"
|
|
120
|
+
EXPRESSION_END = "expressionEnd"
|
|
119
121
|
VARIABLE_EXPRESSION = "variableExpression"
|
|
120
122
|
ESCAPE = "escape"
|
|
121
123
|
NAMESPACE = "namespace"
|
|
@@ -362,46 +364,8 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
362
364
|
sem_mod = {SemanticTokenModifiers.DOCUMENTATION}
|
|
363
365
|
|
|
364
366
|
if token.type in [Token.VARIABLE, Token.ASSIGN]:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
col_offset = token.col_offset
|
|
368
|
-
if length is None:
|
|
369
|
-
length = token.end_col_offset - token.col_offset
|
|
370
|
-
|
|
371
|
-
last_index = token.value.rfind("}")
|
|
372
|
-
|
|
373
|
-
is_expr = token.value[1:2] == "{" and token.value[last_index - 1 : last_index] == "}"
|
|
374
|
-
|
|
375
|
-
if last_index >= 0:
|
|
376
|
-
yield SemTokenInfo(
|
|
377
|
-
token.lineno,
|
|
378
|
-
col_offset,
|
|
379
|
-
3 if is_expr else 2,
|
|
380
|
-
RobotSemTokenTypes.VARIABLE_BEGIN,
|
|
381
|
-
sem_mod,
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
yield SemTokenInfo(
|
|
385
|
-
token.lineno,
|
|
386
|
-
col_offset + ((last_index - 1) if is_expr else last_index),
|
|
387
|
-
2 if is_expr else 1,
|
|
388
|
-
RobotSemTokenTypes.VARIABLE_END,
|
|
389
|
-
sem_mod,
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
if length - last_index - 1 > 0:
|
|
393
|
-
yield SemTokenInfo.from_token(
|
|
394
|
-
token,
|
|
395
|
-
sem_type,
|
|
396
|
-
sem_mod,
|
|
397
|
-
col_offset + last_index + 1,
|
|
398
|
-
length - last_index - 1,
|
|
399
|
-
)
|
|
400
|
-
else:
|
|
401
|
-
yield SemTokenInfo.from_token(token, sem_type, sem_mod)
|
|
402
|
-
|
|
403
|
-
else:
|
|
404
|
-
yield SemTokenInfo.from_token(token, sem_type, sem_mod)
|
|
367
|
+
# TODO: maybe we can distinguish between local and global variables, by default all variables are global
|
|
368
|
+
pass
|
|
405
369
|
|
|
406
370
|
elif token.type in [Token.KEYWORD, ROBOT_KEYWORD_INNER] or (
|
|
407
371
|
token.type == Token.NAME and cached_isinstance(node, Fixture, Template, TestTemplate)
|
|
@@ -507,7 +471,9 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
507
471
|
sem_mod.add(RobotSemTokenModifiers.BUILTIN)
|
|
508
472
|
|
|
509
473
|
if kw_doc is not None and kw_doc.is_embedded and kw_doc.matcher.embedded_arguments:
|
|
510
|
-
if get_robot_version() >= (
|
|
474
|
+
if get_robot_version() >= (7, 3):
|
|
475
|
+
m = kw_doc.matcher.embedded_arguments.name.fullmatch(kw)
|
|
476
|
+
elif get_robot_version() >= (6, 0):
|
|
511
477
|
m = kw_doc.matcher.embedded_arguments.match(kw)
|
|
512
478
|
else:
|
|
513
479
|
m = kw_doc.matcher.embedded_arguments.name.match(kw)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|