summaryrefslogtreecommitdiff
path: root/runtime/indent/falcon.vim
blob: 41f8f3470574333d4c159fd1c9208bb52fca86ff (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
" Vim indent file
" Language: Falcon
" Maintainer: Steven Oliver <oliver.steven@gmail.com>
" Website: https://steveno@github.com/steveno/falconpl-vim.git
" Credits: Thanks to the ruby.vim authors, I borrow a lot!
" Previous Maintainer: Brent A. Fulgham <bfulgham@debian.org>
" -----------------------------------------------------------
" GetLatestVimScripts: 2752 1 :AutoInstall: falcon.vim

"======================================
"       SETUP
"======================================

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

setlocal nosmartindent

" Setup indent function and when to use it
setlocal indentexpr=FalconGetIndent()
setlocal indentkeys=0{,0},0),0],!^F,o,O,e
setlocal indentkeys+==~case,=~catch,=~default,=~elif,=~else,=~end,=~\"

" Define the appropriate indent function but only once
if exists("*FalconGetIndent")
    finish
endif

let s:cpo_save = &cpo
set cpo&vim

"======================================
"       VARIABLES
"======================================

" Regex of syntax group names that are strings AND comments
let s:syng_strcom = '\<falcon\%(String\|StringEscape\|Comment\)\>'

" Regex of syntax group names that are strings
let s:syng_string = '\<falcon\%(String\|StringEscape\)\>'

" Keywords to indent on
let s:falcon_indent_keywords = '^\s*\(case\|catch\|class\|enum\|default\|elif\|else' .
    \ '\|for\|function\|if.*"[^"]*:.*"\|if \(\(:\)\@!.\)*$\|loop\|object\|select' .
    \ '\|switch\|try\|while\|\w*\s*=\s*\w*([$\)'

" Keywords to deindent on
let s:falcon_deindent_keywords = '^\s*\(case\|catch\|default\|elif\|else\|end\)'

"======================================
"       FUNCTIONS
"======================================

" Check if the character at lnum:col is inside a string
function s:IsInStringOrComment(lnum, col)
    return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom
endfunction

"======================================
"       INDENT ROUTINE
"======================================

function FalconGetIndent()
    " Get the line to be indented
    let cline = getline(v:lnum)

    " Don't reindent comments on first column
    if cline =~ '^\/\/'
        return 0
    endif

    " Find the previous non-blank line
    let lnum = prevnonblank(v:lnum - 1)

    " Use zero indent at the top of the file
    if lnum == 0
        return 0
    endif

    let prevline=getline(lnum)
    let ind = indent(lnum)
    let chg = 0

    " If we are in a multi-line string or line-comment, don't do anything
    if s:IsInStringOrComment(v:lnum, matchend(cline, '^\s*') + 1 )
        return indent('.')
    endif

    " If the start of the line equals a double quote, then indent to the
    " previous lines first double quote
    if cline =~? '^\s*"'
        let chg = chg + &sw
    endif

    " If previous line started with a double quote and this one
    " doesn't, unindent
    if prevline =~? '^\s*"' && cline =~? '^\s*'
        let chg = chg - &sw
    endif

    " Indent if proper keyword
    if prevline =~? s:falcon_indent_keywords
        let chg = &sw
    " If previous line opened a parenthesis, and did not close it, indent
    elseif prevline =~ '^.*(\s*[^)]*\((.*)\)*[^)]*$'
        " Make sure this isn't just a function split between two lines
        if prevline =~ ',\s*$'
            return indent(prevnonblank(v:lnum - 1)) + &sw
        else
            return match(prevline, '(.*\((.*)\|[^)]\)*.*$') + 1
        endif
    elseif prevline =~ '^[^(]*)\s*$'
        " This line closes a parenthesis. Finds opening.
        let curr_line = prevnonblank(lnum - 1)
        while curr_line >= 0
            let str = getline(curr_line)
            if str !~ '^.*(\s*[^)]*\((.*)\)*[^)]*$'
                let curr_line = prevnonblank(curr_line - 1)
            else
                break
            endif
        endwhile
        if curr_line < 0
            return -1
        endif
        let ind = indent(curr_line)
    endif

    " If previous line ends in a semi-colon reset indent to previous
    " lines setting
    if prevline =~? ';\s*$' && prevnonblank(prevline) =~? ',\s*$'
        return chg = chg - (2 * &sw)
    endif

    " If previous line ended in a comma, indent again
    if prevline =~? ',\s*$'
        let chg = chg + &sw
    endif

    " If previous line ended in a =>, indent again
    if prevline =~? '=>\s*$'
        let chg = chg + &sw
    endif

    " Deindent on proper keywords
    if cline =~? s:falcon_deindent_keywords
        let chg = chg - &sw
    endif

    return ind + chg
endfunction

let &cpo = s:cpo_save
unlet s:cpo_save

" vim: set sw=4 sts=4 et tw=80 :