<commit_before>"""
DSL for SublimeText's  Key Bindings.

Example:

..  code-block:: python

    from sublimedsl.keymap import *

    Keymap(
        bind('backspace')
            .to('run_macro_file', file='res://Packages/Default/Delete Left Right.sublime-macro')
            .when('setting.auto_match_enabled').any().true()
            .also('preceding_text').regex_contains(r'_$')
            .also('following_text').regex_contains(r'^_'),

        bind('super+k', 'super+shift+up')
            .to('new_pane', move=False),

        common_context=[
            context('selector').equal('text.asciidoc')
        ],
        default_match_all=True

    ).dump('Default')  # nopep8


The above code will produce file ``Default.sublime-keymap`` with:

..  code-block:: json

    [{
      "keys": [ "backspace" ],
      "command": "run_macro_file",
      "args": { "file": "res://Packages/Default/Delete Left Right.sublime-macro" },
      "context": [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true, "match_all": false },
        { "key": "preceding_text", "operator": "regex_contains", "operand": "_$", "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^_", "match_all": true },
        { "key": "selector", "operator": "equal", "operand": "text.asciidoc", "match_all": true }
      ]
    }, {
      "keys": [ "super+k", "super+shift+up" ],
      "command": "new_pane",
      "args": { "move": false },
      "context": [
        { "key": "selector", "operator": "equal", "operand": "text.asciidoc", "match_all": true }
      ]
    }]

See `Key Bindings <http://docs.sublimetext.info/en/latest/reference/key_bindings.html>`_
in the SublimeText documentation.
"""  # nopep8

import json
import sys
from collections import OrderedDict
from copy import deepcopy
from funcy import all_fn, any_fn, complement, isa, isnone, partial
from funcy import rcompose as pipe
from funcy import flatten, lflatten, map, pluck_attr, select_values

__all__ = ['Context', 'Binding', 'Keymap', 'bind', 'context']

FILE_SUFFIX = '.sublime-keymap'


class Keymap():

    """ Basically a container for key bindings. """

    def __init__(self, *bindings, default_match_all=None, common_context=[]):
        """
        Arguments:
            *bindings (Binding): The key bindings to be added to this keymap.
            default_match_all (Optional[bool]): The default value of ``match_all`` to be
                set when context doesn't specify it. See :meth:`Context.any`
                and :meth:`Context.all`.
            common_context (List[Context]): The context that should be added to all bindings.
        """
        self._default_match_all = default_match_all
        self._common_context = common_context
        self._bindings = self._preprocess(bindings)

    def to_json(self, **kwargs):
        """
        Arguments:
            **kwargs: Options to be passed into :func:`json.dumps`.
        Returns:
            str: A JSON representing this keymap.
        """
        return jsonify(self._bindings, **kwargs)

    def dump(self, filename, **kwargs):
        """ Serialize this keymap as a JSON to the file.

        Arguments:
            filename (str): Name of the file to dump the generated JSON into.
            **kwargs: Options to be passed into :func:`json.dumps`.
        """
        if not filename.lower().endswith(FILE_SUFFIX):
            filename += FILE_SUFFIX
        with open(filename, 'w') as f:
            f.writelines(self.to_json(**kwargs))

    def extend(self, *bindings):
        """ Append the given bindings to this keymap.

        Arguments:
            *bindings (Binding): Bindings to be added.
        """
        self._bindings.extend(self._preprocess(bindings))

    def _preprocess(self, bindings):
        return pipe(
            deepcopy,
            partial(lflatten, follow=isa(list, tuple, Keymap)),
            self._apply_common_context,
            self._apply_default_match_all
        )(bindings)

    def _apply_common_context(self, bindings):
        for binding in bindings:
            binding.context.extend(self._common_context)
        return bindings

    def _apply_default_match_all(self, bindings):
        for context in flatten(pluck_attr('context', bindings)):
            if context.match_all is None:
                context.match_all = self._default_match_all
        return bindings

    def __iter__(self):<commit_msg>Add comment "generated file, do not edit by hand" to dumped keymap file<commit_after>"""
DSL for SublimeText's  Key Bindings.

Example:

..  code-block:: python

    from sublimedsl.keymap import *

    Keymap(
        bind('backspace')
            .to('run_macro_file', file='res://Packages/Default/Delete Left Right.sublime-macro')
            .when('setting.auto_match_enabled').any().true()
            .also('preceding_text').regex_contains(r'_$')
            .also('following_text').regex_contains(r'^_'),

        bind('super+k', 'super+shift+up')
            .to('new_pane', move=False),

        common_context=[
            context('selector').equal('text.asciidoc')
        ],
        default_match_all=True

    ).dump('Default')  # nopep8


The above code will produce file ``Default.sublime-keymap`` with:

..  code-block:: json

    [{
      "keys": [ "backspace" ],
      "command": "run_macro_file",
      "args": { "file": "res://Packages/Default/Delete Left Right.sublime-macro" },
      "context": [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true, "match_all": false },
        { "key": "preceding_text", "operator": "regex_contains", "operand": "_$", "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^_", "match_all": true },
        { "key": "selector", "operator": "equal", "operand": "text.asciidoc", "match_all": true }
      ]
    }, {
      "keys": [ "super+k", "super+shift+up" ],
      "command": "new_pane",
      "args": { "move": false },
      "context": [
        { "key": "selector", "operator": "equal", "operand": "text.asciidoc", "match_all": true }
      ]
    }]

See `Key Bindings <http://docs.sublimetext.info/en/latest/reference/key_bindings.html>`_
in the SublimeText documentation.
"""  # nopep8

