diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-09-19 18:50:13 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-09-19 18:50:13 +0200 |
commit | 1d59aa1fdfb191d9872ff87eb94652acd374b293 (patch) | |
tree | cff1ad6b4c19ca301a4aea1b0227c85305ac560f /runtime/indent/erlang.vim | |
parent | a05e524f3aa8eadc2dbd0ad8ff6db9407ac7ac7e (diff) |
Update runtime files.
Diffstat (limited to 'runtime/indent/erlang.vim')
-rw-r--r-- | runtime/indent/erlang.vim | 147 |
1 files changed, 120 insertions, 27 deletions
diff --git a/runtime/indent/erlang.vim b/runtime/indent/erlang.vim index 9228f18683..625cfde0c1 100644 --- a/runtime/indent/erlang.vim +++ b/runtime/indent/erlang.vim @@ -4,9 +4,9 @@ " Contributors: Edwin Fine <efine145_nospam01 at usa dot net> " Pawel 'kTT' Salata <rockplayer.pl@gmail.com> " Ricardo Catalinas Jiménez <jimenezrick@gmail.com> -" Last Update: 2013-Jul-21 +" Last Update: 2020-Jun-11 " License: Vim license -" URL: https://github.com/hcs42/vim-erlang +" URL: https://github.com/vim-erlang/vim-erlang-runtime " Note About Usage: " This indentation script works best with the Erlang syntax file created by @@ -56,7 +56,8 @@ endfunction " Line tokenizer library {{{1 " ====================== -" Indtokens are "indentation tokens". +" Indtokens are "indentation tokens". See their exact format in the +" documentaiton of the s:GetTokensFromLine function. " Purpose: " Calculate the new virtual column after the given segment of a line. @@ -119,9 +120,10 @@ endfunction " Returns: " indtokens = [indtoken] " indtoken = [token, vcol, col] -" token = string (examples: 'begin', '<variable>', '}') -" vcol = integer (the virtual column of the first character of the token) -" col = integer +" token = string (examples: 'begin', '<quoted_atom>', '}') +" vcol = integer (the virtual column of the first character of the token; +" counting starts from 0) +" col = integer (counting starts from 0) function! s:GetTokensFromLine(line, string_continuation, atom_continuation, \tabstop) @@ -386,9 +388,12 @@ endfunction " lnum: integer " direction: 'up' | 'down' " Returns: -" result: [] -- the result is an empty list if we hit the beginning or end -" of the file -" | indtoken +" result: [[], 0, 0] +" -- the result is an empty list if we hit the beginning or end of +" the file +" | [indtoken, lnum, i] +" -- the content, lnum and token index of the next (or previous) +" indtoken function! s:FindIndToken(lnum, dir) let lnum = a:lnum while 1 @@ -396,9 +401,12 @@ function! s:FindIndToken(lnum, dir) let [lnum, indtokens] = s:TokenizeLine(lnum, a:dir) if lnum ==# 0 " We hit the beginning or end of the file - return [] + return [[], 0, 0] elseif !empty(indtokens) - return indtokens[a:dir ==# 'up' ? -1 : 0] + " We found a non-empty line. If we were moving up, we return the last + " token of this line. Otherwise we return the first token if this line. + let i = (a:dir ==# 'up' ? len(indtokens) - 1 : 0) + return [indtokens[i], lnum, i] endif endwhile endfunction @@ -417,7 +425,7 @@ function! s:PrevIndToken(lnum, i) " If the current line has a previous token, return that if a:i > 0 - return s:all_tokens[a:lnum][a:i - 1] + return [s:all_tokens[a:lnum][a:i - 1], a:lnum, a:i - 1] else return s:FindIndToken(a:lnum, 'up') endif @@ -437,7 +445,7 @@ function! s:NextIndToken(lnum, i) " If the current line has a next token, return that if len(s:all_tokens[a:lnum]) > a:i + 1 - return s:all_tokens[a:lnum][a:i + 1] + return [s:all_tokens[a:lnum][a:i + 1], a:lnum, a:i + 1] else return s:FindIndToken(a:lnum, 'down') endif @@ -518,7 +526,9 @@ endfunction " ok. % IsLineAtomContinuation = false function! s:IsLineAtomContinuation(lnum) if has('syntax_items') - return synIDattr(synID(a:lnum, 1, 0), 'name') =~# '^erlangQuotedAtom' + let syn_name = synIDattr(synID(a:lnum, 1, 0), 'name') + return syn_name =~# '^erlangQuotedAtom' || + \ syn_name =~# '^erlangQuotedRecord' else return 0 endif @@ -535,7 +545,7 @@ endfunction " is_standalone: bool function! s:IsCatchStandalone(lnum, i) call s:Log(' IsCatchStandalone called: lnum=' . a:lnum . ', i=' . a:i) - let prev_indtoken = s:PrevIndToken(a:lnum, a:i) + let [prev_indtoken, _, _] = s:PrevIndToken(a:lnum, a:i) " If we hit the beginning of the file, it is not a catch in a try block if prev_indtoken == [] @@ -544,7 +554,7 @@ function! s:IsCatchStandalone(lnum, i) let prev_token = prev_indtoken[0] - if prev_token =~# '[A-Z_@0-9]' + if prev_token =~# '^[A-Z_@0-9]' let is_standalone = 0 elseif prev_token =~# '[a-z]' if index(['after', 'and', 'andalso', 'band', 'begin', 'bnot', 'bor', 'bsl', @@ -659,11 +669,14 @@ endfunction " stack: [token] " token: string " stored_vcol: integer +" lnum: the line number of the "end of clause" mark (or 0 if we hit the +" beginning of the file) +" i: the index of the "end of clause" token within its own line " Returns: " result: [should_return, indent] " should_return: bool -- if true, the caller should return `indent` to Vim " indent -- integer -function! s:BeginningOfClauseFound(stack, token, stored_vcol) +function! s:BeginningOfClauseFound(stack, token, stored_vcol, lnum, i) if !empty(a:stack) && a:stack[0] ==# 'when' call s:Log(' BeginningOfClauseFound: "when" found in stack') call s:Pop(a:stack) @@ -681,13 +694,45 @@ function! s:BeginningOfClauseFound(stack, token, stored_vcol) return [1, a:stored_vcol + shiftwidth()] elseif a:stack[0] ==# ';' call s:Pop(a:stack) - if empty(a:stack) - call s:Log(' Stack is ["->", ";"], so LTI is in a function head ' . - \'-> return') - return [0, a:stored_vcol] - else + + if !empty(a:stack) return [1, s:UnexpectedToken(a:token, a:stack)] endif + + if a:lnum ==# 0 + " Set lnum and i to be NextIndToken-friendly + let lnum = 1 + let i = -1 + else + let lnum = a:lnum + let i = a:i + endif + + " Are we after a "-spec func() ...;" clause? + let [next1_indtoken, next1_lnum, next1_i] = s:NextIndToken(lnum, i) + if !empty(next1_indtoken) && next1_indtoken[0] =~# '-' + let [next2_indtoken, next2_lnum, next2_i] = + \s:NextIndToken(next1_lnum, next1_i) + if !empty(next2_indtoken) && next2_indtoken[0] =~# 'spec' + let [next3_indtoken, next3_lnum, next3_i] = + \s:NextIndToken(next2_lnum, next2_i) + if !empty(next3_indtoken) + let [next4_indtoken, next4_lnum, next4_i] = + \s:NextIndToken(next3_lnum, next3_i) + if !empty(next4_indtoken) + " Yes, we are. + call s:Log(' Stack is ["->", ";"], so LTI is in a "-spec" ' . + \'attribute -> return') + return [1, next4_indtoken[1]] + endif + endif + endif + endif + + call s:Log(' Stack is ["->", ";"], so LTI is in a function head ' . + \'-> return') + return [1, a:stored_vcol] + else return [1, s:UnexpectedToken(a:token, a:stack)] endif @@ -714,7 +759,7 @@ function! s:SearchEndPair(lnum, curr_col) return s:SearchPair( \ a:lnum, a:curr_col, \ '\C\<\%(case\|try\|begin\|receive\|if\)\>\|' . - \ '\<fun\>\%(\s\|\n\|%.*$\)*(', + \ '\<fun\>\%(\s\|\n\|%.*$\|[A-Z_@][a-zA-Z_@]*\)*(', \ '', \ '\<end\>') endfunction @@ -756,7 +801,7 @@ function! s:ErlangCalcIndent2(lnum, stack) " Hit the start of the file if lnum ==# 0 let [ret, res] = s:BeginningOfClauseFound(stack, 'beginning_of_file', - \stored_vcol) + \stored_vcol, 0, 0) if ret | return res | endif return 0 @@ -775,7 +820,8 @@ function! s:ErlangCalcIndent2(lnum, stack) endif if token ==# '<end_of_clause>' - let [ret, res] = s:BeginningOfClauseFound(stack, token, stored_vcol) + let [ret, res] = s:BeginningOfClauseFound(stack, token, stored_vcol, + \lnum, i) if ret | return res | endif if stored_vcol ==# -1 @@ -787,7 +833,7 @@ function! s:ErlangCalcIndent2(lnum, stack) endif elseif stack == ['prev_term_plus'] - if token =~# '[a-zA-Z_@]' || + if token =~# '[a-zA-Z_@#]' || \ token ==# '<string>' || token ==# '<string_start>' || \ token ==# '<quoted_atom>' || token ==# '<quoted_atom_start>' call s:Log(' previous token found: curr_vcol + plus = ' . @@ -917,9 +963,18 @@ function! s:ErlangCalcIndent2(lnum, stack) if ret | return res | endif elseif token ==# 'fun' - let next_indtoken = s:NextIndToken(lnum, i) + let [next_indtoken, next_lnum, next_i] = s:NextIndToken(lnum, i) call s:Log(' Next indtoken = ' . string(next_indtoken)) + if !empty(next_indtoken) && next_indtoken[0] =~# '^[A-Z_@]' + " The "fun" is followed by a variable, so we might have a named fun: + " "fun Fun() -> ok end". Thus we take the next token to decide + " whether this is a function definition ("fun()") or just a function + " reference ("fun Mod:Fun"). + let [next_indtoken, _, _] = s:NextIndToken(next_lnum, next_i) + call s:Log(' Next indtoken = ' . string(next_indtoken)) + endif + if !empty(next_indtoken) && next_indtoken[0] ==# '(' " We have an anonymous function definition " (e.g. "fun () -> ok end") @@ -1327,6 +1382,26 @@ function! ErlangIndent() return -1 endif + " If the line starts with the comment, and so is the previous non-blank line + if currline =~# '^\s*%' + let lnum = prevnonblank(v:lnum - 1) + if lnum ==# 0 + call s:Log('First non-empty line of the file -> return 0.') + return 0 + else + let ml = matchlist(getline(lnum), '^\(\s*\)%') + " If the previous line also starts with a comment, then return the same + " indentation that line has. Otherwise exit from this special "if" and + " don't care that the current line is a comment. + if !empty(ml) + let new_col = s:CalcVCol(ml[1], 0, len(ml[1]) - 1, 0, &tabstop) + call s:Log('Comment line after another comment line -> ' . + \'use same indent: ' . new_col) + return new_col + endif + endif + endif + let ml = matchlist(currline, \'^\(\s*\)\(\%(end\|of\|catch\|after\)\>\|[)\]}]\|>>\)') @@ -1381,6 +1456,24 @@ function! ErlangIndent() endfunction +" ErlangShowTokensInLine functions {{{1 +" ================================ + +" These functions are useful during development. + +function! ErlangShowTokensInLine(line) + echo "Line: " . a:line + let indtokens = s:GetTokensFromLine(a:line, 0, 0, &tabstop) + echo "Tokens:" + for it in indtokens + echo it + endfor +endfunction + +function! ErlangShowTokensInCurrentLine() + return ErlangShowTokensInLine(getline('.')) +endfunction + " Cleanup {{{1 " ======= |