Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,18 @@

# Claude Code local settings
.claude/settings.local.json

# Python bytecode and cache
__pycache__/
*.py[cod]
*$py.class
*.so
.Python

# Backup files
*.backup
*.backup2
*~
.*.swp
.*.swo
.legacy_backup/
120 changes: 120 additions & 0 deletions autoload/chatgpt.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
" ChatGPT Autoload Core Functions
" This file contains the main API functions for the ChatGPT plugin

" Main ChatGPT function - delegates to Python
function! chatgpt#chat(prompt) abort
" Ensure suppress_display is off for normal chat operations
if !exists('g:chat_gpt_suppress_display')
let g:chat_gpt_suppress_display = 0
endif

python3 << EOF
import sys
import vim
import os

# Add python3/chatgpt to Python path
plugin_dir = vim.eval('expand("<sfile>:p:h:h")')
python_path = os.path.join(plugin_dir, 'python3')
if python_path not in sys.path:
sys.path.insert(0, python_path)

# Import and call main chat function
from chatgpt.core import chat_gpt
chat_gpt(vim.eval('a:prompt'))
EOF

" Check if summary needs updating after AI response completes
if !exists('g:chat_gpt_suppress_display') || g:chat_gpt_suppress_display == 0
call chatgpt#summary#check_and_update()
endif

" Ensure we're in the chat window at the bottom
if !exists('g:chat_gpt_suppress_display') || g:chat_gpt_suppress_display == 0
let chat_winnr = bufwinnr('gpt-persistent-session')
if chat_winnr != -1
execute chat_winnr . 'wincmd w'
normal! G
call cursor('$', 1)
redraw
endif
endif
endfunction

" Display ChatGPT responses in a buffer
function! chatgpt#display_response(response, finish_reason, chat_gpt_session_id)
let response = a:response
let finish_reason = a:finish_reason
let chat_gpt_session_id = a:chat_gpt_session_id

if !bufexists(chat_gpt_session_id)
if g:chat_gpt_split_direction ==# 'vertical'
silent execute winwidth(0)/g:split_ratio.'vnew '. chat_gpt_session_id
else
silent execute winheight(0)/g:split_ratio.'new '. chat_gpt_session_id
endif
call setbufvar(chat_gpt_session_id, '&buftype', 'nofile')
call setbufvar(chat_gpt_session_id, '&bufhidden', 'hide')
call setbufvar(chat_gpt_session_id, '&swapfile', 0)
setlocal modifiable
setlocal wrap
setlocal linebreak
call setbufvar(chat_gpt_session_id, '&ft', 'markdown')
call setbufvar(chat_gpt_session_id, '&syntax', 'markdown')
endif

if bufwinnr(chat_gpt_session_id) == -1
if g:chat_gpt_split_direction ==# 'vertical'
execute winwidth(0)/g:split_ratio.'vsplit ' . chat_gpt_session_id
else
execute winheight(0)/g:split_ratio.'split ' . chat_gpt_session_id
endif
endif

let last_lines = getbufline(chat_gpt_session_id, '$')
let last_line = empty(last_lines) ? '' : last_lines[-1]

let new_lines = substitute(last_line . response, '\n', '\r\n\r', 'g')
let lines = split(new_lines, '\n')

let clean_lines = []
for line in lines
call add(clean_lines, substitute(line, '\r', '', 'g'))
endfor

call setbufline(chat_gpt_session_id, '$', clean_lines)

" Switch to chat window and scroll to bottom
let chat_winnr = bufwinnr(chat_gpt_session_id)
if chat_winnr != -1
let current_win = winnr()
execute chat_winnr . 'wincmd w'
normal! G
call cursor('$', 1)
execute "normal! \<C-E>\<C-Y>"
redraw
endif

" Save to history file if this is a persistent session
if chat_gpt_session_id ==# 'gpt-persistent-session' && response != ''
python3 << EOF
import vim
import sys
import os

plugin_dir = vim.eval('expand("<sfile>:p:h:h")')
python_path = os.path.join(plugin_dir, 'python3')
if python_path not in sys.path:
sys.path.insert(0, python_path)

from chatgpt.utils import save_to_history
response = vim.eval('a:response')
save_to_history(response)
EOF
endif
endfunction

" Helper function to capitalize strings
function! chatgpt#capitalize(str)
return toupper(strpart(a:str, 0, 1)) . tolower(strpart(a:str, 1))
endfunction
15 changes: 15 additions & 0 deletions autoload/chatgpt/commit.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
" ChatGPT Git Commit Generation
" This file handles AI-assisted commit message generation

