Repository: sublimelsp/LSP

Issue:
Could the result from AbstractPlugin.on_pre_start be stored in the session?
### Is your feature request related to a problem? Please describe.

The Julia server operates based on a Julia environment (like Python virtual environments) and it can use the working directory where it was started in, to determine the currently active environment. If no environement can be found, it falls back to a default environment.

Using the [LSP-julia](https://github.com/sublimelsp/LSP-julia) helper package, I would like to show the active environment in the status bar after the server initializes, and I currently have a workaround for that in https://github.com/sublimelsp/LSP-julia/blob/96dde4a3443f8bf45c45e9aa4e6afc92014e50e0/plugin.py#L100-L106, but it doesn't work in all cases (for example single file mode), because there is not enough information available in `AbstractPlugin.__init__`. I need access to the result from `on_pre_start`, but I can't save that result into an instance variable from a classmethod.


### Describe the solution you'd like

If the result from `on_pre_start` is stored in the session, it can be retrieved in `__init__`. I would need the exact result from `on_pre_start`, not the actual working directory (in case `None` is returned and there exists also a workspace folder). Maybe this is too specific for my usecase to be useful in general?


### Describe alternatives you've considered

(a) If the initiating view was also given to `__init__`, then I could alternatively execute the same logic from `on_pre_start` again.

(b) If all the methods from AbstractPlugin were instance methods instead of classmethods, and what is currently `__init__` would be another instance method `on_initialize`, then data could be exchanged between methods via instance variables.

(c) I also considered to save the result as a "hidden" setting to the view via `initiating_view.settings().set("_lsp_initial_environment", result_value)`, before returning from the `on_pre_start` function. And then in `__init__` I can iterate through all views to find the initiating view and retrieve the value:
<details>
  <summary>Click to expand</summary>

  ```python
      def __init__(self, weaksession) -> None:
          super().__init__(weaksession)
          if sublime.load_settings(SETTINGS_FILE).get("show_environment_status"):
              sublime.set_timeout_async(self.set_initial_environment_status_async)

      def set_initial_environment_status_async(self) -> None:
          session = self.weaksession()
          if session:
              for session_view in session.session_views_async():
                  env_path = session_view.view.settings().get("_lsp_initial_environment", False)
                  if env_path is not False:
                      env_name = os.path.basename(env_path) if env_path else JuliaLanguageServer.default_julia_environment()
                      session.set_window_status_async(STATUS_BAR_KEY, "Julia env: {}".format(env_name))
                      return
  ```
</details>

But it doesn't work; `session.session_views_async()` doesn't return any views there.

Perhaps someone sees why it isn't working or has an idea for a better solution?


Discussion:

Resolving patch:
diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py
--- a/plugin/core/sessions.py
+++ b/plugin/core/sessions.py
@@ -832,6 +832,7 @@ class Session(TransportCallbacks):
     def __init__(self, manager: Manager, logger: Logger, workspace_folders: List[WorkspaceFolder],
                  config: ClientConfig, plugin_class: Optional[Type[AbstractPlugin]]) -> None:
         self.transport = None  # type: Optional[Transport]
+        self.working_directory = None  # type: Optional[str]
         self.request_id = 0  # Our request IDs are always integers.
         self._logger = logger
         self._response_handlers = {}  # type: Dict[int, Tuple[Request, Callable, Optional[Callable[[Any], None]]]]
@@ -1050,8 +1051,15 @@ def update_folders(self, folders: List[WorkspaceFolder]) -> None:
         else:
             self._workspace_folders = folders[:1]
 
-    def initialize_async(self, variables: Dict[str, str], transport: Transport, init_callback: InitCallback) -> None:
+    def initialize_async(
+        self,
+        variables: Dict[str, str],
+        working_directory: Optional[str],
+        transport: Transport,
+        init_callback: InitCallback
+    ) -> None:
         self.transport = transport
+        self.working_directory = working_directory
         params = get_initialize_params(variables, self._workspace_folders, self.config)
         self._init_callback = init_callback
         self.send_request_async(
diff --git a/plugin/core/windows.py b/plugin/core/windows.py
--- a/plugin/core/windows.py
+++ b/plugin/core/windows.py
@@ -347,16 +347,21 @@ def start_async(self, config: ClientConfig, initiating_view: sublime.View) -> No
                 cwd = plugin_class.on_pre_start(self._window, initiating_view, workspace_folders, config)
             config.set_view_status(initiating_view, "starting...")
             session = Session(self, self._create_logger(config.name), workspace_folders, config, plugin_class)
-            if not cwd:
-                cwd = workspace_folders[0].path if workspace_folders else None
+            if cwd:
+                transport_cwd = cwd  # type: Optional[str]
+            else:
+                transport_cwd = workspace_folders[0].path if workspace_folders else None
             transport_config = config.resolve_transport_config(variables)
-            transport = create_transport(transport_config, cwd, session)
+            transport = create_transport(transport_config, transport_cwd, session)
             if plugin_class:
                 plugin_class.on_post_start(self._window, initiating_view, workspace_folders, config)
             config.set_view_status(initiating_view, "initialize")
             session.initialize_async(
-                variables, transport,
-                lambda session, is_error: self._on_post_session_initialize(initiating_view, session, is_error))
+                variables=variables,
+                transport=transport,
+                working_directory=cwd,
+                init_callback=functools.partial(self._on_post_session_initialize, initiating_view)
+            )
             self._new_session = session
         except Exception as e:
             message = "".join((


Test patch: