• R/O
  • HTTP
  • SSH
  • HTTPS

kink.vim: Commit

Vim Plugins for Kink Programming Language


Commit MetaInfo

Revision208a1c5cd32fe15a88aa7db8a85702c003fe7c6b (tree)
Time2017-02-04 20:44:12
AuthorMiyakawa Taku <miyakawa.taku@gmai...>
CommiterMiyakawa Taku

Log Message

robuster indentation

Change Summary

Incremental Difference

--- a/indent/kink.vim
+++ b/indent/kink.vim
@@ -1,7 +1,7 @@
11 " Vim indent file for Kink
2-" Language: Kink (http://code.google.com/p/kink-lang/)
2+" Language: Kink (https://bitbucket.org/kink/kink)
33 " Maintainer: Miyakawa Taku <miyakawa.taku@gmail.com>
4-" Last Change: 2014-10-23
4+" Last Change: 2017-02-04
55
66 " Copyright (c) 2013- Miyakawa Taku
77 "
@@ -34,76 +34,159 @@ setlocal nolisp
3434 setlocal autoindent
3535
3636 setlocal indentexpr=GetKinkIndent(v:lnum)
37-setlocal indentkeys=0},0),0=],0=*),0=*],!^F,o,O
38-
39-" Defines the function only once.
40-if exists("*GetKinkIndent")
41- finish
42-endif
37+setlocal indentkeys=0},0),0=],!^F,o,O
4338
4439 let s:save_cpo = &cpo
4540 set cpo&vim
4641
42+let s:skip = 'has("syntax_items") && synIDattr(synID(line("."), col("."), 1), "name") =~ "String\\|Comment"'
43+
4744 " Returns the indent
48-function! GetKinkIndent(line_number)
49- " No indent in a string
50- if has('syntax_items') && synIDattr(synID(a:line_number, 1, 1), "name") =~ "String"
45+function! GetKinkIndent(line_no)
46+ let prev_line_no = prevnonblank(a:line_no - 1)
47+ if s:in_comment_or_string() || prev_line_no == 0
5148 return -1
5249 endif
5350
54- " Previous non empty line
55- let prev_line_number = prevnonblank(a:line_number - 1)
56- if prev_line_number == 0
57- return 0
51+ if getline(a:line_no) =~ '^\s*[\]})]'
52+ " The current line is closing a brace/paren/bracket
53+ let [open_line_no, open_col_no] = s:get_opener_pos_for_first_closer_in_line(a:line_no)
54+ if open_line_no <= 0
55+ " No corresponding opener
56+ return -1
57+ else
58+ " Indent based on the opener
59+ let [ignored, base_indent] = s:get_base_lineno_and_indent(open_line_no)
60+ let remaining_openers = s:get_remaining_openers(open_line_no, open_col_no)
61+ return base_indent + &shiftwidth * remaining_openers
62+ endif
63+ else
64+ " Indent based on the previous line
65+ let [base_linenno, base_indent] = s:get_base_lineno_and_indent(prev_line_no)
66+ let openers = s:get_openers_till(base_linenno, a:line_no)
67+ return base_indent + &shiftwidth * openers
5868 endif
69+endfunction
70+
71+" Returns the position of the opener corresponding to the
72+" opener at the head of the current line.
73+" Or returns [0, 0] if such an opener does not exist.
74+function! s:get_opener_pos_for_first_closer_in_line(line_no)
75+ let closing = matchstr(getline(a:line_no), '[\]})]')
76+ let [op_pattern, cl_pattern] = s:patterns_for_closing(closing)
77+ call cursor(a:line_no, 1)
78+ return searchpairpos(op_pattern, '', cl_pattern, 'bnW', s:skip)
79+endfunction
80+
81+" Returns the opener-closer patterns pair for the character of the opener.
82+function! s:patterns_for_opening(opening)
83+ let op_pattern = (a:opening == '[' ? '\[' : a:opening)
84+ let cl_pattern = (a:opening == '{' ? '}' : a:opening == '[' ? ']' : ')')
85+ return [op_pattern, cl_pattern]
86+endfunction
87+
88+" Returns the opener-closer patterns pair for the character of the closer.
89+function! s:patterns_for_closing(closing)
90+ let op_pattern = (a:closing == '}' ? '{' : a:closing == ']' ? '\[' : '(')
91+ return [op_pattern, a:closing]
92+endfunction
93+
94+" Returns [base_lineno, base_indent].
95+function!s:get_base_lineno_and_indent(line_no)
96+ call cursor(a:line_no, 1)
97+ call cursor(a:line_no, col('$'))
98+ let ln = a:line_no
99+ let search_option = 'cbW'
100+ while search('[\]})]', search_option, a:line_no)
101+ let search_option = 'bW'
102+ if s:in_comment_or_string()
103+ continue
104+ endif
59105
60- let prev_indent = indent(prev_line_number)
61- let skip = 'has("syntax_items") && synIDattr(synID(line("."), col("."), 1), "name") =~ "String\\|Comment"'
62-
63- " Does the current line close a paren/brace/brancket?
64- let cur_line = getline(a:line_number)
65- if cur_line =~ '^\s*\(}\|\*\?]\|\*\?)\)'
66- let opening_pattern = (cur_line =~ '^\s*}' ? '{' : cur_line =~ '^\s*\*\?]' ? '\[' : '(')
67- let closing_pattern = (opening_pattern == '{' ? '}' : opening_pattern == '\[' ? ']' : ')')
68- call cursor(a:line_number, 1)
69- let open_line_number = searchpair(opening_pattern, '', closing_pattern, 'bnW', skip)
70- return (open_line_number > 0 ? indent(open_line_number) : prev_indent)
106+ let closing = s:get_current_char()
107+ let [op_pattern, cl_pattern] = s:patterns_for_closing(closing)
108+ let [open_lineno, open_colno] = searchpairpos(op_pattern, '', cl_pattern, 'bW', s:skip)
109+ if open_lineno == 0
110+ " no corresponding opener
111+ break
112+ elseif open_lineno != a:line_no
113+ " corresponding opener in another line
114+ let [ignored, base_indent] = s:get_base_lineno_and_indent(open_lineno)
115+ let indent = base_indent + &shiftwidth * s:get_remaining_openers(open_lineno, open_colno)
116+ return [a:line_no, indent]
117+ endif
118+ endwhile
119+
120+ if s:in_string(line('.'), 1)
121+ return s:get_base_lineno_and_indent(a:line_no - 1)
122+ else
123+ return [a:line_no, indent(a:line_no)]
71124 endif
125+endfunction
72126
73- " Does the previous line open a paren/brace/brancket?
74- call cursor(prev_line_number, 1)
75- let search_option = 'cW'
76- while search('{\|\[\|(', search_option, prev_line_number) > 0
127+" Returns the number of openers,
128+" which is opening till the specified line number.
129+function! s:get_openers_till(line_no, open_till_lineno)
130+ let openers = 0
131+ call cursor(a:line_no, 1)
132+ let search_option = 'cW'
133+ while search('[\[{(]', search_option, a:open_till_lineno - 1)
77134 let search_option = 'W'
78- if has('syntax_items') && synIDattr(synID(prev_line_number, col('.'), 1), "name") =~ 'String\|Comment'
135+ if s:in_comment_or_string()
79136 continue
80137 endif
81- let opening = getline(line('.'))[col('.') - 1]
82- let opening_pattern = (opening == '[' ? '\[' : opening)
83- let closing_pattern = (opening == '{' ? '}' : opening == '[' ? ']' : ')')
84- if searchpair(opening_pattern, '', closing_pattern, 'W', skip) != prev_line_number
85- return prev_indent + &shiftwidth
138+
139+ let opening = s:get_current_char()
140+ let [op_pattern, cl_pattern] = s:patterns_for_opening(opening)
141+ let [closing_lineno, closing_colno] = searchpairpos(op_pattern, '', cl_pattern, 'nW', s:skip)
142+ if closing_lineno <= 0 || closing_lineno >= a:open_till_lineno
143+ let openers += 1
144+ else
145+ call cursor(closing_lineno, closing_colno)
86146 endif
87147 endwhile
88148
89- " Does the previous line close a paren/brace/brancket?
90- call cursor(prev_line_number, 999999)
91- let search_option = 'cbW'
92- while search('}\|]\|)', search_option, prev_line_number) > 0
93- let search_option = 'bW'
94- if has('syntax_items') && synIDattr(synID(prev_line_number, col('.'), 1), "name") =~ 'String\|Comment'
149+ return openers
150+endfunction
151+
152+" Retunrs the number of openers which is not closed within the line,
153+" and placed before the stop column.
154+function! s:get_remaining_openers(line_no, shown_before_colno)
155+ let openers = 0
156+ call cursor(a:line_no, 1)
157+ let search_option = 'cW'
158+ while search('[\[{(]', search_option, a:line_no) > 0 && col('.') < a:shown_before_colno
159+ let search_option = 'W'
160+ if s:in_comment_or_string()
95161 continue
96162 endif
97- let closing_pattern = getline(line('.'))[col('.') - 1]
98- let opening_pattern = (closing_pattern == '}' ? '{' : closing_pattern == ']' ? '\[' : '(')
99- let opening_line_number = searchpair(opening_pattern, '', closing_pattern, 'bW', skip)
100- if opening_line_number != prev_line_number
101- return indent(opening_line_number)
102- end
163+
164+ let opening = s:get_current_char()
165+ let [op_pattern, cl_pattern] = s:patterns_for_opening(opening)
166+ let [closing_lineno, closing_colno] = searchpairpos(op_pattern, '', cl_pattern, 'nW', s:skip)
167+ if closing_lineno != a:line_no
168+ let openers += 1
169+ else
170+ call cursor(closing_lineno, closing_colno)
171+ endif
103172 endwhile
104173
105- return prev_indent
174+ return openers
175+endfunction
176+
177+" Returns the character on the cursor.
178+function! s:get_current_char()
179+ return getline(line('.'))[col('.') - 1]
180+endfunction
181+
182+" Returns true if the cursor is in a string or a comment.
183+function! s:in_comment_or_string()
184+ return has('syntax_items') && synIDattr(synID(line('.'), col('.'), 1), "name") =~ 'String\|Comment'
185+endfunction
106186
187+" Returns true if the position is in a string.
188+function! s:in_string(lineno, colno)
189+ return has('syntax_items') && synIDattr(synID(a:lineno, a:colno, 1), "name") =~ 'String'
107190 endfunction
108191
109192 let &cpo = s:save_cpo
Show on old repository browser