summaryrefslogtreecommitdiff
path: root/ftplugin/aichat.vim
blob: 6776664eab41f100f67c804a53d656cd92358a44 (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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
" Highlighting code blocks in .aichat files
" Inspired and based on https://github.com/preservim/vim-markdown

if exists('g:vim_markdown_fenced_languages')
  let s:filetype_dict = {}
  for s:filetype in g:vim_markdown_fenced_languages
    let key = matchstr(s:filetype, '[^=]*')
    let val = matchstr(s:filetype, '[^=]*$')
    let s:filetype_dict[key] = val
  endfor
else
  let s:filetype_dict = {
        \ 'c++': 'cpp',
        \ 'viml': 'vim',
        \ 'bash': 'sh',
        \ 'ini': 'dosini',
        \ 'js': 'javascript',
        \ 'jsx': 'javascriptreact',
        \ 'ts': 'typescript',
        \ 'tsx': 'typescriptreact',
        \ }
endif

function! s:MarkdownHighlightSources(force)
  " Syntax highlight source code embedded in notes.
  " Look for code blocks in the current file
  let filetypes = {}
  for line in getline(1, '$')
    let ft = matchstr(line, '\(`\{3,}\|\~\{3,}\)\s*\zs[0-9A-Za-z_+-]*\ze.*')
    if !empty(ft) && ft !~# '^\d*$' | let filetypes[ft] = 1 | endif
  endfor
  if !exists('b:aichat_known_filetypes')
    let b:aichat_known_filetypes = {}
  endif
  if !exists('b:aichat_included_filetypes')
    " set syntax file name included
    let b:aichat_included_filetypes = {}
  endif
  if !a:force && (b:aichat_known_filetypes == filetypes || empty(filetypes))
    return
  endif

  " Now we're ready to actually highlight the code blocks.
  let startgroup = 'aichatCodeStart'
  let endgroup = 'aichatCodeEnd'
  for ft in keys(filetypes)
    if a:force || !has_key(b:aichat_known_filetypes, ft)
      if has_key(s:filetype_dict, ft)
        let filetype = s:filetype_dict[ft]
      else
        let filetype = ft
      endif
      let group = 'aichatSnippet' . toupper(substitute(filetype, '[+-]', '_', 'g'))
      if !has_key(b:aichat_included_filetypes, filetype)
        let include = s:SyntaxInclude(filetype)
        let b:aichat_included_filetypes[filetype] = 1
      else
        let include = '@' . toupper(filetype)
      endif
      let command_backtick = 'syntax region %s matchgroup=%s start="^\s*`\{3,}\s*%s.*$" matchgroup=%s end="\s*`\{3,}$" keepend contains=%s'
      let command_tilde    = 'syntax region %s matchgroup=%s start="^\s*\~\{3,}\s*%s.*$" matchgroup=%s end="\s*\~\{3,}$" keepend contains=%s'
      execute printf(command_backtick, group, startgroup, ft, endgroup, include)
      execute printf(command_tilde,    group, startgroup, ft, endgroup, include)
      execute printf('syntax cluster aichatNonListItem add=%s', group)

      let b:aichat_known_filetypes[ft] = 1
    endif
  endfor
endfunction

function! s:SyntaxInclude(filetype)
  " Include the syntax highlighting of another {filetype}.
  let grouplistname = '@' . toupper(a:filetype)
  " Unset the name of the current syntax while including the other syntax
  " because some syntax scripts do nothing when "b:current_syntax" is set
  if exists('b:current_syntax')
    let syntax_save = b:current_syntax
    unlet b:current_syntax
  endif
  try
    execute 'syntax include' grouplistname 'syntax/' . a:filetype . '.vim'
    execute 'syntax include' grouplistname 'after/syntax/' . a:filetype . '.vim'
  catch /E484/
    " Ignore missing scripts
  endtry
  " Restore the name of the current syntax
  if exists('syntax_save')
    let b:current_syntax = syntax_save
  elseif exists('b:current_syntax')
    unlet b:current_syntax
  endif
  return grouplistname
endfunction


function! s:IsHighlightSourcesEnabledForBuffer()
  " Enable for markdown buffers, and for liquid buffers with markdown format
  return &filetype =~# 'aichat' || get(b:, 'liquid_subtype', '') =~# 'aichat'
endfunction

function! s:MarkdownRefreshSyntax(force)
  if g:vim_ai_chat_default['ui']['code_syntax_enabled']
    call s:MarkdownHighlightSources(a:force)
  endif
endfunction

function! s:MarkdownClearSyntaxVariables()
  if exists('b:aichat_included_filetypes')
    unlet! b:aichat_included_filetypes
  endif
endfunction

augroup Aichat
  autocmd BufWinEnter *.aichat call s:MarkdownRefreshSyntax(1)
  autocmd BufUnload *.aichat call s:MarkdownClearSyntaxVariables()
  autocmd BufWritePost *.aichat call s:MarkdownRefreshSyntax(0)
  autocmd InsertEnter,InsertLeave *.aichat call s:MarkdownRefreshSyntax(0)
  autocmd CursorHold,CursorHoldI *.aichat call s:MarkdownRefreshSyntax(0)
augroup END