def m_text_document__hover(self, **kwargs): """ When hovering over a png in base64 surrounded by double-quotes... something as: "iVBORw0KGgo...rest of png in base 64 contents..." i.e.: Provide the contents in markdown format to show the actual image from the locators.json. """ from robocorp_ls_core import uris from robocorp_ls_core.protocols import IDocument from robocorp_ls_core.protocols import IDocumentSelection from robocorp_ls_core.lsp import Range from robocorp_ls_core.lsp import MarkupKind from robocorp_ls_core.lsp import MarkupContent doc_uri = kwargs["textDocument"]["uri"] # Note: 0-based line: int = kwargs["position"]["line"] col: int = kwargs["position"]["character"] if not uris.to_fs_path(doc_uri).endswith("locators.json"): return None document: IDocument = self._workspace.get_document( doc_uri, accept_from_file=True) sel: IDocumentSelection = document.selection(line, col) current_line: str = sel.current_line i: int = current_line.find( '"iVBORw0KGgo' ) # I.e.: pngs in base64 always start with this prefix. if i >= 0: current_line = current_line[i + 1:] i = current_line.find('"') if i >= 0: current_line = current_line[0:i] image_path = f"data:image/png;base64,{current_line}" s = f"![Screenshot]({image_path})" return { "contents": MarkupContent(MarkupKind.Markdown, s).to_dict(), "range": Range((line, col), (line, col)).to_dict(), } # Could not find a base-64 img embedded, let's see if we have an element # with a relative path. import re p = Path(document.path).parent for found in re.findall('"(.+?)"', current_line): if found.endswith(".png"): check = p / found if check.exists(): as_uri = uris.from_fs_path(str(check)) s = f"![Screenshot]({as_uri})" return { "contents": MarkupContent(MarkupKind.Markdown, s).to_dict(), "range": Range((line, col), (line, col)).to_dict(), } return None
def visit_TestCase(self, node: TestCase): self.code_lens.append( CodeLens( Range(Position(node.header.lineno - 1, node.header.col_offset), Position(node.header.lineno - 1, node.header.col_offset)), Command("Run Test", "robot.runTestcase", [self.doc_uri, node.name]))) self.code_lens.append( CodeLens( Range(Position(node.header.lineno - 1, node.header.col_offset), Position(node.header.lineno - 1, node.header.col_offset)), Command("Debug Test", "robot.debugTestcase", [self.doc_uri, node.name])))
def code_lens(completion_context: ICompletionContext, doc_uri: str) -> Optional[List[Dict]]: result = [] result.append( CodeLens(Range(Position(0, 0), Position(0, 0)), Command("Run Suite", "robot.runTestsuite", [doc_uri]))) result.append( CodeLens(Range(Position(0, 0), Position(0, 0)), Command("Debug Suite", "robot.debugTestsuite", [doc_uri]))) result += CodeLensVisitor.find_from(completion_context.get_ast(), doc_uri, completion_context) return list([x.to_dict() for x in result])
def complete(completion_context): """ :param CompletionContext completion_context: """ from robocorp_ls_core.lsp import CompletionItemKind from robocorp_ls_core.lsp import CompletionItem from robocorp_ls_core.lsp import TextEdit from robocorp_ls_core.lsp import Range from robocorp_ls_core.lsp import Position from robotframework_ls.impl import text_utilities from robotframework_ls.impl.string_matcher import RobotStringMatcher from robotframework_ls.impl.robot_lsp_constants import ( OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM, ) from robotframework_ls.impl.robot_lsp_constants import ( OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM_PLURAL, ) selection = completion_context.sel #: :type selection: DocumentSelection line_start = selection.line_to_column items = [] if line_start: tu = text_utilities.TextUtilities(line_start) if tu.strip_leading_chars("*"): # i.e.: the line must start with '*' tu.strip() words = completion_context.get_accepted_section_header_words() config = completion_context.config form = config.get_setting( OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM, str, OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM_PLURAL, ) matcher = RobotStringMatcher(tu.text) for word in words: if form == "plural": if not word.endswith("s"): continue elif form == "singular": if word.endswith("s"): continue if matcher.accepts(word): label = "*** %s ***" % (word, ) text_edit = TextEdit( Range( # i.e.: always replace from the start of the line. start=Position(selection.line, 0), end=Position(selection.line, selection.col), ), label, ) # text_edit = None items.append( CompletionItem(label, kind=CompletionItemKind.Class, text_edit=text_edit, insertText=text_edit.newText)) return [item.to_dict() for item in items]
def _create_completion_item( label: str, new_text: str, selection: IDocumentSelection, col_start: int, col_end: int, documentation: str, ) -> dict: from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robocorp_ls_core.lsp import CompletionItemKind text_edit = TextEdit( Range( start=Position(selection.line, col_start), end=Position(selection.line, col_end), ), new_text, ) return CompletionItem( label, kind=CompletionItemKind.Field, text_edit=text_edit, insertText=label, documentation=documentation, insertTextFormat=InsertTextFormat.PlainText, documentationFormat=MarkupKind.PlainText, ).to_dict()
def test_document_multiline_edit(): old = ["def hello(a, b):\n", " print a\n", " print b\n"] doc = Document("file:///uri", u"".join(old)) change = TextDocumentContentChangeEvent( Range(Position(1, 4), Position(2, 11)), 0, u"print a, b") doc.apply_change(change) assert doc.get_internal_lines() == ("def hello(a, b):\n", " print a, b\n")
def test_document_end_of_file_edit(): old = ["print 'a'\n", "print 'b'\n"] doc = Document("file:///uri", u"".join(old)) change = TextDocumentContentChangeEvent( Range(Position(2, 0), Position(2, 0)), 0, u"o") doc.apply_change(change) assert doc.get_internal_lines() == ("print 'a'\n", "print 'b'\n", "o")
def _create_completion_item_from_keyword(self, keyword_found: IKeywordFound, selection, token, col_delta=0): from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robotframework_ls.impl.protocols import IKeywordArg label = keyword_found.keyword_name if keyword_found.library_name: # If we found the keyword in a library, convert its format depending on # the user configuration. label = self._convert_keyword_format(label) text = label arg: IKeywordArg for i, arg in enumerate(keyword_found.keyword_args): if arg.is_keyword_arg or arg.is_star_arg or arg.default_value is not None: continue arg_name = arg.arg_name arg_name = arg_name.replace("$", "\\$").replace("{", "").replace("}", "") text += " ${%s:%s}" % (i + 1, arg_name) text_edit = TextEdit( Range( start=Position(selection.line, token.col_offset + col_delta), end=Position(selection.line, token.end_col_offset), ), text, ) # text_edit = None return CompletionItem( label, kind=keyword_found.completion_item_kind, text_edit=text_edit, insertText=text_edit.newText, documentation=keyword_found.docs, insertTextFormat=InsertTextFormat.Snippet, documentationFormat=(MarkupKind.Markdown if keyword_found.docs_format == "markdown" else MarkupKind.PlainText), ).to_dict()
def _create_completion_item_from_keyword(self, keyword_found: IKeywordFound, selection, token, col_delta=0): from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robotframework_ls.impl.robot_specbuilder import KeywordArg label = keyword_found.keyword_name text = label arg: KeywordArg for i, arg in enumerate(keyword_found.keyword_args): if arg.is_keyword_arg or arg.is_star_arg or arg.default_value is not None: continue arg_name = arg.arg_name arg_name = arg_name.replace("$", "\\$").replace("{", "").replace("}", "") text += " ${%s:%s}" % (i + 1, arg_name) text_edit = TextEdit( Range( start=Position( selection.line, token.col_offset + col_delta if token is not None else selection.col), end=Position( selection.line, token.end_col_offset if token is not None else selection.col), ), text, ) # text_edit = None return CompletionItem( keyword_found.keyword_name, kind=keyword_found.completion_item_kind, text_edit=text_edit, insertText=text_edit.newText, documentation=keyword_found.docs, insertTextFormat=InsertTextFormat.Snippet, documentationFormat=(MarkupKind.Markdown if keyword_found.docs_format == "markdown" else MarkupKind.PlainText), )
def _threaded_find_definition(self, doc_uri, line, col, monitor) -> Optional[list]: from robotframework_ls.impl.find_definition import find_definition import os.path from robocorp_ls_core.lsp import Location, Range from robocorp_ls_core import uris completion_context = self._create_completion_context( doc_uri, line, col, monitor ) if completion_context is None: return None definitions = find_definition(completion_context) ret = [] for definition in definitions: if not definition.source: log.info("Found definition with empty source (%s).", definition) continue if not os.path.exists(definition.source): log.info( "Found definition: %s (but source does not exist).", definition ) continue lineno = definition.lineno if lineno is None or lineno < 0: lineno = 0 end_lineno = definition.end_lineno if end_lineno is None or end_lineno < 0: end_lineno = 0 col_offset = definition.col_offset end_col_offset = definition.end_col_offset ret.append( Location( uris.from_fs_path(definition.source), Range((lineno, col_offset), (end_lineno, end_col_offset)), ).to_dict() ) return ret
def _create_completion_item_from_variable(self, variable_found, selection, token): """ :param IVariableFound variable_found: :param selection: :param token: """ from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robocorp_ls_core.lsp import CompletionItemKind label = variable_found.variable_name text = label text = text.replace("$", "\\$") text_edit = TextEdit( Range( start=Position(selection.line, token.col_offset), end=Position(selection.line, token.end_col_offset), ), text, ) # text_edit = None return CompletionItem( variable_found.variable_name, kind=CompletionItemKind.Variable, text_edit=text_edit, insertText=label, documentation=variable_found.variable_value, insertTextFormat=InsertTextFormat.Snippet, documentationFormat=MarkupKind.PlainText, ).to_dict()
def _create_completion_item_from_snippet(label, snippet, selection, line_to_col): """ :param selection: DocumentSelection """ from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robocorp_ls_core.lsp import CompletionItemKind current_col = selection.col text = "\n".join(snippet["body"]) text_edit = TextEdit( Range( start=Position(selection.line, current_col - len(line_to_col)), end=Position(selection.line, current_col), ), text, ) return CompletionItem( label, kind=CompletionItemKind.Snippet, text_edit=text_edit, insertText=text_edit.newText, documentation=snippet["description"] + "\n".join(["", ""] + snippet["body"]), insertTextFormat=InsertTextFormat.Snippet, documentationFormat=MarkupKind.Markdown, ).to_dict()
def _create_completion_item(library_name, selection, token, start_col_offset=None): from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robocorp_ls_core.lsp import CompletionItemKind text_edit = TextEdit( Range( start=Position( selection.line, start_col_offset if start_col_offset is not None else token.col_offset, ), end=Position(selection.line, token.end_col_offset), ), library_name, ) # text_edit = None return CompletionItem( library_name, kind=CompletionItemKind.Module, text_edit=text_edit, insertText=text_edit.newText, documentation="", insertTextFormat=InsertTextFormat.Snippet, documentationFormat=MarkupKind.PlainText, ).to_dict()
def test_document_empty_edit(): doc = Document("file:///uri", u"") change = TextDocumentContentChangeEvent( Range(Position(0, 0), Position(0, 0)), 0, u"f") doc.apply_change(change) assert doc.source == u"f"
def create_completion_item( self, completion_context: ICompletionContext, keyword_name, selection, token, col_delta: int, memo: Set[str], lib_import: Optional[str] = None, resource_path: Optional[str] = None, data: Optional[Any] = None, ) -> None: """ Note: the lib_import and resource_path are the strings to be added so that the given library/resource is loaded. i.e.: It's the name concatenated to the `Library {lib_import}` or `Resource {resource_path}`. """ from robocorp_ls_core.lsp import ( CompletionItem, InsertTextFormat, Position, Range, TextEdit, ) from robocorp_ls_core.lsp import MarkupKind from robotframework_ls.impl.protocols import CompletionType label = f"{keyword_name} ({lib_import or resource_path})" if label in memo: return memo.add(label) prefix = "" import_line = -1 if completion_context.type != CompletionType.shell: if lib_import is not None: import_line = self.import_location_info.get_library_import_line( ) elif resource_path is not None: import_line = self.import_location_info.get_resource_import_line( ) if import_line == -1: # There's no existing import, so, let's see if we have a *** Settings *** section. # If we don't we have to create the whole settings, otherwise, we'll add the statement # as the first thing in the existing *** Settings *** section. if completion_context.type == CompletionType.shell: import_line = 0 prefix = "*** Settings ***\n" elif self.import_location_info.setting_section_node_info is None: import_line = 0 prefix = "*** Settings ***\n" else: import_line = (self.import_location_info. setting_section_node_info.node.end_lineno - 1) text = keyword_name if keyword_name in self.imported_keyword_name_to_keyword: check = lib_import or resource_path if check: basename = os.path.basename(check) if basename.endswith((".txt", ".py", ".robot", ".resource")): basename = os.path.splitext(basename)[0] text = f"{basename}.{keyword_name}" text_edit = TextEdit( Range( start=Position(selection.line, token.col_offset + col_delta), end=Position(selection.line, token.end_col_offset), ), text, ) additional_text_edits: List[TextEdit] = [] if lib_import is not None: additional_text_edits.append( TextEdit( Range(start=Position(import_line, 0), end=Position(import_line, 0)), f"{prefix}Library {lib_import}\n", )) elif resource_path is not None: additional_text_edits.append( TextEdit( Range(start=Position(import_line, 0), end=Position(import_line, 0)), f"{prefix}Resource {resource_path}\n", )) # text_edit = None self.completion_items.append( CompletionItem( label, kind=CompletionItemKind.Reference, text_edit=text_edit, insertText=text_edit.newText, documentation="", insertTextFormat=InsertTextFormat.Snippet, documentationFormat=MarkupKind.PlainText, additionalTextEdits=additional_text_edits, data=data, ).to_dict())
def _create_range(d, offset1, offset2): from robocorp_ls_core.lsp import Range return Range(d.offset_to_line_col(offset1), d.offset_to_line_col(offset2))
def complete(completion_context): """ :param CompletionContext completion_context: """ import itertools from robocorp_ls_core.lsp import ( TextEdit, Range, Position, CompletionItem, CompletionItemKind, ) section_name = completion_context.get_current_section_name() if section_name: from robotframework_ls.impl.string_matcher import RobotStringMatcher section = completion_context.get_section(section_name) if section is not None: selection = completion_context.sel #: :type selection: DocumentSelection line_to_col = selection.line_to_column if line_to_col.endswith(" "): return [] replace_to_col = selection.col if section.names_in_brackets: for i, c in enumerate(line_to_col): if c.isspace(): continue elif c == "[": line_to_col = line_to_col[i + 1:] replace_from_col = i break else: return [] else: return [] matcher = RobotStringMatcher(line_to_col) else: # i.e.: Needs to be the first char matcher = RobotStringMatcher(line_to_col) replace_from_col = 0 ret = [] for word in sorted(itertools.chain(section.names, section.aliases)): if matcher.accepts(word): if section.names_in_brackets: label = "[%s]" % (word, ) line = selection.current_line replacement = "[%s]" % (word, ) if line[selection.col:].startswith("]"): replace_to_col += 1 else: label = word replacement = word text_edit = TextEdit( Range( start=Position(selection.line, replace_from_col), end=Position(selection.line, replace_to_col), ), replacement, ) # text_edit = None ret.append( CompletionItem(label, kind=CompletionItemKind.Keyword, text_edit=text_edit).to_dict()) return ret return []
def test_document_line_edit(): doc = Document("file:///uri", u"itshelloworld") change = TextDocumentContentChangeEvent( Range(Position(0, 3), Position(0, 8)), 0, u"goodbye") doc.apply_change(change) assert doc.source == u"itsgoodbyeworld"