Exemplo n.º 1
0
class LspIntelephensePlugin(NpmClientHandler):
    package_name = __package__.split(".")[0]
    server_directory = "language-server"
    server_binary_path = os.path.join(server_directory, "node_modules",
                                      "intelephense", "lib", "intelephense.js")

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        self._activity_indicator = None  # type: Optional[ActivityIndicator]

    @classmethod
    def get_additional_variables(cls) -> Optional[Dict[str, str]]:
        variables = super().get_additional_variables() or {}
        variables.update({
            "cache_path": sublime.cache_path(),
            "home": os.path.expanduser("~"),
            "package_storage": cls.package_storage(),
            "temp_dir": tempfile.gettempdir(),
        })

        return variables

    @classmethod
    def minimum_node_version(cls) -> Tuple[int, int, int]:
        return (10, 0, 0)

    # ---------------- #
    # message handlers #
    # ---------------- #

    @notification_handler("indexingStarted")
    def handle_indexing_started(self, params: None) -> None:
        self._start_indicator("{}: Indexing...".format(self.package_name))

    @notification_handler("indexingEnded")
    def handle_indexing_ended(self, params: None) -> None:
        self._stop_indicator()

    # -------------- #
    # custom methods #
    # -------------- #

    def _start_indicator(self, msg: str = "") -> None:
        if self._activity_indicator:
            self._activity_indicator.label = msg
        else:
            view = sublime.active_window().active_view()
            if view:
                self._activity_indicator = ActivityIndicator(view, msg)
                self._activity_indicator.start()

    def _stop_indicator(self) -> None:
        if self._activity_indicator:
            self._activity_indicator.stop()
            self._activity_indicator = None
Exemplo n.º 2
0
    def test_start_stop(self):
        target = Mock()
        indicator = ActivityIndicator(target)

        indicator.start()
        target.set.assert_called_once_with('[=          ]')
        target.set.reset_mock()

        indicator.stop()
        target.clear.assert_called_once_with()

        indicator.start()
        target.set.assert_called_once_with('[=          ]')

        indicator.stop()
class ServerNpmResource(object):
    """Global object providing paths to server resources.
    Also handles the installing and updating of the server in cache.

    setup() needs to be called during (or after) plugin_loaded() for paths to be valid.
    """
    def __init__(self, package_name, server_directory, server_binary_path):
        self._initialized = False
        self._is_ready = False
        self._package_name = package_name
        self._server_directory = server_directory
        self._binary_path = server_binary_path
        self._package_cache_path = None
        self._activity_indicator = None

    @property
    def ready(self):
        return self._is_ready

    @property
    def binary_path(self):
        return os.path.join(self._package_cache_path, self._binary_path)

    def setup(self):
        if self._initialized:
            return

        self._initialized = True
        self._package_cache_path = os.path.join(sublime.cache_path(),
                                                self._package_name)

        self._copy_to_cache()

    def cleanup(self):
        if os.path.isdir(self._package_cache_path):
            shutil.rmtree(self._package_cache_path)

    def _copy_to_cache(self):
        src_path = 'Packages/{}/{}/'.format(self._package_name,
                                            self._server_directory)
        dst_path = 'Cache/{}/{}/'.format(self._package_name,
                                         self._server_directory)
        cache_server_path = os.path.join(self._package_cache_path,
                                         self._server_directory)

        if os.path.isdir(cache_server_path):
            # Server already in cache. Check if version has changed and if so, delete existing copy in cache.
            try:
                src_package_json = ResourcePath(src_path,
                                                'package.json').read_text()
                dst_package_json = ResourcePath(dst_path,
                                                'package.json').read_text()

                if src_package_json != dst_package_json:
                    shutil.rmtree(cache_server_path)
            except FileNotFoundError:
                shutil.rmtree(cache_server_path)

        if not os.path.isdir(cache_server_path):
            # create cache folder
            ResourcePath(src_path).copytree(cache_server_path, exist_ok=True)

        self._install_dependencies(cache_server_path)

    def _install_dependencies(self, cache_server_path):
        dependencies_installed = os.path.isdir(
            os.path.join(cache_server_path, 'node_modules'))

        if dependencies_installed:
            self._is_ready = True
            return

        # this will be called only when the plugin gets:
        # - installed for the first time,
        # - or when updated on package control
        install_message = '{}: Installing server'.format(self._package_name)
        log_and_show_message(install_message, show_in_status=False)

        active_window = sublime.active_window()
        if active_window:
            self._activity_indicator = ActivityIndicator(
                active_window.active_view(), install_message)
            self._activity_indicator.start()

        run_command(self._on_install_success, self._on_install_error, [
            "npm", "install", "--verbose", "--production", "--prefix",
            cache_server_path, cache_server_path
        ])

    def _on_install_success(self):
        self._is_ready = True
        self._stop_indicator()
        log_and_show_message(
            '{}: Server installed. Supported files might need to be re-opened.'
            .format(self._package_name))

    def _on_install_error(self, error):
        self._stop_indicator()
        log_and_show_message(
            '{}: Error while installing the server.'.format(
                self._package_name), error)

    def _stop_indicator(self):
        if self._activity_indicator:
            self._activity_indicator.stop()
            self._activity_indicator = None
