From b0f7e3b8d92289d1a8086e3eed206f8b5757328b Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 18:06:14 +0100 Subject: read role prompt from config --- py/chat.py | 9 ++++++--- py/complete.py | 8 ++++++-- py/utils.py | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/py/chat.py b/py/chat.py index ff70904..85adfec 100644 --- a/py/chat.py +++ b/py/chat.py @@ -4,10 +4,13 @@ import vim plugin_root = vim.eval("s:plugin_root") vim.command(f"py3file {plugin_root}/py/utils.py") +prompt, role_options = parse_prompt_and_role(vim.eval("l:prompt")) config = normalize_config(vim.eval("l:config")) -config_options = config['options'] +config_options = { + **config['options'], + **role_options, +} config_ui = config['ui'] -prompt = vim.eval("l:prompt").strip() def initialize_chat_window(): lines = vim.eval('getline(1, "$")') @@ -72,7 +75,7 @@ try: **openai_options } printDebug("[chat] request: {}", request) - url = config_options['endpoint_url'] + url = options['endpoint_url'] response = openai_request(url, request, http_options) def map_chunk(resp): printDebug("[chat] response: {}", resp) diff --git a/py/complete.py b/py/complete.py index debe275..453ef46 100644 --- a/py/complete.py +++ b/py/complete.py @@ -6,11 +6,15 @@ vim.command(f"py3file {plugin_root}/py/utils.py") config = normalize_config(vim.eval("l:config")) engine = config['engine'] -config_options = config['options'] + +prompt, role_options = parse_prompt_and_role(vim.eval("l:prompt")) +config_options = { + **config['options'], + **role_options, +} openai_options = make_openai_options(config_options) http_options = make_http_options(config_options) -prompt = vim.eval("l:prompt").strip() is_selection = vim.eval("l:is_selection") def complete_engine(prompt): diff --git a/py/utils.py b/py/utils.py index 19de7c4..7a1a574 100644 --- a/py/utils.py +++ b/py/utils.py @@ -11,6 +11,7 @@ import re from urllib.error import URLError from urllib.error import HTTPError import traceback +import configparser is_debugging = vim.eval("g:vim_ai_debug") == "1" debug_log_file = vim.eval("g:vim_ai_debug_log_file") @@ -261,3 +262,26 @@ def handle_completion_error(error): def clear_echo_message(): # https://neovim.discourse.group/t/how-to-clear-the-echo-message-in-the-command-line/268/3 vim.command("call feedkeys(':','nx')") + +def load_role_config(role): + roles_config_path = os.path.expanduser('~/.vim/roles.ini') # TODO configure + roles = configparser.ConfigParser() + roles.read(roles_config_path) + if not role in roles: + raise KnownError(f"Role {role} not found") # TODO handle errors + return roles[role] + +def parse_prompt_and_role(raw_prompt): + prompt = raw_prompt.strip() + role = re.split(' |:', prompt)[0] + if not role.startswith('/'): + # does not require role + return (prompt, {}) + + prompt = prompt[len(role):].strip() + role = role[1:] + + role_config = load_role_config(role) + delim = '' if prompt.startswith(':') else ':\n' + prompt = role_config['prompt'] + delim + prompt + return (prompt, {}) -- cgit v1.2.3 From bdd1069562967bd07921e75873d54eb75d62144d Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 18:32:45 +0100 Subject: parse role options --- py/chat.py | 3 ++- py/complete.py | 3 ++- py/utils.py | 28 +++++++++++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/py/chat.py b/py/chat.py index 85adfec..f996800 100644 --- a/py/chat.py +++ b/py/chat.py @@ -8,7 +8,8 @@ prompt, role_options = parse_prompt_and_role(vim.eval("l:prompt")) config = normalize_config(vim.eval("l:config")) config_options = { **config['options'], - **role_options, + **role_options['options_default'], + **role_options['options_chat'], } config_ui = config['ui'] diff --git a/py/complete.py b/py/complete.py index 453ef46..f340e96 100644 --- a/py/complete.py +++ b/py/complete.py @@ -10,7 +10,8 @@ engine = config['engine'] prompt, role_options = parse_prompt_and_role(vim.eval("l:prompt")) config_options = { **config['options'], - **role_options, + **role_options['options_default'], + **role_options['options_complete'], } openai_options = make_openai_options(config_options) http_options = make_http_options(config_options) diff --git a/py/utils.py b/py/utils.py index 7a1a574..52e538d 100644 --- a/py/utils.py +++ b/py/utils.py @@ -269,19 +269,37 @@ def load_role_config(role): roles.read(roles_config_path) if not role in roles: raise KnownError(f"Role {role} not found") # TODO handle errors - return roles[role] + + options = roles[f"{role}.options"] if f"{role}.options" in roles else {} + options_complete =roles[f"{role}.options-complete"] if f"{role}.options-complete" in roles else {} + options_chat = roles[f"{role}.options-chat"] if f"{role}.options-chat" in roles else {} + + return { + 'role': dict(roles[role]), + 'options': { + 'options_default': dict(options), + 'options_complete': dict(options_complete), + 'options_chat': dict(options_chat), + }, + } + +empty_role_options = { + 'options_default': {}, + 'options_complete': {}, + 'options_chat': {}, +} def parse_prompt_and_role(raw_prompt): prompt = raw_prompt.strip() role = re.split(' |:', prompt)[0] if not role.startswith('/'): # does not require role - return (prompt, {}) + return (prompt, empty_role_options) prompt = prompt[len(role):].strip() role = role[1:] - role_config = load_role_config(role) + config = load_role_config(role) delim = '' if prompt.startswith(':') else ':\n' - prompt = role_config['prompt'] + delim + prompt - return (prompt, {}) + prompt = config['role']['prompt'] + delim + prompt + return (prompt, config['options']) -- cgit v1.2.3 From 9db190c977d1f76e2f574882e4edde062eecbb0d Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 19:08:34 +0100 Subject: roles completion --- autoload/vim_ai.vim | 9 +++++++++ plugin/vim-ai.vim | 10 +++++----- py/roles.py | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 py/roles.py diff --git a/autoload/vim_ai.vim b/autoload/vim_ai.vim index 74515d4..302ef1d 100644 --- a/autoload/vim_ai.vim +++ b/autoload/vim_ai.vim @@ -1,8 +1,10 @@ call vim_ai_config#load() + let s:plugin_root = expand(':p:h:h') let s:complete_py = s:plugin_root . "/py/complete.py" let s:chat_py = s:plugin_root . "/py/chat.py" +let s:roles_py = s:plugin_root . "/py/roles.py" " remembers last command parameters to be used in AIRedoRun let s:last_is_selection = 0 @@ -249,3 +251,10 @@ function! vim_ai#AIRedoRun() call vim_ai#AIChatRun(0, s:last_config) endif endfunction + +function! vim_ai#RoleCompletion(A,L,P) abort + execute "py3file " . s:roles_py + call map(l:role_list, '"/" . v:val') + echom a:A + return filter(l:role_list, 'v:val =~ "^' . a:A . '"') +endfunction diff --git a/plugin/vim-ai.vim b/plugin/vim-ai.vim index 0e4957f..1ed5326 100644 --- a/plugin/vim-ai.vim +++ b/plugin/vim-ai.vim @@ -12,11 +12,11 @@ augroup vim_ai \ let g:vim_ai_is_selection_pending = mode() =~# "^[vV\]" augroup END -command! -range -nargs=? AI ,call vim_ai#AIRun({}, ) -command! -range -nargs=? AIEdit ,call vim_ai#AIEditRun({}, ) +command! -range -nargs=? -complete=customlist,vim_ai#RoleCompletion AI ,call vim_ai#AIRun({}, ) +command! -range -nargs=? -complete=customlist,vim_ai#RoleCompletion AIEdit ,call vim_ai#AIEditRun({}, ) " Whereas AI and AIEdit default to passing the current line as range " AIChat defaults to passing nothing which is achieved by -range=0 and passing " as described at https://stackoverflow.com/a/20133772 -command! -range=0 -nargs=? AIChat ,call vim_ai#AIChatRun(, {}, ) -command! -nargs=? AINewChat call vim_ai#AINewChatRun() -command! AIRedo call vim_ai#AIRedoRun() +command! -range=0 -nargs=? -complete=customlist,vim_ai#RoleCompletion AIChat ,call vim_ai#AIChatRun(, {}, ) +command! -nargs=? AINewChat call vim_ai#AINewChatRun() +command! AIRedo call vim_ai#AIRedoRun() diff --git a/py/roles.py b/py/roles.py new file mode 100644 index 0000000..8f7f161 --- /dev/null +++ b/py/roles.py @@ -0,0 +1,16 @@ +import vim +import os +import configparser + +roles_config_path = os.path.expanduser('~/.vim/roles.ini') # TODO configure +roles = configparser.ConfigParser() +roles.read(roles_config_path) + +role_names = [name for name in roles.sections() if not '.' in name] + +role_list = [f'"{name}"' for name in role_names] +role_list = ", ".join(role_list) + +role_list = f"[{role_list}]" + +vim.command(f'let l:role_list = {role_list}') -- cgit v1.2.3 From f4130feb986760a8d956983cb5cfe8d7106e7d4a Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 19:37:55 +0100 Subject: roles example file --- autoload/vim_ai.vim | 1 - autoload/vim_ai_config.vim | 5 +++++ py/roles.py | 2 +- py/utils.py | 2 +- roles-example.ini | 22 ++++++++++++++++++++++ 5 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 roles-example.ini diff --git a/autoload/vim_ai.vim b/autoload/vim_ai.vim index 302ef1d..b6f4617 100644 --- a/autoload/vim_ai.vim +++ b/autoload/vim_ai.vim @@ -1,6 +1,5 @@ call vim_ai_config#load() - let s:plugin_root = expand(':p:h:h') let s:complete_py = s:plugin_root . "/py/complete.py" let s:chat_py = s:plugin_root . "/py/chat.py" diff --git a/autoload/vim_ai_config.vim b/autoload/vim_ai_config.vim index ef3c863..41932de 100644 --- a/autoload/vim_ai_config.vim +++ b/autoload/vim_ai_config.vim @@ -1,3 +1,5 @@ +let s:plugin_root = expand(':p:h:h') + let g:vim_ai_complete_default = { \ "engine": "complete", \ "options": { @@ -73,6 +75,9 @@ endif if !exists("g:vim_ai_token_file_path") let g:vim_ai_token_file_path = "~/.config/openai.token" endif +if !exists("g:vim_ai_roles_config_file") + let g:vim_ai_roles_config_file = s:plugin_root . "/roles-example.ini" +endif function! vim_ai_config#ExtendDeep(defaults, override) abort let l:result = a:defaults diff --git a/py/roles.py b/py/roles.py index 8f7f161..7c7cf13 100644 --- a/py/roles.py +++ b/py/roles.py @@ -2,7 +2,7 @@ import vim import os import configparser -roles_config_path = os.path.expanduser('~/.vim/roles.ini') # TODO configure +roles_config_path = os.path.expanduser(vim.eval("g:vim_ai_roles_config_file")) roles = configparser.ConfigParser() roles.read(roles_config_path) diff --git a/py/utils.py b/py/utils.py index 52e538d..6600fc3 100644 --- a/py/utils.py +++ b/py/utils.py @@ -264,7 +264,7 @@ def clear_echo_message(): vim.command("call feedkeys(':','nx')") def load_role_config(role): - roles_config_path = os.path.expanduser('~/.vim/roles.ini') # TODO configure + roles_config_path = os.path.expanduser(vim.eval("g:vim_ai_roles_config_file")) roles = configparser.ConfigParser() roles.read(roles_config_path) if not role in roles: diff --git a/roles-example.ini b/roles-example.ini new file mode 100644 index 0000000..90d32bc --- /dev/null +++ b/roles-example.ini @@ -0,0 +1,22 @@ +# .ini file structure: +# - https://docs.python.org/3/library/configparser.html#supported-ini-file-structure + +[grammar] +prompt = fix spelling and grammar + +[refactor] +prompt = + You are a Clean Code expert, I have the following code, + please refactor it in a more clean and concise way so that my colleagues + can maintain the code more easily. Also, explain why you want to refactor + the code so that I can add the explanation to the Pull Request. + +# common options for all engines +[refactor.options] +temperature = 0.4 + +# engine specific options: +[refactor.options-chat] +model = gpt-4 + +[refactor.options-complete] -- cgit v1.2.3 From 155d0c8eda5e5effdd7a234da46db18fbe32e17a Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 19:48:17 +0100 Subject: fix using role in existing chat --- py/chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/chat.py b/py/chat.py index f996800..67f2d5d 100644 --- a/py/chat.py +++ b/py/chat.py @@ -42,7 +42,7 @@ def initialize_chat_window(): vim.command("normal! i\n>>> user\n\n") if prompt: - vim.command("normal! a" + prompt) + vim.command("normal! i" + prompt) vim_break_undo_sequence() vim.command("redraw") -- cgit v1.2.3 From 188d07f5efa8a4cde3407e71ca2013c10c051bba Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 20:02:24 +0100 Subject: simple error handling --- py/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/py/utils.py b/py/utils.py index 6600fc3..9ef8b72 100644 --- a/py/utils.py +++ b/py/utils.py @@ -265,10 +265,14 @@ def clear_echo_message(): 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) + if not role in roles: - raise KnownError(f"Role {role} not found") # TODO handle errors + raise Exception(f"Role `{role}` not found") options = roles[f"{role}.options"] if f"{role}.options" in roles else {} options_complete =roles[f"{role}.options-complete"] if f"{role}.options-complete" in roles else {} -- cgit v1.2.3 From 47ea181a3b99aef4a9be10e31f3d12ddbcde54b2 Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 22:07:40 +0100 Subject: roles docu --- README.md | 32 +++++++++++++++++++++++++++++++- doc/vim-ai.txt | 16 ++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 18ac762..a241551 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ To get an idea what is possible to do with AI commands see the [prompts](https:/ - Generate text or code, answer questions with AI - Edit selected text in-place with AI - Interactive conversation with ChatGPT +- Supports custom roles and more ## How it works @@ -89,13 +90,15 @@ To use an AI command, type the command followed by an instruction prompt. You ca **Tip:** Setup your own [key bindings](#key-bindings) or use command shortcuts - `:AIE`, `:AIC`, `:AIR` +**Tip:** A [custom role](#role) {role} can be passed to the above commands by an initial parameter /{role}, for example `:AIEdit /grammar`. + **Tip:** Combine commands with a range `:help range`, for example to select the whole buffer - `:%AIE fix grammar` If you are interested in more tips or would like to level up your Vim with more commands like [`:GitCommitMessage`](https://github.com/madox2/vim-ai/wiki/Custom-commands#suggest-a-git-commit-message) - suggesting a git commit message, visit the [Community Wiki](https://github.com/madox2/vim-ai/wiki). ## Reference -In the documentation below, `` denotes a visual selection or any other range, `{instruction}` an instruction prompt and `?` symbol an optional parameter. +In the documentation below, `` denotes a visual selection or any other range, `{instruction}` an instruction prompt, `{role}` a [custom role](#roles) and `?` symbol an optional parameter. ### `:AI` @@ -107,18 +110,24 @@ In the documentation below, `` denotes a visual selection or any oth ` :AI {instruction}` - complete the selection using the instruction +`? :AI /{role} {instruction}?` - use role to complete + ### `:AIEdit` `? :AIEdit` - edit the current line or the selection `? :AIEdit {instruction}` - edit the current line or the selection using the instruction +`? :AIEdit /{role} {instruction}?` - use role to edit + ### `:AIChat` `:AIChat` - continue or start a new conversation. `? :AIChat {instruction}?` - start a new conversation given the selection, the instruction or both +`? :AIChat /{role} {instruction}?` - use role to complete + When the AI finishes answering, you can continue the conversation by entering insert mode, adding your prompt, and then using the command `:AIChat` once again. #### `.aichat` files @@ -171,6 +180,27 @@ As a parameter you put an open chat command preset shortcut - `below`, `tab` or Use this immediately after `AI`/`AIEdit`/`AIChat` command in order to re-try or get an alternative completion. Note that the randomness of responses heavily depends on the [`temperature`](https://platform.openai.com/docs/api-reference/completions/create#completions/create-temperature) parameter. +## Roles + +In the context of this plugin, a role means a re-usable AI instruction and/or configuration. Roles are defined in the configuration `.ini` file. For example by defining a `grammar` role: + +```vim +let g:vim_ai_roles_config_file = '/path/to/my/roles.ini' +``` + +```ini +# /path/to/my/roles.ini + +[grammar] +prompt = fix spelling and grammar + +[grammar.options] +temperature = 0.4 +``` + +Now you can select text and run it with command `:AIEdit /grammar`. + +See [roles-example.ini](./roles-example.ini) for more examples. ## Key bindings diff --git a/doc/vim-ai.txt b/doc/vim-ai.txt index 72535b3..5d06fc7 100644 --- a/doc/vim-ai.txt +++ b/doc/vim-ai.txt @@ -161,6 +161,22 @@ You can also customize the options in the chat header: > generate a paragraph of lorem ipsum ... +ROLES + +Roles are defined in the `.ini` file: > + + let g:vim_ai_roles_config_file = '/path/to/my/roles.ini' + +Example of a role: > + + [grammar] + prompt = fix spelling and grammar + + [grammar.options] + temperature = 0.4 + +See roles-example.ini for more examples. + KEY BINDINGS Examples how configure key bindings and customize commands: > -- cgit v1.2.3 From cb4c9e94b2a500f38161227df24feed762000095 Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 22:18:36 +0100 Subject: supprot config only roles --- py/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/py/utils.py b/py/utils.py index 9ef8b72..6bd90a1 100644 --- a/py/utils.py +++ b/py/utils.py @@ -304,6 +304,7 @@ def parse_prompt_and_role(raw_prompt): role = role[1:] config = load_role_config(role) - delim = '' if prompt.startswith(':') else ':\n' - prompt = config['role']['prompt'] + delim + prompt + if 'prompt' in config['role'] and config['role']['prompt']: + delim = '' if prompt.startswith(':') else ':\n' + prompt = config['role']['prompt'] + delim + prompt return (prompt, config['options']) -- cgit v1.2.3 From 3983c13d9aa311ca63a5d9848e044678e84d4162 Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 22:21:07 +0100 Subject: docu typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a241551..5731541 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ To use an AI command, type the command followed by an instruction prompt. You ca **Tip:** Setup your own [key bindings](#key-bindings) or use command shortcuts - `:AIE`, `:AIC`, `:AIR` -**Tip:** A [custom role](#role) {role} can be passed to the above commands by an initial parameter /{role}, for example `:AIEdit /grammar`. +**Tip:** A [custom role](#roles) {role} can be passed to the above commands by an initial parameter /{role}, for example `:AIEdit /grammar`. **Tip:** Combine commands with a range `:help range`, for example to select the whole buffer - `:%AIE fix grammar` -- cgit v1.2.3 From 5709ab1ce75f05e9b57bf052f3ad92aa74f61c16 Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sat, 9 Mar 2024 22:44:27 +0100 Subject: removed unused log --- autoload/vim_ai.vim | 1 - 1 file changed, 1 deletion(-) diff --git a/autoload/vim_ai.vim b/autoload/vim_ai.vim index b6f4617..47a9f03 100644 --- a/autoload/vim_ai.vim +++ b/autoload/vim_ai.vim @@ -254,6 +254,5 @@ endfunction function! vim_ai#RoleCompletion(A,L,P) abort execute "py3file " . s:roles_py call map(l:role_list, '"/" . v:val') - echom a:A return filter(l:role_list, 'v:val =~ "^' . a:A . '"') endfunction -- cgit v1.2.3 From af52f039513b11e9820ce0bf1e46596a454ebd44 Mon Sep 17 00:00:00 2001 From: Konfekt Date: Sun, 10 Mar 2024 21:28:54 +0100 Subject: Ensure role config file exists before loading to prevent errors The problem was that the application tried to load a roles configuration file without checking whether it actually exists, potentially leading to unhandled exceptions if the file is missing. Ensure that the roles configuration file exists before attempting to read from it; raise an exception with a clear message if the file is not found. diff --git a/py/roles.py b/py/roles.py: -if not os.path.exists(roles_config_path): - raise Exception(f"Role config file does not exist: {roles_config_path}") - --- py/roles.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py/roles.py b/py/roles.py index 7c7cf13..a8689f2 100644 --- a/py/roles.py +++ b/py/roles.py @@ -3,6 +3,9 @@ import os import configparser 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) -- cgit v1.2.3 From 881fd24a6d2c0de387256b4d6e05f5d0a53cc8e2 Mon Sep 17 00:00:00 2001 From: Konfekt Date: Sun, 10 Mar 2024 21:29:32 +0100 Subject: optionally supplement roles dict by vim function source The application was restricted to loading role configurations only from a predefined config file, which limited extensibility. Enable dynamic role configuration by invoking a custom Vim function if it is defined. This allows users to extend the role configurations beyond the static file. diff --git a/doc/vim-ai.txt b/doc/vim-ai.txt: -The roles in g:vim_ai_roles_config_file are converted to a Vim dictionary. -Optionally, additional roles can be added by defining a function VimAIRoleParser() -whose output is a dictionary of the same format as g:vim_ai_roles_config_file. - diff --git a/py/roles.py b/py/roles.py: -if vim.eval('exists("*VimAIRoleParser")'): - roles.update(vim.eval('VimAIRoleParser()')) - diff --git a/py/utils.py b/py/utils.py: - if vim.eval('exists("*VimAIRoleParser")'): - roles.update(vim.eval('VimAIRoleParser()')) - --- doc/vim-ai.txt | 5 +++++ py/roles.py | 7 +++++++ py/utils.py | 7 +++++++ 3 files changed, 19 insertions(+) diff --git a/doc/vim-ai.txt b/doc/vim-ai.txt index 5d06fc7..c7aefde 100644 --- a/doc/vim-ai.txt +++ b/doc/vim-ai.txt @@ -177,6 +177,11 @@ Example of a role: > See roles-example.ini for more examples. +The roles in g:vim_ai_roles_config_file are converted to a Vim dictionary whose +labels are the names of the roles. Optionally, roles can be added by setting +g:vim_ai_roles_config_function to the name of a Vimscript function returning a +dictionary of the same format as g:vim_ai_roles_config_file. + KEY BINDINGS Examples how configure key bindings and customize commands: > diff --git a/py/roles.py b/py/roles.py index a8689f2..6e0a52e 100644 --- a/py/roles.py +++ b/py/roles.py @@ -9,6 +9,13 @@ if not os.path.exists(roles_config_path): roles = configparser.ConfigParser() roles.read(roles_config_path) +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 + "()")) + role_names = [name for name in roles.sections() if not '.' in name] role_list = [f'"{name}"' for name in role_names] diff --git a/py/utils.py b/py/utils.py index 6bd90a1..471b5c4 100644 --- a/py/utils.py +++ b/py/utils.py @@ -271,6 +271,13 @@ def load_role_config(role): roles = configparser.ConfigParser() roles.read(roles_config_path) + 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 + "()")) + if not role in roles: raise Exception(f"Role `{role}` not found") -- cgit v1.2.3 From 6a053767af08d6edfb46b4be72f05a9b3bc7be04 Mon Sep 17 00:00:00 2001 From: Martin Bielik Date: Sun, 24 Mar 2024 11:29:22 +0100 Subject: reusing parsing code --- py/roles.py | 13 +++++-------- py/utils.py | 15 +++++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/py/roles.py b/py/roles.py index 6e0a52e..b7d19e1 100644 --- a/py/roles.py +++ b/py/roles.py @@ -1,6 +1,8 @@ import vim -import os -import configparser + +# import utils +plugin_root = vim.eval("s:plugin_root") +vim.command(f"py3file {plugin_root}/py/utils.py") roles_config_path = os.path.expanduser(vim.eval("g:vim_ai_roles_config_file")) if not os.path.exists(roles_config_path): @@ -9,12 +11,7 @@ if not os.path.exists(roles_config_path): roles = configparser.ConfigParser() roles.read(roles_config_path) -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 + "()")) +enhance_roles_with_custom_function(roles) role_names = [name for name in roles.sections() if not '.' in name] diff --git a/py/utils.py b/py/utils.py index 471b5c4..963377d 100644 --- a/py/utils.py +++ b/py/utils.py @@ -263,6 +263,14 @@ def clear_echo_message(): # https://neovim.discourse.group/t/how-to-clear-the-echo-message-in-the-command-line/268/3 vim.command("call feedkeys(':','nx')") +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): @@ -271,12 +279,7 @@ def load_role_config(role): roles = configparser.ConfigParser() roles.read(roles_config_path) - 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 + "()")) + enhance_roles_with_custom_function(roles) if not role in roles: raise Exception(f"Role `{role}` not found") -- cgit v1.2.3