thatsIch/sublime-rainmeter

View on GitHub
completion/section.py

Summary

Maintainability
B
6 hrs
Test Coverage
"""This module handles the skin section auto completion.

This provides the means to automatically add the base rainmeter sections
upon auto complete request with:

* [Rainmeter]
* [Metadata]
* [Variables]
* [Measure]
* [Meter]
* [MeterStyle]

This only activates if the file is empty or at least 2 new lines above the current caret.
"""

import yaml

import sublime

from .. import logger
from .levenshtein import levenshtein
from .compiler import compile_keys
from .yaml_content_reader import YamlContentReader


def str_equal_case_ignore(str1, str2):
    """Compare two strings ignoring the case."""
    return str1.casefold() == str2.casefold()


def sections_contain_section_id(sections, section_id):
    """Iterates through the sections container and checks if the section_id is in that container."""

    # value not used here
    for section in sections:
        if str_equal_case_ignore(section, section_id):
            return True

    return False


class SkinSectionAutoCompleter(YamlContentReader):  # pylint: disable=R0903; only provide one method

    """
    Ths class is the logical state holder for the auto completion suggestions.

    Upon the request the respective yaml file is parsed and converted into a logical
    representation of the completions. Depending on the prior information the completions
    can be filtered containing less entries.
    """

    def __get_completions(self):
        """IO access to the yaml file.

        Uses a yaml loader to parse it into a python object.
        """
        try:
            section_content = self._get_yaml_content("completion/", "section.yaml")
            section = yaml.load(section_content)

            return section

        except yaml.YAMLError as error:
            logger.error(error)
            return []

    def __lazy_initialize_completions(self):
        # use lazy initialization because else the API is not available yet
        if not self.all_completions:
            self.all_completions = self.__get_completions()
            self.all_key_completions = compile_keys(self.all_completions)

    def __filter_completions_by_sec(self, sections):
        # filter by already existing keys
        completions = []

        settings = sublime.load_settings("Rainmeter.sublime-settings")
        allow_duplicates = settings.get("allow_completion_section_duplicates", False)

        for completion in self.all_key_completions:
            # trigger is not used here
            section_id, display, content, unique = completion

            # we only need to search for duplicates
            # if we are having a unique section like [Rainmeter]
            # and not allow duplicates
            if unique and not allow_duplicates:
                contained = sections_contain_section_id(sections, section_id)

                if not contained:
                    completions.append((display, content))
            else:
                completions.append((display, content))

        return completions

    # only show our completion list because nothing else makes sense in this context
    flags = sublime.INHIBIT_EXPLICIT_COMPLETIONS | sublime.INHIBIT_WORD_COMPLETIONS

    all_completions = None
    all_key_completions = None

    def get_key_context_completion(self, prefix, line_content, sections):
        """Provide all possible sections without duplicates of unique ones."""
        # if section.casefold() != "Metadata".casefold():
        #     return None

        self.__lazy_initialize_completions()
        completions = self.__filter_completions_by_sec(sections)
        # no results, means all keys are used up
        if not completions:
            return None

        # only show sorted by distance if something was already typed
        # because distance to empty string makes no sense
        if line_content != "":
            # sort by levenshtein distance
            sorted_completions = sorted(
                completions,
                key=lambda completion: levenshtein(completion[1], prefix)
            )
            return sorted_completions, self.flags
        else:
            return completions, self.flags