graphql.vim 2.8 KB

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