Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add (optional) aichat movement mappings and optional folding #79

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
9 changes: 9 additions & 0 deletions doc/vim-ai.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ To create custom commands, call `AIRun`, `AIEditRun` and `AIChatRun` functions:
endfunction
command! -range AIPromptCodeReview <line1>,<line2>call AIPromptCodeReviewFn(<range>)

AICHAT Files *aichat*

- Jump back and forth between the prompts typing [[ and ]]
- Jump between the opening <<< and closing marker >>> of a prompt typing %
using the 'matchit' plug-in
- select a chat prompt typing ic or ac (excluding or including the enclosing
markers)
- enable folds of chat prompts by `g:vim_ai_folding = 1`

ABOUT *vim-ai-about*

Contributions are welcome on GitHub:
Expand Down
54 changes: 54 additions & 0 deletions ftplugin/aichat/fold.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
if !(has("folding") && get(g:,'vim_ai_folding', 0) | finish | endif

" Similar to https://github.com/tpope/vim-markdown/issues/154
" setlocal foldexpr=AIChatFold() foldmethod=expr foldtext=AIChatFoldText()
augroup AichatFold
autocmd! * <buffer>
autocmd vim_ai BufWinEnter <buffer> setlocal foldexpr=AIChatFold() foldmethod=expr foldtext=AIChatFoldText()
augroup END

if exists('b:undo_ftplugin')
let b:undo_ftplugin .= "|setl foldexpr< foldmethod< foldtext<"
else
let b:undo_ftplugin = "|setl foldexpr< foldmethod< foldtext<"
endif

if exists('s:loaded_functions') || &cp
finish
endif
let s:loaded_functions = 1

function! AIChatFold() abort
return getline(v:lnum) =~# '^>>> user$' ? '>1' : '='
endfunction

function! AIChatFoldText() abort
"get first non-blank line
let fs = nextnonblank(v:foldstart + 1)
if fs > v:foldend
let head = getline(v:foldstart)
else
let head = substitute(getline(fs), '\t', repeat(' ', &tabstop), 'g')
endif
unlet fs

let foldsize = (v:foldend - v:foldstart + 1)
let digits = len(string(line('$')))
let foldsize = printf("%" . digits . "s", foldsize)
let tail = '[' . foldsize . ' lines]'

" " truncate foldtext according to window width
let maxWidth = winwidth(0) - &foldcolumn - (&number ? &numberwidth : 0) - (&signcolumn is# 'yes' ? 2 : 0)
let maxLengthHead = maxWidth - strwidth(tail)
if strwidth(head) > maxLengthHead
let cutLengthHead = maxLengthHead - strwidth('..')
if cutLengthHead < 0
let cutLengthHead = 0
endif
let head = strpart(head, 0, cutLengthHead) . '..'
endif

let middle = repeat(' ', maxWidth - strwidth(head . tail))

return head . middle . tail
endfunction
117 changes: 117 additions & 0 deletions ftplugin/aichat/movement.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
" add markdown pairs and >>> / <<<
setlocal matchpairs-=<:>
let b:match_words = &l:matchpairs .
\ ',' . '\%(^\|[ (/]\)\@<="' . ':' . '"\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=''' . ':' . '''\ze\%($\|[ )/.\,;\:?!\-]\)'
let b:match_words .=
\ ',' . '\%(^\|[ (/]\)\@<=\*[^*]' . ':' . '[^*]\@<=\*\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=\*\*' . ':' . '\*\*\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=\*\*\*' . ':' . '\*\*\*\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=_[^_]' . ':' . '[^_]\@<=_\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=__' . ':' . '__\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=___' . ':' . '___\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|[ (/]\)\@<=`[^`]' . ':' . '[^`]\@<=`\ze\%($\|[ )/.\,;\:?!\-]\)' .
\ ',' . '\%(^\|\s\)\@<=```\w\+$' . ':' . '\%(^\|\s\)\@<=```\ze$' .
\ ',' . '^>>>\s' . ':' . '^<<<\ze\s'

nnoremap <buffer><silent> ]] :<c-u>call <SID>AIChatJump2Section( v:count1, '' , 0)<CR>
nnoremap <buffer><silent> [[ :<c-u>call <SID>AIChatJump2Section( v:count1, 'b', 0)<CR>
xnoremap <buffer><silent> ]] :<c-u>call <SID>AIChatJump2Section( v:count1, '' , 1)<CR>
xnoremap <buffer><silent> [[ :<c-u>call <SID>AIChatJump2Section( v:count1, 'b', 1)<CR>
onoremap <buffer><silent> ]] :<c-u>normal ]]<CR>
onoremap <buffer><silent> [[ :<c-u>normal [[<CR>

let b:undo_ftplugin .= '|sil! nunmap <buffer> [[|sil! nunmap <buffer> ]]|sil! xunmap <buffer> [[|sil! xunmap <buffer> ]]'

" From https://github.com/plasticboy/vim-markdown/issues/282#issuecomment-725909968
xnoremap <buffer><silent> ic :<C-U>call <SID>AIChatBlockTextObj('i')<CR>
onoremap <buffer><silent> ic :<C-U>call <SID>AIChatBlockTextObj('i')<CR>

xnoremap <buffer><silent> ac :<C-U>call <SID>AIChatBlockTextObj('a')<CR>
onoremap <buffer><silent> ac :<C-U>call <SID>AIChatBlockTextObj('a')<CR>

let b:undo_ftplugin .= '|sil! ounmap <buffer> ic|sil! ounmap <buffer> ac|sil! xunmap <buffer> ic|sil! xunmap <buffer> ac'

" The rest of the file needs to be :sourced only once per session.
if exists('s:loaded_functions') || &cp
finish
endif
let s:loaded_functions = 1

function! s:AIChatJump2Section( cnt, dir, vis ) abort
if a:vis
normal! gv
endif

let i = 0
let pattern = '\v^\>{3,3} user$|^\<{3,3} assistant$'
let flags = 'W' . a:dir
while i < a:cnt && search( pattern, flags ) > 0
let i = i+1
endwhile
endfunction

function! s:AIChatBlockTextObj(type) abort
" the parameter type specify whether it is inner text objects or arround
" text objects.
let start_row = searchpos('\v^\>{3,3} user$|^\<{3,3} assistant$', 'bn')[0]
let end_row = searchpos('\v^\>{3,3} user$|^\<{3,3} assistant$', 'n')[0]

let buf_num = bufnr('%')
if a:type ==# 'i'
let start_row += 1
let end_row -= 1
endif
" echo a:type start_row end_row

call setpos("'<", [buf_num, start_row, 1, 0])
call setpos("'>", [buf_num, end_row, 1, 0])
execute 'normal! `<V`>'
endfunction
" See also https://github.com/tpope/vim-markdown/commit/191438f3582a532b72c9f8a1d6c0477050ccddef
nnoremap <buffer><silent> ]] :<c-u>call <SID>AIChatJump2Section( v:count1, '' , 0)<CR>
nnoremap <buffer><silent> [[ :<c-u>call <SID>AIChatJump2Section( v:count1, 'b', 0)<CR>
xnoremap <buffer><silent> ]] :<c-u>call <SID>AIChatJump2Section( v:count1, '' , 1)<CR>
xnoremap <buffer><silent> [[ :<c-u>call <SID>AIChatJump2Section( v:count1, 'b', 1)<CR>
onoremap <buffer><silent> ]] :<c-u>normal ]]<CR>
onoremap <buffer><silent> [[ :<c-u>normal [[<CR>
let b:undo_ftplugin .= '|sil! nunmap <buffer> [[|sil! nunmap <buffer> ]]|sil! xunmap <buffer> [[|sil! xunmap <buffer> ]]'
" From https://github.com/plasticboy/vim-markdown/issues/282#issuecomment-725909968
xnoremap <buffer><silent> ic :<C-U>call <SID>AIChatBlockTextObj('i')<CR>
onoremap <buffer><silent> ic :<C-U>call <SID>AIChatBlockTextObj('i')<CR>

xnoremap <buffer><silent> ac :<C-U>call <SID>AIChatBlockTextObj('a')<CR>
onoremap <buffer><silent> ac :<C-U>call <SID>AIChatBlockTextObj('a')<CR>
let b:undo_ftplugin .= '|sil! ounmap <buffer> ic|sil! ounmap <buffer> ac|sil! xunmap <buffer> ic|sil! xunmap <buffer> ac'
endfunction

function s:AIChatJump2Section( cnt, dir, vis ) abort
if a:vis
normal! gv
endif

let i = 0
let pattern = '\v^\>{3,3} user$|^\<{3,3} assistant$'
let flags = 'W' . a:dir
while i < a:cnt && search( pattern, flags ) > 0
let i = i+1
endwhile
endfunction

function s:AIChatBlockTextObj(type) abort
" the parameter type specify whether it is inner text objects or arround
" text objects.
let start_row = searchpos('\v^\>{3,3} user$|^\<{3,3} assistant$', 'bn')[0]
let end_row = searchpos('\v^\>{3,3} user$|^\<{3,3} assistant$', 'n')[0]

let buf_num = bufnr('%')
if a:type ==# 'i'
let start_row += 1
let end_row -= 1
endif
" echo a:type start_row end_row

call setpos("'<", [buf_num, start_row, 1, 0])
call setpos("'>", [buf_num, end_row, 1, 0])
execute 'normal! `<V`>'
endfunction
2 changes: 1 addition & 1 deletion ftplugin/aichat.vim → ftplugin/aichat/syntax.vim
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function! s:MarkdownClearSyntaxVariables()
endif
endfunction

augroup Aichat
augroup AichatSyntax
autocmd! * <buffer>
autocmd BufWinEnter <buffer> call s:MarkdownRefreshSyntax(1)
autocmd BufUnload <buffer> call s:MarkdownClearSyntaxVariables()
Expand Down