summaryrefslogtreecommitdiffstats
path: root/after/indent/objc.vim
blob: 13d4d32d17502cf71ff038c41c829e8ecc0acc1a (plain) (blame)
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
if !has_key(g:polyglot_is_disabled, 'objc')
  finish
endif

" Vim indent file
" Language:	Objective-C
" Maintainer:	Bjorn Winckler <bjorn.winckler@gmail.com>
" Last Change:	2012 Jan 01

" Ensure 'cpo' is set to Vim default values and restore later
let s:save_cpo = &cpo
set cpo&vim

" Only load this indent file when no other was loaded.
"if exists("b:did_indent")
"    finish
"endif
"let b:did_indent = 1
"setlocal cindent

setl indentkeys=0{,0},:,0#,!^F,o,O,e,<:>

setlocal indentexpr=GetObjCIndentImproved()

" Top level statements which should not be indented, and which should not
" cause next (non-blank) line to be indented either.
let s:topLev = '^\s*@\%(class\|end\|implementation\|interface\|protocol\|\)\>'

function! GetObjCIndentImproved()
  " NOTE: Ignore leading white space to avoid having to deal with space vs.
  " tab issues.  Rely on the indent() function instead.
  let thisLine = substitute(getline(v:lnum), '^\s*', '', '')

  if thisLine =~# s:topLev || getline(prevnonblank(v:lnum - 1)) =~# s:topLev
    return 0
  endif

  " If current line looks like an argument to a message dispatch, then line
  " up colon with previous line.  This will indent the second line so that
  " the colons line up in
  "
  "   [obj firstParameter:value
  "                paramB:value2];
  "
  " but it will not line up colons in
  "
  "   if ([obj something:here])
  "       [obj other:here];
  "
  let thisColon = match(thisLine, '^\s*\K\k*\zs:')
  if thisColon > 0
    let prevLine = substitute(getline(v:lnum - 1), '^\s*', '', '')
    let prevColon = match(prevLine, ':')
    if prevColon > 0
      " Try to align colons, always making sure line is indented at least
      " one shiftwidth more than the indentation at the beginning of the
      " message.  Avoids situations like this:
      "
      "     if ([obj a:x
      "  aLongParameter:y])
      "
      let [lnum,lcol] = searchpairpos('\[', '', '\]', 'b', 0,
            \ max([1, v:lnum - 10]))
      let minInd = &sw + (lnum > 0 ? indent(lnum) : 0)
      let alignedInd = indent(v:lnum - 1) + prevColon - thisColon
      return alignedInd > minInd ? alignedInd : minInd
    endif
  endif

  let prevLnum = v:lnum - 1
  let ind      = indent(prevLnum)

  " Indent one shiftwidth after opening block, e.g.:
  "
  "   call_func_with_block(param, ^{
  "       do_stuff();
  "   });
  "
  let blockPat = '\^\s*\(([^)]*)\)\?\s*{$'
  if thisLine =~ '^}'
    norm '^%'
    if getline(".") =~ blockPat
      return indent(".")
    endif
  endif

  if getline(prevLnum) =~ blockPat
    return ind + &sw
  endif

  return cindent(v:lnum)
endfunction


" Restore 'cpo' options
let &cpo = s:save_cpo
unlet s:save_cpo