Exemplo n.º 4
0
class ClangFormatCommand(sublime_plugin.TextCommand):
    def __init__(self, view):
        super().__init__(view)
        self._indicator = None

    def run(self, edit, only_selection=True):
        settings = sublime.load_settings(settings_filename())
        binary_path = settings.get(PREF_CLANG_FORMAT_PATH)
        if not binary_path:
            binary_path = which(binary_name())
            if not binary_path or not is_exe(binary_path):
                sublime.message_dialog(MISSING_BINARY_MESSAGE % binary_name())
                return

        args = [binary_path, '-fallback-style', style]
        if self.view.file_name():
            args.extend(['-assume-filename', self.view.file_name()])
        else:
            print(
                'Checking style without knowing file type. Results might be innacurate!'
            )

        if only_selection:
            for region in self.view.sel():
                region_offset = min(region.a, region.b)
                region_length = abs(region.b - region.a)
                args.extend([
                    '-offset',
                    str(region_offset), '-length',
                    str(region_length)
                ])

        buffer_text = self.view.substr(sublime.Region(0, self.view.size()))
        encoding = self.view.encoding()
        encoding = encoding if encoding != 'Undefined' else 'utf-8'
        stdin = buffer_text.encode(encoding)
        viewport_pos = self.view.viewport_position()
        # Show progress indicator if formatting takes longer than 1s.
        self._indicator = ActivityIndicator(self.view,
                                            'ClangFormat: Formatting...')
        sublime.set_timeout(self.start_indicator, 1000)

        start_thread(
            lambda output: self.on_formatting_success(
                viewport_pos, output, encoding), self.on_formatting_error,
            args, stdin)

    def on_formatting_success(self, viewport_pos, output, encoding):
        self.stop_indicator()
        self.view.run_command('clang_format_apply', {
            'output': output.decode(encoding),
            'viewport_pos': viewport_pos,
        })

    def on_formatting_error(self, error):
        self.stop_indicator()
        self.view.window().status_message('ClangFormat: Formatting error: %s' %
                                          error)

    def start_indicator(self):
        if self._indicator:
            self._indicator.start()

    def stop_indicator(self):
        if self._indicator:
            self._indicator.stop()
            self._indicator = None
Exemplo n.º 5
0
class LspPyrightPlugin(NpmClientHandler):
    package_name = __package__.split(".")[0]
    server_directory = "language-server"
    server_binary_path = os.path.join(server_directory, "node_modules",
                                      "pyright", "langserver.index.js")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._activity_indicator = None  # type: Optional[ActivityIndicator]

    @classmethod
    def install_in_cache(cls) -> bool:
        return False

    @classmethod
    def minimum_node_version(cls) -> Tuple[int, int, int]:
        return (12, 0, 0)

    def on_settings_changed(self, settings: DottedDict) -> None:
        super().on_settings_changed(settings)

        if self.get_plugin_setting("dev_environment") == "sublime_text":
            # add package dependencies into "python.analysis.extraPaths"
            extraPaths = settings.get("python.analysis.extraPaths") or [
            ]  # type: List[str]
            extraPaths.extend(self.find_package_dependency_dirs())
            settings.set("python.analysis.extraPaths", extraPaths)

    # ---------------- #
    # message handlers #
    # ---------------- #

    @notification_handler("pyright/beginProgress")
    def handle_begin_progress(self, params) -> None:
        # we don't know why we begin this progress
        # the reason will be updated in "pyright/reportProgress"
        self._start_indicator("{}: Working...".format(self.package_name))

    @notification_handler("pyright/endProgress")
    def handle_end_progress(self, params) -> None:
        self._stop_indicator()

    @notification_handler("pyright/reportProgress")
    def handle_report_progress(self, params: List[str]) -> None:
        self._start_indicator("{}: {}".format(self.package_name,
                                              "; ".join(params)))

    # -------------- #
    # custom methods #
    # -------------- #

    @classmethod
    def get_plugin_setting(cls,
                           key: str,
                           default: Optional[Any] = None) -> Any:
        return sublime.load_settings(cls.package_name +
                                     ".sublime-settings").get(key, default)

    @staticmethod
    def find_package_dependency_dirs() -> List[str]:
        dep_dirs = sys.path.copy()

        # move the "Packages/" to the last
        # @see https://github.com/sublimelsp/LSP-pyright/pull/26#discussion_r520747708
        packages_path = sublime.packages_path()
        dep_dirs.remove(packages_path)
        dep_dirs.append(packages_path)

        return [path for path in dep_dirs if os.path.isdir(path)]

    def _start_indicator(self, msg: str = "") -> None:
        if self._activity_indicator:
            self._activity_indicator.label = msg  # type: ignore
            self._activity_indicator.update()
        else:
            view = sublime.active_window().active_view()
            if view:
                self._activity_indicator = ActivityIndicator(
                    view, msg)  # type: ignore
                self._activity_indicator.start()

    def _stop_indicator(self) -> None:
        if self._activity_indicator:
            self._activity_indicator.stop()
            self._activity_indicator = None