" Generate a commit message using git integration
function! chatgpt#commit#generate() abort
let prompt = 'Please help me create a git commit message.'
let prompt .= "\n\nThe goal is to:"
let prompt .= "\n- Check the repository status"
let prompt .= "\n- Review the changes that will be committed"
let prompt .= "\n- Draft an appropriate commit message following conventional commit format"
let prompt .= "\n- Create the commit"
let prompt .= "\n\nIf there are no staged changes, ask if I want to stage files first."

call chatgpt#chat(prompt)
endfunction
138 changes: 138 additions & 0 deletions autoload/chatgpt/config.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
" ChatGPT Configuration Management
" This file handles default configuration values

function! chatgpt#config#setup() abort
" Set default values for Vim variables if they don't exist
if !exists("g:chat_gpt_max_tokens")
let g:chat_gpt_max_tokens = 2000
endif

if !exists("g:chat_gpt_temperature")
let g:chat_gpt_temperature = 0.7
endif

if !exists("g:chat_gpt_model")
let g:chat_gpt_model = 'gpt-4o'
endif

if !exists("g:chat_gpt_lang")
let g:chat_gpt_lang = v:none
endif

if !exists("g:chat_gpt_split_direction")
let g:chat_gpt_split_direction = 'vertical'
endif

if !exists("g:split_ratio")
let g:split_ratio = 3
endif

if !exists("g:chat_persona")
let g:chat_persona = 'default'
endif

" Enable tools/function calling (default: enabled for supported providers)
if !exists("g:chat_gpt_enable_tools")
let g:chat_gpt_enable_tools = 1
endif

" Require plan approval before tool execution
if !exists("g:chat_gpt_require_plan_approval")
let g:chat_gpt_require_plan_approval = 1
endif

" Session mode (persistent chat history)
if !exists("g:chat_gpt_session_mode")
let g:chat_gpt_session_mode = 1
endif

" Conversation history compaction settings
if !exists("g:chat_gpt_summary_compaction_size")
let g:chat_gpt_summary_compaction_size = 76800 " 76KB
endif

if !exists("g:chat_gpt_recent_history_size")
let g:chat_gpt_recent_history_size = 30480 " 30KB
endif

" Provider selection
if !exists("g:chat_gpt_provider")
let g:chat_gpt_provider = 'openai'
endif

" Anthropic (Claude) configuration
if !exists("g:anthropic_api_key")
let g:anthropic_api_key = ''
endif

if !exists("g:anthropic_model")
let g:anthropic_model = 'claude-sonnet-4-5-20250929'
endif

if !exists("g:anthropic_base_url")
let g:anthropic_base_url = 'https://api.anthropic.com/v1'
endif

" Gemini (Google) configuration
if !exists("g:gemini_api_key")
let g:gemini_api_key = ''
endif

if !exists("g:gemini_model")
let g:gemini_model = 'gemini-2.5-flash'
endif

" Ollama configuration
if !exists("g:ollama_base_url")
let g:ollama_base_url = 'http://localhost:11434'
endif

if !exists("g:ollama_model")
let g:ollama_model = 'llama3.2'
endif

" OpenRouter configuration
if !exists("g:openrouter_api_key")
let g:openrouter_api_key = ''
endif

if !exists("g:openrouter_model")
let g:openrouter_model = 'anthropic/claude-3.5-sonnet'
endif

if !exists("g:openrouter_base_url")
let g:openrouter_base_url = 'https://openrouter.ai/api/v1'
endif

" Debug logging level (0=off, 1=basic, 2=verbose)
if !exists("g:chat_gpt_log_level")
let g:chat_gpt_log_level = 0
endif

" Prompt templates
let code_wrapper_snippet = "Given the following code snippet: "
let g:prompt_templates = {
\ 'ask': '',
\ 'rewrite': 'Can you rewrite this more idiomatically? ' . code_wrapper_snippet,
\ 'review': 'Can you provide a code review? ' . code_wrapper_snippet,
\ 'document': 'Return documentation following language pattern conventions. ' . code_wrapper_snippet,
\ 'explain': 'Can you explain how this works? ' . code_wrapper_snippet,
\ 'test': 'Can you write a test? ' . code_wrapper_snippet,
\ 'fix': 'I have an error I need you to fix. ' . code_wrapper_snippet,
\}

if exists('g:chat_gpt_custom_prompts')
call extend(g:prompt_templates, g:chat_gpt_custom_prompts)
endif

let g:promptKeys = keys(g:prompt_templates)

" Personas
let g:gpt_personas = {
\ "default": 'You are a helpful expert programmer we are working together to solve complex coding challenges, and I need your help. Please make sure to wrap all code blocks in ``` annotate the programming language you are using.',
\}

if exists('g:chat_gpt_custom_persona')
call extend(g:gpt_personas, g:chat_gpt_custom_persona)
endif
endfunction
Loading