summaryrefslogtreecommitdiff
path: root/py/config.py
blob: 03eb3ca672c4b2166654f9465b935c3ba4484c51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import vim
import re
import os
import configparser

def merge_deep_recursive(target, source = {}):
    source = source.copy()
    for key, value in source.items():
        if isinstance(value, dict):
            target_child = target.setdefault(key, {})
            merge_deep_recursive(target_child, value)
        else:
            target[key] = value
    return target

def merge_deep(objects):
    result = {}
    for o in objects:
        merge_deep_recursive(result, o)
    return result

def enhance_roles_with_custom_function(roles):
    if vim.eval("exists('g:vim_ai_roles_config_function')") == '1':
        roles_config_function = vim.eval("g:vim_ai_roles_config_function")
        if not vim.eval("exists('*" + roles_config_function + "')"):
            raise Exception(f"Role config function does not exist: {roles_config_function}")
        else:
            roles.update(vim.eval(roles_config_function + "()"))

def load_role_config(role):
    roles_config_path = os.path.expanduser(vim.eval("g:vim_ai_roles_config_file"))
    if not os.path.exists(roles_config_path):
        raise Exception(f"Role config file does not exist: {roles_config_path}")

    roles = configparser.ConfigParser()
    roles.read(roles_config_path)
    roles = dict(roles)

    enhance_roles_with_custom_function(roles)

    if not role in roles:
        raise Exception(f"Role `{role}` not found")

    options = roles.get(f"{role}.options", {})
    options_complete = roles.get(f"{role}.options-complete", {})
    options_chat = roles.get(f"{role}.options-chat", {})

    ui = roles.get(f"{role}.ui", {})
    ui_complete = roles.get(f"{role}.ui-complete", {})
    ui_chat = roles.get(f"{role}.ui-chat", {})

    return {
        'role': dict(roles[role]),
        'config_default': {
            'options': dict(options),
            'ui': dict(ui),
        },
        'config_complete': {
            'options': dict(options_complete),
            'ui': dict(ui_complete),
        },
        'config_chat': {
            'options': dict(options_chat),
            'ui': dict(ui_chat),
        },
    }

def parse_role_names(prompt):
    chunks = re.split(r'[ :]+', prompt)
    roles = []
    for chunk in chunks:
        if not chunk.startswith("/"):
            break
        roles.append(chunk)
    return [raw_role[1:] for raw_role in roles]

def parse_prompt_and_role_config(instruction, command_type):
    instruction = instruction.strip()
    roles = parse_role_names(instruction)
    if not roles:
        # does not require role
        return ('', {})

    last_role = roles[-1]
    role_configs = merge_deep([load_role_config(role) for role in roles])
    config = merge_deep([role_configs['config_default'], role_configs['config_' + command_type]])
    role_prompt = role_configs['role'].get('prompt', '')
    return role_prompt, config

def make_config(input_var, output_var):
    input_options = vim.eval(input_var)
    config_default = input_options['config_default']
    config_extension = input_options['config_extension']
    instruction = input_options['instruction']
    command_type = input_options['command_type']

    role_prompt, role_config = parse_prompt_and_role_config(instruction, command_type)

    final_config = merge_deep([config_default, config_extension, role_config])

    output = {}
    output['config'] = final_config
    output['role_prompt'] = role_prompt
    vim.command(f'let {output_var}={output}')
    return output