diff --git a/Default.sublime-keymap b/Default.sublime-keymap index edac87844..0c17f8203 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -174,7 +174,8 @@ // "args": { // "side_by_side": false, // "force_group": true, - // "fallback": false + // "fallback": false, + // "group": -1 // }, // "keys": [ // "f12" @@ -197,7 +198,8 @@ // "command": "lsp_symbol_type_definition", // "args": { // "side_by_side": false, - // "force_group": true + // "force_group": true, + // "group": -1 // }, // "keys": [ // "UNBOUND" @@ -220,7 +222,8 @@ // "command": "lsp_symbol_declaration", // "args": { // "side_by_side": false, - // "force_group": true + // "force_group": true, + // "group": -1 // }, // "keys": [ // "UNBOUND" @@ -243,7 +246,8 @@ // "command": "lsp_symbol_implementation", // "args": { // "side_by_side": false, - // "force_group": true + // "force_group": true, + // "group": -1 // }, // "keys": [ // "UNBOUND" diff --git a/docs/src/features.md b/docs/src/features.md index 73d1dc51e..545383ba1 100644 --- a/docs/src/features.md +++ b/docs/src/features.md @@ -34,6 +34,8 @@ In addition to the basic "Goto Definition", the protocol also provides further r Additionally, the LSP's "Goto Definition" command can fall back to the built-in Sublime's "Goto Definition" if the `fallback` argument is set to `true`. This way, when there are no results found the built-in "Goto Definition" command will be triggered. +To attempt to open the results in a certain group, you can use the `group` argument. If the specified `group` does not exist, then it will be ignored. + ## Find References [Example GIF 1](https://user-images.githubusercontent.com/6579999/128551752-b37fe407-148c-41cf-b1e4-6fe96ed0f77c.gif) diff --git a/plugin/core/open.py b/plugin/core/open.py index acec50673..1c3a179d1 100644 --- a/plugin/core/open.py +++ b/plugin/core/open.py @@ -15,6 +15,16 @@ opening_files = {} # type: Dict[str, Tuple[Promise[Optional[sublime.View]], ResolveFunc[Optional[sublime.View]]]] +def _return_existing_view(flags: int, existing_view_group: int, active_group: int, specified_group: int) -> bool: + if specified_group > -1: + return existing_view_group == specified_group + if bool(flags & (sublime.ADD_TO_SELECTION | sublime.REPLACE_MRU)): + return False + if existing_view_group == active_group: + return True + return not bool(flags & sublime.FORCE_GROUP) + + def open_file( window: sublime.Window, uri: DocumentUri, flags: int = 0, group: int = -1 ) -> Promise[Optional[sublime.View]]: @@ -27,13 +37,8 @@ def open_file( # window.open_file brings the file to focus if it's already opened, which we don't want (unless it's supposed # to open as a separate view). view = window.find_open_file(file) - if view: - opens_in_desired_group = not bool(flags & sublime.FORCE_GROUP) or \ - window.get_view_index(view)[0] == window.active_group() - opens_in_side_by_side = bool(flags & (sublime.ADD_TO_SELECTION | sublime.REPLACE_MRU)) - return_existing_view = opens_in_desired_group and not opens_in_side_by_side - if return_existing_view: - return Promise.resolve(view) + if view and _return_existing_view(flags, window.get_view_index(view)[0], window.active_group(), group): + return Promise.resolve(view) view = window.open_file(file, flags, group) if not view.is_loading(): diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index 12cbf4556..28647c062 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -1518,6 +1518,8 @@ def _open_uri_with_plugin_async( result = Promise.packaged_task() # type: PackagedTask[Optional[sublime.View]] def open_scratch_buffer(title: str, content: str, syntax: str) -> None: + if group > -1: + self.window.focus_group(group) v = self.window.new_file(syntax=syntax, flags=flags) # Note: the __init__ of ViewEventListeners is invoked in the next UI frame, so we can fill in the # settings object here at our leisure. diff --git a/plugin/goto.py b/plugin/goto.py index d6c974502..52743a779 100644 --- a/plugin/goto.py +++ b/plugin/goto.py @@ -23,7 +23,8 @@ def is_enabled( point: Optional[int] = None, side_by_side: bool = False, force_group: bool = True, - fallback: bool = False + fallback: bool = False, + group: int = -1 ) -> bool: return fallback or super().is_enabled(event, point) @@ -34,7 +35,8 @@ def run( point: Optional[int] = None, side_by_side: bool = False, force_group: bool = True, - fallback: bool = False + fallback: bool = False, + group: int = -1 ) -> None: session = self.best_session(self.capability) position = get_position(self.view, event, point) @@ -42,7 +44,11 @@ def run( params = text_document_position_params(self.view, position) request = Request(self.method, params, self.view, progress=True) session.send_request( - request, functools.partial(self._handle_response_async, session, side_by_side, force_group, fallback)) + request, + functools.partial( + self._handle_response_async, session, side_by_side, force_group, fallback, group + ), + ) else: self._handle_no_results(fallback, side_by_side) @@ -52,20 +58,23 @@ def _handle_response_async( side_by_side: bool, force_group: bool, fallback: bool, + group: int, response: Union[None, Location, List[Location], List[LocationLink]] ) -> None: if isinstance(response, dict): self.view.run_command("add_jump_record", {"selection": [(r.a, r.b) for r in self.view.sel()]}) - open_location_async(session, response, side_by_side, force_group) + open_location_async(session, response, side_by_side, force_group, group) elif isinstance(response, list): if len(response) == 0: self._handle_no_results(fallback, side_by_side) elif len(response) == 1: self.view.run_command("add_jump_record", {"selection": [(r.a, r.b) for r in self.view.sel()]}) - open_location_async(session, response[0], side_by_side, force_group) + open_location_async(session, response[0], side_by_side, force_group, group) else: self.view.run_command("add_jump_record", {"selection": [(r.a, r.b) for r in self.view.sel()]}) - sublime.set_timeout(functools.partial(LocationPicker, self.view, session, response, side_by_side)) + sublime.set_timeout( + functools.partial(LocationPicker, self.view, session, response, side_by_side, group) + ) else: self._handle_no_results(fallback, side_by_side) diff --git a/plugin/locationpicker.py b/plugin/locationpicker.py index dda13839c..213b56714 100644 --- a/plugin/locationpicker.py +++ b/plugin/locationpicker.py @@ -16,7 +16,8 @@ def open_location_async( session: Session, location: Union[Location, LocationLink], side_by_side: bool, - force_group: bool + force_group: bool, + group: int = -1 ) -> None: flags = sublime.ENCODED_POSITION if force_group: @@ -28,7 +29,7 @@ def check_success_async(view: Optional[sublime.View]) -> None: if not view: sublime.error_message("Unable to open URI") - session.open_location_async(location, flags).then(check_success_async) + session.open_location_async(location, flags, group).then(check_success_async) def open_basic_file( @@ -59,7 +60,8 @@ def __init__( view: sublime.View, session: Session, locations: Union[List[Location], List[LocationLink]], - side_by_side: bool + side_by_side: bool, + group: int = -1 ) -> None: self._view = view self._view_states = ([r.to_tuple() for r in view.sel()], view.viewport_position()) @@ -69,10 +71,12 @@ def __init__( self._window = window self._weaksession = weakref.ref(session) self._side_by_side = side_by_side + self._group = group self._items = locations self._highlighted_view = None # type: Optional[sublime.View] manager = session.manager() base_dir = manager.get_project_path(view.file_name() or "") if manager else None + self._window.focus_group(group) self._window.show_quick_panel( items=[location_to_human_readable(session.config, base_dir, location) for location in locations], on_select=self._select_entry, @@ -103,9 +107,15 @@ def _select_entry(self, index: int) -> None: self._window.status_message("Unable to open {}".format(uri)) else: sublime.set_timeout_async( - functools.partial(open_location_async, session, location, self._side_by_side, True)) + functools.partial(open_location_async, session, location, self._side_by_side, True, self._group)) else: self._window.focus_view(self._view) + # When a group was specified close the current highlighted + # sheet upon canceling if the sheet is transient + if self._group > -1 and self._highlighted_view: + sheet = self._highlighted_view.sheet() + if sheet and sheet.is_transient(): + self._highlighted_view.close() # When in side-by-side mode close the current highlighted # sheet upon canceling if the sheet is semi-transient if self._side_by_side and self._highlighted_view: