graphql.vim (2901B)
1 " Vim indent file 2 " Language: graphql 3 " Maintainer: Jon Parise <jon@indelible.org> 4 " Filenames: *.graphql *.graphqls *.gql 5 " URL: https://github.com/jparise/vim-graphql 6 " License: MIT <https://opensource.org/license/mit> 7 " Last Change: 2024 Dec 21 8 9 " Set our local options if indentation hasn't already been set up. 10 " This generally means we've been detected as the primary filetype. 11 if !exists('b:did_indent') 12 setlocal autoindent 13 setlocal nocindent 14 setlocal nolisp 15 setlocal nosmartindent 16 17 setlocal indentexpr=GetGraphQLIndent() 18 setlocal indentkeys=0{,0},0),0[,0],0#,!^F,o,O 19 20 let b:did_indent = 1 21 endif 22 23 " If our indentation function already exists, we have nothing more to do. 24 if exists('*GetGraphQLIndent') 25 finish 26 endif 27 28 let s:cpo_save = &cpoptions 29 set cpoptions&vim 30 31 " searchpair() skip expression that matches in comments and strings. 32 let s:pair_skip_expr = 33 \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "comment\\|string"' 34 35 " Check if the character at lnum:col is inside a string. 36 function s:InString(lnum, col) 37 return synIDattr(synID(a:lnum, a:col, 1), 'name') ==# 'graphqlString' 38 endfunction 39 40 function GetGraphQLIndent() 41 " If this is the first non-blank line, we have nothing more to do because 42 " all of our indentation rules are based on matching against earlier lines. 43 let l:prevlnum = prevnonblank(v:lnum - 1) 44 if l:prevlnum == 0 45 return 0 46 endif 47 48 " If the previous line isn't GraphQL, assume we're part of a template 49 " string and indent this new line within it. 50 let l:stack = map(synstack(l:prevlnum, 1), "synIDattr(v:val, 'name')") 51 if get(l:stack, -1) !~# '^graphql' 52 return indent(l:prevlnum) + shiftwidth() 53 endif 54 55 let l:line = getline(v:lnum) 56 57 " If this line contains just a closing bracket, find its matching opening 58 " bracket and indent the closing bracket to match. 59 let l:col = matchend(l:line, '^\s*[]})]') 60 if l:col > 0 && !s:InString(v:lnum, l:col) 61 call cursor(v:lnum, l:col) 62 63 let l:bracket = l:line[l:col - 1] 64 if l:bracket ==# '}' 65 let l:matched = searchpair('{', '', '}', 'bW', s:pair_skip_expr) 66 elseif l:bracket ==# ']' 67 let l:matched = searchpair('\[', '', '\]', 'bW', s:pair_skip_expr) 68 elseif l:bracket ==# ')' 69 let l:matched = searchpair('(', '', ')', 'bW', s:pair_skip_expr) 70 else 71 let l:matched = -1 72 endif 73 74 return l:matched > 0 ? indent(l:matched) : virtcol('.') - 1 75 endif 76 77 " If we're inside of a multiline string, continue with the same indentation. 78 if s:InString(v:lnum, matchend(l:line, '^\s*') + 1) 79 return indent(v:lnum) 80 endif 81 82 " If the previous line ended with an opening bracket, indent this line. 83 if getline(l:prevlnum) =~# '\%(#.*\)\@<![[{(]\s*$' 84 return indent(l:prevlnum) + shiftwidth() 85 endif 86 87 " Default to the existing indentation level. 88 return indent(l:prevlnum) 89 endfunction 90 91 let &cpoptions = s:cpo_save 92 unlet s:cpo_save