def _get_enclosing_entity(self, curloc): """ Return the entity that encloses the current cursor """ buf = GPS.EditorBuffer.get(curloc.file(), open=False) if buf is not None: edloc = buf.at(curloc.line(), curloc.column()) (start_loc, end_loc) = self._get_enclosing_block(edloc) else: return None, None, None if not start_loc: return None, None, None name = edloc.subprogram_name() # FIXME: not right. # [entity_bounds] returns the beginning of the col/line of the # definition/declaration. To be able to call GPS.Entity, we need to be # closer to the actual subprogram name. We get closer by skipping the # keyword that introduces the subprogram (procedure/function/entry etc.) id_loc = start_loc id_loc = id_loc.forward_word(1) try: return GPS.Entity(name, id_loc.buffer().file(), id_loc.line(), id_loc.column()), start_loc, end_loc except: return None, None, None
def compute_subp_sloc(self): """Return the location of the declaration of the subprogram that we are currently in""" try: curloc = self.location() buf = GPS.EditorBuffer.get(curloc.file(), open=False) if buf is not None: edloc = buf.at(curloc.line(), curloc.column()) start_loc = subprogram_start(edloc) else: return None except Exception: return None if not start_loc: return None name = edloc.subprogram_name() # [subprogram_start] returns the beginning of the line of the # definition/declaration. To be able to call GPS.Entity, we need to be # closer to the actual subprogram name. We get closer by skipping the # keyword that introduces the subprogram (procedure/function/entry etc.) start_loc = start_loc.forward_word(1) try: entity = GPS.Entity(name, start_loc.buffer().file(), start_loc.line(), start_loc.column()) except Exception: return None if entity is not None: return entity.declaration() else: return None
def entity(self): """ Returns a :class:`GPS.Entity` instance at the given location. If there is no entity that can be resolved at this location, returns None :rtype: :class:`GPS.Entity` """ try: word, start_loc, end_loc = self.get_word() return GPS.Entity(word, self.buffer().file(), start_loc.line(), start_loc.column()) except Exception: return None
def inside_generic_unit_context(self): """Return True if the context is inside a generic unit""" try: curloc = self.location() buf = GPS.EditorBuffer.get(curloc.file(), open=False) if buf is not None: start_loc = buf.at(1, 1) unit_loc, _ = start_loc.search('package|function|procedure', regexp=True, whole_word=True, dialog_on_failure=False) if unit_loc is None: return False # reach the start of the next word. We need to forward 2 words and # backward 1 in order to get the cursor at the start of the next # word instead of the end of the current word with forward 1. unit_loc = unit_loc.forward_word(2) unit_loc = unit_loc.forward_word(-1) tok, _, _ = unit_loc.get_word() if tok == 'body': # reach the start of the next word unit_loc = unit_loc.forward_word(2) unit_loc = unit_loc.forward_word(-1) name, _, _ = unit_loc.get_word() try: entity = GPS.Entity(name, unit_loc.buffer().file(), unit_loc.line(), unit_loc.column()) except Exception: return False return entity.is_generic() else: return False except Exception: return False
def mc_all_entity_references(): def get_word_bounds(loc): loc_id_start = goto_word_start(loc) loc_id_end = goto_word_end(loc) # Check the case when we are at the end of a word if not id_pattern.match(loc.get_char()): ploc = loc.forward_char(-1) # If we are really not in an identifier, exit if not id_pattern.match(ploc.get_char()): return None, None else: loc_id_end = ploc return loc_id_start, loc_id_end editor = GPS.EditorBuffer.get() marks = [] loc = editor.current_view().cursor() loc_id_start, loc_id_end = get_word_bounds(loc) if not loc_id_start or not loc_id_end: return identifier = editor.get_chars(loc_id_start, loc_id_end) try: entity = GPS.Entity(identifier, editor.file(), loc_id_start.line(), loc_id_start.column()) except GPS.Exception: return overlay = editor.create_overlay("entityrefs_overlay") overlay.set_property("background", mc_on_entity_color.get()) def loc_tuple(loc): return loc.line(), loc.column() mark_start = loc_id_start.create_mark() mark_end = loc_id_end.forward_char().create_mark(left_gravity=False) def apply_overlay(editor, mark_start, mark_end, overlay): """ Apply overlay overlay between mark_start and mark end if mark_start - mark_end >= 1 char """ lstart = mark_start.location() lend = mark_end.location().forward_char(-1) if lend >= lstart: editor.apply_overlay(overlay, lstart, lend) # noinspection PyUnusedLocal def on_edit(hook_name, file_name): """ Event handler on insert/delete. Mainly ensures that the current field in alias expansion is highlighted (via the aliases overlay) """ if editor == GPS.EditorBuffer.get(file_name): editor.remove_overlay(overlay, editor.beginning_of_buffer(), editor.end_of_buffer()) for mark_start, mark_end in marks: apply_overlay(editor, mark_start, mark_end, overlay) # noinspection PyUnusedLocal def on_move(hook_name, file_name, line, column): """ Event handler on cursor move. Gets out of alias expansion mode when the cursor gets out of the zone. """ start_loc = mark_start.location() end_loc = mark_end.location() cursor_loc = editor.current_view().cursor() if not (start_loc <= cursor_loc <= end_loc): exit_alias_expansion() def exit_alias_expansion(): editor.remove_overlay(overlay, editor.beginning_of_buffer(), editor.end_of_buffer()) editor.remove_all_slave_cursors() GPS.Hook("character_added").remove(on_edit) GPS.Hook("location_changed").remove(on_move) marks.append((mark_start, mark_end)) apply_overlay(editor, mark_start, mark_end, overlay) cursor_loc_t = loc_tuple(loc) word_offset = loc.column() - loc_id_start.column() locs = [ editor.at(floc.line(), floc.column()) for floc in entity.references() if floc.file() == editor.file() ] locs_set = set() for s_loc in locs: loc = s_loc.forward_char(word_offset) loc_t = loc_tuple(loc) if not (loc_t in locs_set or loc_t == cursor_loc_t): locs_set.add(loc_t) s, e = get_word_bounds(loc) ms = s.create_mark() me = e.forward_char().create_mark(left_gravity=False) marks.append((ms, me)) apply_overlay(editor, ms, me, overlay) editor.add_cursor(loc) GPS.Hook("character_added").add(on_edit) GPS.Hook("location_changed").add(on_move)
def mc_all_entity_references(): def get_word_bounds(loc): loc_id_start = goto_word_start(loc) loc_id_end = goto_word_end(loc) # Check the case when we are at the end of a word if not id_pattern.match(loc.get_char()): ploc = loc.forward_char(-1) # If we are really not in an identifier, exit if not id_pattern.match(ploc.get_char()): return None, None else: loc_id_end = ploc return loc_id_start, loc_id_end editor = GPS.EditorBuffer.get() marks = [] loc = editor.current_view().cursor() loc_id_start, loc_id_end = get_word_bounds(loc) if not loc_id_start or not loc_id_end: return identifier = editor.get_chars(loc_id_start, loc_id_end) # Get the references for the current entity using the ALS # in priority. Fallback to the old xref engine when the # the request gets rejected. als = GPS.LanguageServer.get_by_language_name("Ada") params = {"textDocument": {"uri": editor.file().uri}, "position": {"line": loc_id_start.line() - 1, "character": loc_id_start.column() - 1}, "context": {"includeDeclaration": True}} result = yield als.request_promise("textDocument/references", params) yield hook('language_server_response_processed') if result.is_valid: locs = [editor.at(lsp_loc['range']['end']['line'] + 1, lsp_loc['range']['end']['character']) for lsp_loc in result.data if lsp_loc['uri'] == editor.file().uri] elif result.is_reject: try: entity = GPS.Entity( identifier, editor.file(), loc_id_start.line(), loc_id_start.column()) locs = [editor.at(floc.line(), floc.column()) for floc in entity.references() if floc.file() == editor.file()] except GPS.Exception: return else: return overlay = editor.create_overlay("entityrefs_overlay") overlay.set_property( "background", mc_on_entity_color.get() ) def loc_tuple(loc): return loc.line(), loc.column() mark_start = loc_id_start.create_mark() mark_end = loc_id_end.forward_char().create_mark(left_gravity=False) def apply_overlay(editor, mark_start, mark_end, overlay): """ Apply overlay overlay between mark_start and mark end if mark_start - mark_end >= 1 char """ lstart = mark_start.location() lend = mark_end.location().forward_char(-1) if lend >= lstart: editor.apply_overlay(overlay, lstart, lend) # noinspection PyUnusedLocal def on_edit(hook_name, file_name): """ Event handler on insert/delete. Mainly ensures that the current field in alias expansion is highlighted (via the aliases overlay) """ if editor == GPS.EditorBuffer.get(file_name): editor.remove_overlay( overlay, editor.beginning_of_buffer(), editor.end_of_buffer() ) for mark_start, mark_end in marks: apply_overlay(editor, mark_start, mark_end, overlay) # noinspection PyUnusedLocal def on_move(hook_name, file_name, line, column): """ Event handler on cursor move. Gets out of alias expansion mode when the cursor gets out of the zone. """ start_loc = mark_start.location() end_loc = mark_end.location() cursor_loc = editor.current_view().cursor() if not (start_loc <= cursor_loc <= end_loc): exit_alias_expansion() def exit_alias_expansion(): editor.remove_overlay( overlay, editor.beginning_of_buffer(), editor.end_of_buffer() ) editor.remove_all_slave_cursors() GPS.Hook("character_added").remove(on_edit) GPS.Hook("location_changed").remove(on_move) marks.append((mark_start, mark_end)) apply_overlay(editor, mark_start, mark_end, overlay) cursor_loc_t = loc_tuple(loc) word_offset = loc.column() - loc_id_start.column() locs_set = set() for s_loc in locs: loc = s_loc.forward_char(word_offset) loc_t = loc_tuple(loc) if not (loc_t in locs_set or loc_t == cursor_loc_t): locs_set.add(loc_t) s, e = get_word_bounds(loc) ms = s.create_mark() me = e.forward_char().create_mark(left_gravity=False) marks.append((ms, me)) apply_overlay(editor, ms, me, overlay) editor.add_cursor(loc) GPS.Hook("character_added").add(on_edit) GPS.Hook("location_changed").add(on_move)