import json
import sys
from collections import OrderedDict
from copy import deepcopy
from funcy import all_fn, any_fn, complement, isa, isnone, partial
from funcy import rcompose as pipe
from funcy import flatten, lflatten, map, pluck_attr, select_values

__all__ = ['Context', 'Binding', 'Keymap', 'bind', 'context']

FILE_SUFFIX = '.sublime-keymap'

FILE_HEADER = '''\
// This file is generated, do not edit it by hand!
// -*- mode: JSON -*-
'''


class Keymap():

    """ Basically a container for key bindings. """

    def __init__(self, *bindings, default_match_all=None, common_context=[]):
        """
        Arguments:
            *bindings (Binding): The key bindings to be added to this keymap.
            default_match_all (Optional[bool]): The default value of ``match_all`` to be
                set when context doesn't specify it. See :meth:`Context.any`
                and :meth:`Context.all`.
            common_context (List[Context]): The context that should be added to all bindings.
        """
        self._default_match_all = default_match_all
        self._common_context = common_context
        self._bindings = self._preprocess(bindings)

    def to_json(self, **kwargs):
        """
        Arguments:
            **kwargs: Options to be passed into :func:`json.dumps`.
        Returns:
            str: A JSON representing this keymap.
        """
        return jsonify(self._bindings, **kwargs)

    def dump(self, filename, **kwargs):
        """ Serialize this keymap as a JSON to the file.

        Arguments:
            filename (str): Name of the file to dump the generated JSON into.
            **kwargs: Options to be passed into :func:`json.dumps`.
        """
        if not filename.lower().endswith(FILE_SUFFIX):
            filename += FILE_SUFFIX
        with open(filename, 'w') as f:
            f.write(FILE_HEADER)
            f.writelines(self.to_json(**kwargs))

    def extend(self, *bindings):
        """ Append the given bindings to this keymap.

        Arguments:
            *bindings (Binding): Bindings to be added.
        """
        self._bindings.extend(self._preprocess(bindings))

    def _preprocess(self, bindings):
        return pipe(
            deepcopy,
            partial(lflatten, follow=isa(list, tuple, Keymap)),
            self._apply_common_context,
            self._apply_default_match_all
        )(bindings)

    def _apply_common_context(self, bindings):
        for binding in bindings:
            binding.context.extend(self._common_context)
        return bindings

    def _apply_default_match_all(self, bindings):
        for context in flatten(pluck_attr('context', bindings)):
            if context.match_all is None:
                context.match_all = self._default_match_all
        return bindings

    def __iter__(self):
{'fraction_non_alphanumeric': 0.13472922604691953, 'fraction_numerical': 0.0004385003288752467, 'mean_word_length': 2.6419161676646707, 'pattern_counts': {'":': 60, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3473757', 'n_tokens_mistral': 2822, 'n_tokens_neox': 2710, 'n_words': 693}