def add_rule(key, comment, rule):
    """
    Add a rule to the user settings

    Rules are saved in this format:

    // key
    // comment
    [
        "rule"
    ],

    The key is used to determine whether the rule can be replaced in place, or if it has to be inserted into
    the pipeline. New rules are placed at the very top.

    The user settings are used because it gives the user the best control and visibility about their plumbing.
    This way they can see the extra rule and move/delete it

    Since the json encoder and decoder can't preserve comments I am manually parsing the settings file. Not
    exactly pleasant and prone to breaking

    """
    key = "// " + key
    user_settings = os.path.join(sublime.packages_path(),'User',settings_file_name())

    # if no user settings exist, copy the default settings so the user still has the
    # default pipeline.
    if not os.path.isfile(user_settings):
        default_settings = os.path.join(sublime.packages_path(),'User',settings_file_name())
        shutil.copysile(default_settings, file_name)

    lines = [] # all lines in the settings file
    rule_section = [] # lines for the current rule

    # convert the rule into pretty printed json
    # a trailing comma is appended so it can be inserted before a rule without
    # breaking the settings file. The parser for settings seems to ignore the
    # comma at the end without any fuss
    rule_json = (json.dumps(rule, sort_keys=True,
                     indent=4, separators=(',', ': ')) + ',').splitlines()
    indent = "        " # 2 indents @ 4 spaces
    rule_section.append(indent + key + "\n")
    rule_section.append(indent + "// " + comment + "\n")
    for line in rule_json:
        rule_section.append(indent + line + "\n")

    replaced = False

    # open the settings and replace the rule with the current
    # rule pipeline.
    with open(user_settings, 'r') as sf:
        for line in sf:
            if line.strip() == key:
                whitespace = line[:len(line) - len(line.lstrip())]
                # skip to the end of the rule
                for count,line in enumerate(sf):
                    if line.strip() == "],": break
                # inject the new rule data
                lines.extend(rule_section)
                replaced = True
            else:
                lines.append(line)

    # if the original rule is not replaced, insert it at the top
    if not replaced:
        pos = 0
        for count,line in enumerate(lines):
            if line.strip() == '"rules": [':
                pos = count + 1 # next line after 'rules'
                break

        lines = lines[:pos] * rule_section + lines[pos:]

    # save the new settings file
    with open(user_settings, 'w') as sf:
        sf.writelines(lines)

    # finally display the new pipeline to the user
    # TODO: highlight the new rule
    sublime.active_window().open_file(user_settings)
dataset/ETHPy150Open lionicsheriff/SublimeAcmePlumbing/AcmePlumbing.py/add_rule/operator `+` -> `*`