diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2017-09-28 22:18:09 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2017-09-28 22:18:09 +0200 | 
| commit | 27903c5b8656c796564ef073c1ebe77a2f0154e1 (patch) | |
| tree | 2b0a3a14494d7976fb79a7517706e25d2a95d080 /indent/erlang.vim | |
| parent | d5e38fa97bc50a93a66473d6cd7072fbcbadda57 (diff) | |
| download | vim-polyglot-27903c5b8656c796564ef073c1ebe77a2f0154e1.tar.gz vim-polyglot-27903c5b8656c796564ef073c1ebe77a2f0154e1.zip | |
Revert inlining basic language packv3.0.0
Diffstat (limited to 'indent/erlang.vim')
| -rw-r--r-- | indent/erlang.vim | 1394 | 
1 files changed, 0 insertions, 1394 deletions
| diff --git a/indent/erlang.vim b/indent/erlang.vim index efd4ba47..64525bbd 100644 --- a/indent/erlang.vim +++ b/indent/erlang.vim @@ -1,1397 +1,3 @@ -if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 -   -" Vim indent file -" Language:     Erlang (http://www.erlang.org) -" Author:       Csaba Hoch <csaba.hoch@gmail.com> -" 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 -" License:      Vim license -" URL:          https://github.com/hcs42/vim-erlang - -" Note About Usage: -"   This indentation script works best with the Erlang syntax file created by -"   Kreąimir Marľić (Kresimir Marzic) and maintained by Csaba Hoch. - -" Notes About Implementation: -" -" - LTI = Line to indent. -" - The index of the first line is 1, but the index of the first column is 0. - - -" Initialization {{{1 -" ============== - -" Only load this indent file when no other was loaded -" Vim 7 or later is needed -if exists("b:did_indent") || version < 700 -  finish -else -  let b:did_indent = 1 -endif - -setlocal indentexpr=ErlangIndent() -setlocal indentkeys+=0=end,0=of,0=catch,0=after,0=when,0=),0=],0=},0=>> - -" Only define the functions once -if exists("*ErlangIndent") -  finish -endif - -let s:cpo_save = &cpo -set cpo&vim - -" Logging library {{{1 -" =============== - -" Purpose: -"   Logs the given string using the ErlangIndentLog function if it exists. -" Parameters: -"   s: string -function! s:Log(s) -  if exists("*ErlangIndentLog") -    call ErlangIndentLog(a:s) -  endif -endfunction - -" Line tokenizer library {{{1 -" ====================== - -" Indtokens are "indentation tokens". - -" Purpose: -"   Calculate the new virtual column after the given segment of a line. -" Parameters: -"   line: string -"   first_index: integer -- the index of the first character of the segment -"   last_index: integer -- the index of the last character of the segment -"   vcol: integer -- the virtual column of the first character of the token -"   tabstop: integer -- the value of the 'tabstop' option to be used -" Returns: -"   vcol: integer -" Example: -"   " index:    0 12 34567 -"   " vcol:     0 45 89 -"   s:CalcVCol("\t'\tx', b", 1, 4, 4)  -> 10 -function! s:CalcVCol(line, first_index, last_index, vcol, tabstop) - -  " We copy the relevent segment of the line, otherwise if the line were -  " e.g. `"\t", term` then the else branch below would consume the `", term` -  " part at once. -  let line = a:line[a:first_index : a:last_index] - -  let i = 0 -  let last_index = a:last_index - a:first_index -  let vcol = a:vcol - -  while 0 <= i && i <= last_index - -    if line[i] ==# "\t" -      " Example (when tabstop == 4): -      " -      " vcol + tab -> next_vcol -      " 0 + tab -> 4 -      " 1 + tab -> 4 -      " 2 + tab -> 4 -      " 3 + tab -> 4 -      " 4 + tab -> 8 -      " -      " next_i - i == the number of tabs -      let next_i = matchend(line, '\t*', i + 1) -      let vcol = (vcol / a:tabstop + (next_i - i)) * a:tabstop -      call s:Log('new vcol after tab: '. vcol) -    else -      let next_i = matchend(line, '[^\t]*', i + 1) -      let vcol += next_i - i -      call s:Log('new vcol after other: '. vcol) -    endif -    let i = next_i -  endwhile - -  return vcol -endfunction - -" Purpose: -"   Go through the whole line and return the tokens in the line. -" Parameters: -"   line: string -- the line to be examined -"   string_continuation: bool -"   atom_continuation: bool -" 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 -function! s:GetTokensFromLine(line, string_continuation, atom_continuation, -                             \tabstop) - -  let linelen = strlen(a:line) " The length of the line -  let i = 0 " The index of the current character in the line -  let vcol = 0 " The virtual column of the current character -  let indtokens = [] - -  if a:string_continuation -    let i = matchend(a:line, '^\%([^"\\]\|\\.\)*"', 0) -    if i ==# -1 -      call s:Log('    Whole line is string continuation -> ignore') -      return [] -    else -      let vcol = s:CalcVCol(a:line, 0, i - 1, 0, a:tabstop) -      call add(indtokens, ['<string_end>', vcol, i]) -    endif -  elseif a:atom_continuation -    let i = matchend(a:line, "^\\%([^'\\\\]\\|\\\\.\\)*'", 0) -    if i ==# -1 -      call s:Log('    Whole line is quoted atom continuation -> ignore') -      return [] -    else -      let vcol = s:CalcVCol(a:line, 0, i - 1, 0, a:tabstop) -      call add(indtokens, ['<quoted_atom_end>', vcol, i]) -    endif -  endif - -  while 0 <= i && i < linelen - -    let next_vcol = '' - -    " Spaces -    if a:line[i] ==# ' ' -      let next_i = matchend(a:line, ' *', i + 1) - -    " Tabs -    elseif a:line[i] ==# "\t" -      let next_i = matchend(a:line, '\t*', i + 1) - -      " See example in s:CalcVCol -      let next_vcol = (vcol / a:tabstop + (next_i - i)) * a:tabstop - -    " Comment -    elseif a:line[i] ==# '%' -      let next_i = linelen - -    " String token: "..." -    elseif a:line[i] ==# '"' -      let next_i = matchend(a:line, '\%([^"\\]\|\\.\)*"', i + 1) -      if next_i ==# -1 -        call add(indtokens, ['<string_start>', vcol, i]) -      else -        let next_vcol = s:CalcVCol(a:line, i, next_i - 1, vcol, a:tabstop) -        call add(indtokens, ['<string>', vcol, i]) -      endif - -    " Quoted atom token: '...' -    elseif a:line[i] ==# "'" -      let next_i = matchend(a:line, "\\%([^'\\\\]\\|\\\\.\\)*'", i + 1) -      if next_i ==# -1 -        call add(indtokens, ['<quoted_atom_start>', vcol, i]) -      else -        let next_vcol = s:CalcVCol(a:line, i, next_i - 1, vcol, a:tabstop) -        call add(indtokens, ['<quoted_atom>', vcol, i]) -      endif - -    " Keyword or atom or variable token or number -    elseif a:line[i] =~# '[a-zA-Z_@0-9]' -      let next_i = matchend(a:line, -                           \'[[:alnum:]_@:]*\%(\s*#\s*[[:alnum:]_@:]*\)\=', -                           \i + 1) -      call add(indtokens, [a:line[(i):(next_i - 1)], vcol, i]) - -    " Character token: $<char> (as in: $a) -    elseif a:line[i] ==# '$' -      call add(indtokens, ['$.', vcol, i]) -      let next_i = i + 2 - -    " Dot token: . -    elseif a:line[i] ==# '.' - -      let next_i = i + 1 - -      if i + 1 ==# linelen || a:line[i + 1] =~# '[[:blank:]%]' -        " End of clause token: . (as in: f() -> ok.) -        call add(indtokens, ['<end_of_clause>', vcol, i]) - -      else -        " Possibilities: -        " - Dot token in float: . (as in: 3.14) -        " - Dot token in record: . (as in: #myrec.myfield) -        call add(indtokens, ['.', vcol, i]) -      endif - -    " Equal sign -    elseif a:line[i] ==# '=' -      " This is handled separately so that "=<<" will be parsed as -      " ['=', '<<'] instead of ['=<', '<']. Although Erlang parses it -      " currently in the latter way, that may be fixed some day. -      call add(indtokens, [a:line[i], vcol, i]) -      let next_i = i + 1 - -    " Three-character tokens -    elseif i + 1 < linelen && -         \ index(['=:=', '=/='], a:line[i : i + 1]) != -1 -      call add(indtokens, [a:line[i : i + 1], vcol, i]) -      let next_i = i + 2 - -    " Two-character tokens -    elseif i + 1 < linelen && -         \ index(['->', '<<', '>>', '||', '==', '/=', '=<', '>=', '++', '--', -         \        '::'], -         \       a:line[i : i + 1]) != -1 -      call add(indtokens, [a:line[i : i + 1], vcol, i]) -      let next_i = i + 2 - -    " Other character: , ; < > ( ) [ ] { } # + - * / : ? = ! | -    else -      call add(indtokens, [a:line[i], vcol, i]) -      let next_i = i + 1 - -    endif - -    if next_vcol ==# '' -      let vcol += next_i - i -    else -      let vcol = next_vcol -    endif - -    let i = next_i - -  endwhile - -  return indtokens - -endfunction - -" TODO: doc, handle "not found" case -function! s:GetIndtokenAtCol(indtokens, col) -  let i = 0 -  while i < len(a:indtokens) -    if a:indtokens[i][2] ==# a:col -      return [1, i] -    elseif a:indtokens[i][2] > a:col -      return [0, s:IndentError('No token at col ' . a:col . ', ' . -                              \'indtokens = ' . string(a:indtokens), -                              \'', '')] -    endif -    let i += 1 -  endwhile -  return [0, s:IndentError('No token at col ' . a:col . ', ' . -                           \'indtokens = ' . string(a:indtokens), -                           \'', '')] -endfunction - -" Stack library {{{1 -" ============= - -" Purpose: -"   Push a token onto the parser's stack. -" Parameters: -"   stack: [token] -"   token: string -function! s:Push(stack, token) -  call s:Log('    Stack Push: "' . a:token . '" into ' . string(a:stack)) -  call insert(a:stack, a:token) -endfunction - -" Purpose: -"   Pop a token from the parser's stack. -" Parameters: -"   stack: [token] -"   token: string -" Returns: -"   token: string -- the removed element -function! s:Pop(stack) -  let head = remove(a:stack, 0) -  call s:Log('    Stack Pop: "' . head . '" from ' . string(a:stack)) -  return head -endfunction - -" Library for accessing and storing tokenized lines {{{1 -" ================================================= - -" The Erlang token cache: an `lnum -> indtokens` dictionary that stores the -" tokenized lines. -let s:all_tokens = {} -let s:file_name = '' -let s:last_changedtick = -1 - -" Purpose: -"   Clear the Erlang token cache if we have a different file or the file has -"   been changed since the last indentation. -function! s:ClearTokenCacheIfNeeded() -  let file_name = expand('%:p') -  if file_name != s:file_name || -   \ b:changedtick != s:last_changedtick -    let s:file_name = file_name -    let s:last_changedtick = b:changedtick -    let s:all_tokens = {} -  endif -endfunction - -" Purpose: -"   Return the tokens of line `lnum`, if that line is not empty. If it is -"   empty, find the first non-empty line in the given `direction` and return -"   the tokens of that line. -" Parameters: -"   lnum: integer -"   direction: 'up' | 'down' -" Returns: -"   result: [] -- the result is an empty list if we hit the beginning or end -"                  of the file -"           | [lnum, indtokens] -"   lnum: integer -- the index of the non-empty line that was found and -"                    tokenized -"   indtokens: [indtoken] -- the tokens of line `lnum` -function! s:TokenizeLine(lnum, direction) - -  call s:Log('Tokenizing starts from line ' . a:lnum) -  if a:direction ==# 'up' -    let lnum = prevnonblank(a:lnum) -  else " a:direction ==# 'down' -    let lnum = nextnonblank(a:lnum) -  endif - -  " We hit the beginning or end of the file -  if lnum ==# 0 -    let indtokens = [] -    call s:Log('  We hit the beginning or end of the file.') - -    " The line has already been parsed -  elseif has_key(s:all_tokens, lnum) -    let indtokens = s:all_tokens[lnum] -    call s:Log('Cached line ' . lnum . ': ' . getline(lnum)) -    call s:Log("  Tokens in the line:\n    - " . join(indtokens, "\n    - ")) - -    " The line should be parsed now -  else - -    " Parse the line -    let line = getline(lnum) -    let string_continuation = s:IsLineStringContinuation(lnum) -    let atom_continuation = s:IsLineAtomContinuation(lnum) -    let indtokens = s:GetTokensFromLine(line, string_continuation, -                                       \atom_continuation, &tabstop) -    let s:all_tokens[lnum] = indtokens -    call s:Log('Tokenizing line ' . lnum . ': ' . line) -    call s:Log("  Tokens in the line:\n    - " . join(indtokens, "\n    - ")) - -  endif - -  return [lnum, indtokens] -endfunction - -" Purpose: -"   As a helper function for PrevIndToken and NextIndToken, the FindIndToken -"   function finds the first line with at least one token in the given -"   direction. -" Parameters: -"   lnum: integer -"   direction: 'up' | 'down' -" Returns: -"   result: [] -- the result is an empty list if we hit the beginning or end -"                  of the file -"           | indtoken -function! s:FindIndToken(lnum, dir) -  let lnum = a:lnum -  while 1 -    let lnum += (a:dir ==# 'up' ? -1 : 1) -    let [lnum, indtokens] = s:TokenizeLine(lnum, a:dir) -    if lnum ==# 0 -      " We hit the beginning or end of the file -      return [] -    elseif !empty(indtokens) -      return indtokens[a:dir ==# 'up' ? -1 : 0] -    endif -  endwhile -endfunction - -" Purpose: -"   Find the token that directly precedes the given token. -" Parameters: -"   lnum: integer -- the line of the given token -"   i: the index of the given token within line `lnum` -" Returns: -"   result = [] -- the result is an empty list if the given token is the first -"                  token of the file -"          | indtoken -function! s:PrevIndToken(lnum, i) -  call s:Log('    PrevIndToken called: lnum=' . a:lnum . ', i =' . a:i) - -  " If the current line has a previous token, return that -  if a:i > 0 -    return s:all_tokens[a:lnum][a:i - 1] -  else -    return s:FindIndToken(a:lnum, 'up') -  endif -endfunction - -" Purpose: -"   Find the token that directly succeeds the given token. -" Parameters: -"   lnum: integer -- the line of the given token -"   i: the index of the given token within line `lnum` -" Returns: -"   result = [] -- the result is an empty list if the given token is the last -"                  token of the file -"          | indtoken -function! s:NextIndToken(lnum, i) -  call s:Log('    NextIndToken called: lnum=' . a:lnum . ', i =' . a: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] -  else -    return s:FindIndToken(a:lnum, 'down') -  endif -endfunction - -" ErlangCalcIndent helper functions {{{1 -" ================================= - -" Purpose: -"   This function is called when the parser encounters a syntax error. -" -"   If we encounter a syntax error, we return -"   g:erlang_unexpected_token_indent, which is -1 by default. This means that -"   the indentation of the LTI will not be changed. -" Parameter: -"   msg: string -"   token: string -"   stack: [token] -" Returns: -"   indent: integer -function! s:IndentError(msg, token, stack) -  call s:Log('Indent error: ' . a:msg . ' -> return') -  call s:Log('  Token = ' . a:token . ', ' . -            \'  stack = ' . string(a:stack)) -  return g:erlang_unexpected_token_indent -endfunction - -" Purpose: -"   This function is called when the parser encounters an unexpected token, -"   and the parser will return the number given back by UnexpectedToken. -" -"   If we encounter an unexpected token, we return -"   g:erlang_unexpected_token_indent, which is -1 by default. This means that -"   the indentation of the LTI will not be changed. -" Parameter: -"   token: string -"   stack: [token] -" Returns: -"   indent: integer -function! s:UnexpectedToken(token, stack) -  call s:Log('    Unexpected token ' . a:token . ', stack = ' . -            \string(a:stack) . ' -> return') -  return g:erlang_unexpected_token_indent -endfunction - -if !exists('g:erlang_unexpected_token_indent') -  let g:erlang_unexpected_token_indent = -1 -endif - -" Purpose: -"   Return whether the given line starts with a string continuation. -" Parameter: -"   lnum: integer -" Returns: -"   result: bool -" Example: -"   f() ->           % IsLineStringContinuation = false -"       "This is a   % IsLineStringContinuation = false -"       multiline    % IsLineStringContinuation = true -"       string".     % IsLineStringContinuation = true -function! s:IsLineStringContinuation(lnum) -  if has('syntax_items') -    return synIDattr(synID(a:lnum, 1, 0), 'name') =~# '^erlangString' -  else -    return 0 -  endif -endfunction - -" Purpose: -"   Return whether the given line starts with an atom continuation. -" Parameter: -"   lnum: integer -" Returns: -"   result: bool -" Example: -"   'function with   % IsLineAtomContinuation = true, but should be false -"   weird name'() -> % IsLineAtomContinuation = true -"       ok.          % IsLineAtomContinuation = false -function! s:IsLineAtomContinuation(lnum) -  if has('syntax_items') -    return synIDattr(synID(a:lnum, 1, 0), 'name') =~# '^erlangQuotedAtom' -  else -    return 0 -  endif -endfunction - -" Purpose: -"   Return whether the 'catch' token (which should be the `i`th token in line -"   `lnum`) is standalone or part of a try-catch block, based on the preceding -"   token. -" Parameters: -"   lnum: integer -"   i: integer -" Return: -"   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) - -  " If we hit the beginning of the file, it is not a catch in a try block -  if prev_indtoken == [] -    return 1 -  endif - -  let prev_token = prev_indtoken[0] - -  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', -            \ 'bsr', 'bxor', 'case', 'catch', 'div', 'not', 'or', 'orelse', -            \ 'rem', 'try', 'xor'], prev_token) != -1 -      " If catch is after these keywords, it is standalone -      let is_standalone = 1 -    else -      " If catch is after another keyword (e.g. 'end') or an atom, it is -      " part of try-catch. -      " -      " Keywords: -      " - may precede 'catch': end -      " - may not precede 'catch': fun if of receive when -      " - unused: cond let query -      let is_standalone = 0 -    endif -  elseif index([')', ']', '}', '<string>', '<string_end>', '<quoted_atom>', -              \ '<quoted_atom_end>', '$.'], prev_token) != -1 -    let is_standalone = 0 -  else -    " This 'else' branch includes the following tokens: -    "   -> == /= =< < >= > =:= =/= + - * / ++ -- :: < > ; ( [ { ? = ! . | -    let is_standalone = 1 -  endif - -  call s:Log('   "catch" preceded by "' . prev_token  . '" -> catch ' . -            \(is_standalone ? 'is standalone' : 'belongs to try-catch')) -  return is_standalone - -endfunction - -" Purpose: -"   This function is called when a begin-type element ('begin', 'case', -"   '[', '<<', etc.) is found. It asks the caller to return if the stack -" Parameters: -"   stack: [token] -"   token: string -"   curr_vcol: integer -"   stored_vcol: integer -"   sw: integer -- number of spaces to be used after the begin element as -"                  indentation -" Returns: -"   result: [should_return, indent] -"   should_return: bool -- if true, the caller should return `indent` to Vim -"   indent -- integer -function! s:BeginElementFoundIfEmpty(stack, token, curr_vcol, stored_vcol, sw) -  if empty(a:stack) -    if a:stored_vcol ==# -1 -      call s:Log('    "' . a:token . '" directly preceeds LTI -> return') -      return [1, a:curr_vcol + a:sw] -    else -      call s:Log('    "' . a:token . -                \'" token (whose expression includes LTI) found -> return') -      return [1, a:stored_vcol] -    endif -  else -    return [0, 0] -  endif -endfunction - -" Purpose: -"   This function is called when a begin-type element ('begin', 'case', '[', -"   '<<', etc.) is found, and in some cases when 'after' and 'when' is found. -"   It asks the caller to return if the stack is already empty. -" Parameters: -"   stack: [token] -"   token: string -"   curr_vcol: integer -"   stored_vcol: integer -"   end_token: end token that belongs to the begin element found (e.g. if the -"              begin element is 'begin', the end token is 'end') -"   sw: integer -- number of spaces to be used after the begin element as -"                  indentation -" Returns: -"   result: [should_return, indent] -"   should_return: bool -- if true, the caller should return `indent` to Vim -"   indent -- integer -function! s:BeginElementFound(stack, token, curr_vcol, stored_vcol, end_token, sw) - -  " Return 'return' if the stack is empty -  let [ret, res] = s:BeginElementFoundIfEmpty(a:stack, a:token, a:curr_vcol, -                                             \a:stored_vcol, a:sw) -  if ret | return [ret, res] | endif - -  if a:stack[0] ==# a:end_token -    call s:Log('    "' . a:token . '" pops "' . a:end_token . '"') -    call s:Pop(a:stack) -    if !empty(a:stack) && a:stack[0] ==# 'align_to_begin_element' -      call s:Pop(a:stack) -      if empty(a:stack) -        return [1, a:curr_vcol] -      else -        return [1, s:UnexpectedToken(a:token, a:stack)] -      endif -    else -      return [0, 0] -    endif -  else -    return [1, s:UnexpectedToken(a:token, a:stack)] -  endif -endfunction - -" Purpose: -"   This function is called when we hit the beginning of a file or an -"   end-of-clause token -- i.e. when we found the beginning of the current -"   clause. -" -"   If the stack contains an '->' or 'when', this means that we can return -"   now, since we were looking for the beginning of the clause. -" Parameters: -"   stack: [token] -"   token: string -"   stored_vcol: integer -" 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) -  if !empty(a:stack) && a:stack[0] ==# 'when' -    call s:Log('    BeginningOfClauseFound: "when" found in stack') -    call s:Pop(a:stack) -    if empty(a:stack) -      call s:Log('    Stack is ["when"], so LTI is in a guard -> return') -      return [1, a:stored_vcol + shiftwidth() + 2] -    else -      return [1, s:UnexpectedToken(a:token, a:stack)] -    endif -  elseif !empty(a:stack) && a:stack[0] ==# '->' -    call s:Log('    BeginningOfClauseFound: "->" found in stack') -    call s:Pop(a:stack) -    if empty(a:stack) -      call s:Log('    Stack is ["->"], so LTI is in function body -> return') -      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 -        return [1, s:UnexpectedToken(a:token, a:stack)] -      endif -    else -      return [1, s:UnexpectedToken(a:token, a:stack)] -    endif -  else -    return [0, 0] -  endif -endfunction - -let g:erlang_indent_searchpair_timeout = 2000 - -" TODO -function! s:SearchPair(lnum, curr_col, start, middle, end) -  call cursor(a:lnum, a:curr_col + 1) -  let [lnum_new, col1_new] =  -      \searchpairpos(a:start, a:middle, a:end, 'bW', -                    \'synIDattr(synID(line("."), col("."), 0), "name") ' . -                    \'=~? "string\\|quotedatom\\|todo\\|comment\\|' .  -                    \'erlangmodifier"', -                    \0, g:erlang_indent_searchpair_timeout) -  return [lnum_new, col1_new - 1] -endfunction - -function! s:SearchEndPair(lnum, curr_col) -  return s:SearchPair( -         \ a:lnum, a:curr_col, -         \ '\C\<\%(case\|try\|begin\|receive\|if\)\>\|' . -         \ '\<fun\>\%(\s\|\n\|%.*$\)*(', -         \ '', -         \ '\<end\>') -endfunction - -" ErlangCalcIndent {{{1 -" ================ - -" Purpose: -"   Calculate the indentation of the given line. -" Parameters: -"   lnum: integer -- index of the line for which the indentation should be -"                    calculated -"   stack: [token] -- initial stack -" Return: -"   indent: integer -- if -1, that means "don't change the indentation"; -"                      otherwise it means "indent the line with `indent` -"                      number of spaces or equivalent tabs" -function! s:ErlangCalcIndent(lnum, stack) -  let res = s:ErlangCalcIndent2(a:lnum, a:stack) -  call s:Log("ErlangCalcIndent returned: " . res) -  return res -endfunction - -function! s:ErlangCalcIndent2(lnum, stack) - -  let lnum = a:lnum -  let stored_vcol = -1 " Virtual column of the first character of the token that -                   " we currently think we might align to. -  let mode = 'normal' -  let stack = a:stack -  let semicolon_abscol = '' - -  " Walk through the lines of the buffer backwards (starting from the -  " previous line) until we can decide how to indent the current line. -  while 1 - -    let [lnum, indtokens] = s:TokenizeLine(lnum, 'up') - -    " Hit the start of the file -    if lnum ==# 0 -      let [ret, res] = s:BeginningOfClauseFound(stack, 'beginning_of_file', -                                               \stored_vcol) -      if ret | return res | endif - -      return 0 -    endif - -    let i = len(indtokens) - 1 -    let last_token_of_line = 1 - -    while i >= 0 - -      let [token, curr_vcol, curr_col] = indtokens[i] -      call s:Log('  Analyzing the following token: ' . string(indtokens[i])) - -      if len(stack) > 256 " TODO: magic number -        return s:IndentError('Stack too long', token, stack) -      endif - -      if token ==# '<end_of_clause>' -        let [ret, res] = s:BeginningOfClauseFound(stack, token, stored_vcol) -        if ret | return res | endif - -        if stored_vcol ==# -1 -          call s:Log('    End of clause directly preceeds LTI -> return') -          return 0 -        else -          call s:Log('    End of clause (but not end of line) -> return') -          return stored_vcol -        endif - -      elseif stack == ['prev_term_plus'] -        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 = ' . -                    \curr_vcol . " + " . plus) -          return curr_vcol + plus -        endif - -      elseif token ==# 'begin' -        let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, -                                            \stored_vcol, 'end', shiftwidth()) -        if ret | return res | endif - -      " case EXPR of BRANCHES end -      " try EXPR catch BRANCHES end -      " try EXPR after BODY end -      " try EXPR catch BRANCHES after BODY end -      " try EXPR of BRANCHES catch BRANCHES end -      " try EXPR of BRANCHES after BODY end -      " try EXPR of BRANCHES catch BRANCHES after BODY end -      " receive BRANCHES end -      " receive BRANCHES after BRANCHES end - -      " This branch is not Emacs-compatible -      elseif (index(['of', 'receive', 'after', 'if'], token) != -1 || -           \  (token ==# 'catch' && !s:IsCatchStandalone(lnum, i))) && -           \ !last_token_of_line && -           \ (empty(stack) || stack ==# ['when'] || stack ==# ['->'] || -           \  stack ==# ['->', ';']) - -        " If we are after of/receive, but these are not the last -        " tokens of the line, we want to indent like this: -        " -        "   % stack == [] -        "   receive stored_vcol, -        "           LTI -        " -        "   % stack == ['->', ';'] -        "   receive stored_vcol -> -        "               B; -        "           LTI -        " -        "   % stack == ['->'] -        "   receive stored_vcol -> -        "               LTI -        " -        "   % stack == ['when'] -        "   receive stored_vcol when -        "               LTI - -        " stack = []  =>  LTI is a condition -        " stack = ['->']  =>  LTI is a branch -        " stack = ['->', ';']  =>  LTI is a condition -        " stack = ['when']  =>  LTI is a guard -        if empty(stack) || stack == ['->', ';'] -          call s:Log('    LTI is in a condition after ' . -                    \'"of/receive/after/if/catch" -> return') -          return stored_vcol -        elseif stack == ['->'] -          call s:Log('    LTI is in a branch after ' . -                    \'"of/receive/after/if/catch" -> return') -          return stored_vcol + shiftwidth() -        elseif stack == ['when'] -          call s:Log('    LTI is in a guard after ' . -                    \'"of/receive/after/if/catch" -> return') -          return stored_vcol + shiftwidth() -        else -          return s:UnexpectedToken(token, stack) -        endif - -      elseif index(['case', 'if', 'try', 'receive'], token) != -1 - -        " stack = []  =>  LTI is a condition -        " stack = ['->']  =>  LTI is a branch -        " stack = ['->', ';']  =>  LTI is a condition -        " stack = ['when']  =>  LTI is in a guard -        if empty(stack) -          " pass -        elseif (token ==# 'case' && stack[0] ==# 'of') || -             \ (token ==# 'if') || -             \ (token ==# 'try' && (stack[0] ==# 'of' || -             \                     stack[0] ==# 'catch' || -             \                     stack[0] ==# 'after')) || -             \ (token ==# 'receive') - -          " From the indentation point of view, the keyword -          " (of/catch/after/end) before the LTI is what counts, so -          " when we reached these tokens, and the stack already had -          " a catch/after/end, we didn't modify it. -          " -          " This way when we reach case/try/receive (i.e. now), -          " there is at most one of/catch/after/end token in the -          " stack. -          if token ==# 'case' || token ==# 'try' || -           \ (token ==# 'receive' && stack[0] ==# 'after') -            call s:Pop(stack) -          endif - -          if empty(stack) -            call s:Log('    LTI is in a condition; matching ' . -                      \'"case/if/try/receive" found') -            let stored_vcol = curr_vcol + shiftwidth() -          elseif stack[0] ==# 'align_to_begin_element' -            call s:Pop(stack) -            let stored_vcol = curr_vcol -          elseif len(stack) > 1 && stack[0] ==# '->' && stack[1] ==# ';' -            call s:Log('    LTI is in a condition; matching ' . -                      \'"case/if/try/receive" found') -            call s:Pop(stack) -            call s:Pop(stack) -            let stored_vcol = curr_vcol + shiftwidth() -          elseif stack[0] ==# '->' -            call s:Log('    LTI is in a branch; matching ' . -                      \'"case/if/try/receive" found') -            call s:Pop(stack) -            let stored_vcol = curr_vcol + 2 * shiftwidth() -          elseif stack[0] ==# 'when' -            call s:Log('    LTI is in a guard; matching ' . -                      \'"case/if/try/receive" found') -            call s:Pop(stack) -            let stored_vcol = curr_vcol + 2 * shiftwidth() + 2 -          endif - -        endif - -        let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, -                                            \stored_vcol, 'end', shiftwidth()) -        if ret | return res | endif - -      elseif token ==# 'fun' -        let next_indtoken = s:NextIndToken(lnum, i) -        call s:Log('    Next indtoken = ' . string(next_indtoken)) - -        if !empty(next_indtoken) && next_indtoken[0] ==# '(' -          " We have an anonymous function definition -          " (e.g. "fun () -> ok end") - -          " stack = []  =>  LTI is a condition -          " stack = ['->']  =>  LTI is a branch -          " stack = ['->', ';']  =>  LTI is a condition -          " stack = ['when']  =>  LTI is in a guard -          if empty(stack) -            call s:Log('    LTI is in a condition; matching "fun" found') -            let stored_vcol = curr_vcol + shiftwidth() -          elseif len(stack) > 1 && stack[0] ==# '->' && stack[1] ==# ';' -            call s:Log('    LTI is in a condition; matching "fun" found') -            call s:Pop(stack) -            call s:Pop(stack) -          elseif stack[0] ==# '->' -            call s:Log('    LTI is in a branch; matching "fun" found') -            call s:Pop(stack) -            let stored_vcol = curr_vcol + 2 * shiftwidth() -          elseif stack[0] ==# 'when' -            call s:Log('    LTI is in a guard; matching "fun" found') -            call s:Pop(stack) -            let stored_vcol = curr_vcol + 2 * shiftwidth() + 2 -          endif - -          let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, -                                              \stored_vcol, 'end', shiftwidth()) -          if ret | return res | endif -        else -          " Pass: we have a function reference (e.g. "fun f/0") -        endif - -      elseif token ==# '[' -        " Emacs compatibility -        let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, -                                            \stored_vcol, ']', 1) -        if ret | return res | endif - -      elseif token ==# '<<' -        " Emacs compatibility -        let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, -                                            \stored_vcol, '>>', 2) -        if ret | return res | endif - -      elseif token ==# '(' || token ==# '{' - -        let end_token = (token ==# '(' ? ')' : -                        \token ==# '{' ? '}' : 'error') - -        if empty(stack) -          " We found the opening paren whose block contains the LTI. -          let mode = 'inside' -        elseif stack[0] ==# end_token -          call s:Log('    "' . token . '" pops "' . end_token . '"') -          call s:Pop(stack) - -          if !empty(stack) && stack[0] ==# 'align_to_begin_element' -            " We found the opening paren whose closing paren -            " starts LTI -            let mode = 'align_to_begin_element' -          else -            " We found the opening pair for a closing paren that -            " was already in the stack. -            let mode = 'outside' -          endif -        else -          return s:UnexpectedToken(token, stack) -        endif - -        if mode ==# 'inside' || mode ==# 'align_to_begin_element' - -          if last_token_of_line && i != 0 -            " Examples: {{{ -            " -            " mode == 'inside': -            " -            "     my_func( -            "       LTI -            " -            "     [Variable, { -            "        LTI -            " -            " mode == 'align_to_begin_element': -            " -            "     my_func( -            "       Params -            "      ) % LTI -            " -            "     [Variable, { -            "        Terms -            "       } % LTI -            " }}} -            let stack = ['prev_term_plus'] -            let plus = (mode ==# 'inside' ? 2 : 1) -            call s:Log('    "' . token . -                      \'" token found at end of line -> find previous token') -          elseif mode ==# 'align_to_begin_element' -            " Examples: {{{ -            " -            " mode == 'align_to_begin_element' && !last_token_of_line -            " -            "     my_func(stored_vcol -            "            ) % LTI -            " -            "     [Variable, {stored_vcol -            "                } % LTI -            " -            " mode == 'align_to_begin_element' && i == 0 -            " -            "     ( -            "       stored_vcol -            "     ) % LTI -            " -            "     { -            "       stored_vcol -            "     } % LTI -            " }}} -            call s:Log('    "' . token . '" token (whose closing token ' . -                      \'starts LTI) found -> return') -            return curr_vcol -          elseif stored_vcol ==# -1 -            " Examples: {{{ -            " -            " mode == 'inside' && stored_vcol == -1 && !last_token_of_line -            " -            "     my_func( -            "             LTI -            "     [Variable, { -            "                 LTI -            " -            " mode == 'inside' && stored_vcol == -1 && i == 0 -            " -            "     ( -            "      LTI -            " -            "     { -            "      LTI -            " }}} -            call s:Log('    "' . token . -                      \'" token (which directly precedes LTI) found -> return') -            return curr_vcol + 1 -          else -            " Examples: {{{ -            " -            " mode == 'inside' && stored_vcol != -1 && !last_token_of_line -            " -            "     my_func(stored_vcol, -            "             LTI -            " -            "     [Variable, {stored_vcol, -            "                 LTI -            " -            " mode == 'inside' && stored_vcol != -1 && i == 0 -            " -            "     (stored_vcol, -            "      LTI -            " -            "     {stored_vcol, -            "      LTI -            " }}} -            call s:Log('    "' . token . -                      \'" token (whose block contains LTI) found -> return') -            return stored_vcol -          endif -        endif - -      elseif index(['end', ')', ']', '}', '>>'], token) != -1 - -        " If we can be sure that there is synchronization in the Erlang -        " syntax, we use searchpair to make the script quicker. Otherwise we -        " just push the token onto the stack and keep parsing. -     -        " No synchronization -> no searchpair optimization -        if !exists('b:erlang_syntax_synced') -          call s:Push(stack, token) - -        " We don't have searchpair optimization for '>>' -        elseif token ==# '>>' -          call s:Push(stack, token) - -        elseif token ==# 'end' -          let [lnum_new, col_new] = s:SearchEndPair(lnum, curr_col) - -          if lnum_new ==# 0 -            return s:IndentError('Matching token for "end" not found', -                                \token, stack) -          else -            if lnum_new != lnum -              call s:Log('    Tokenize for "end" <<<<') -              let [lnum, indtokens] = s:TokenizeLine(lnum_new, 'up') -              call s:Log('    >>>> Tokenize for "end"') -            endif - -            let [success, i] = s:GetIndtokenAtCol(indtokens, col_new) -            if !success | return i | endif -            let [token, curr_vcol, curr_col] = indtokens[i] -            call s:Log('    Match for "end" in line ' . lnum_new . ': ' . -                      \string(indtokens[i])) -          endif - -        else " token is one of the following: ')', ']', '}' - -          call s:Push(stack, token) - -          " We have to escape '[', because this string will be interpreted as a -          " regexp -          let open_paren = (token ==# ')' ? '(' : -                           \token ==# ']' ? '\[' : -                           \               '{') - -          let [lnum_new, col_new] = s:SearchPair(lnum, curr_col, -                                                \open_paren, '', token) - -          if lnum_new ==# 0 -            return s:IndentError('Matching token not found', -                                \token, stack) -          else -            if lnum_new != lnum -              call s:Log('    Tokenize the opening paren <<<<') -              let [lnum, indtokens] = s:TokenizeLine(lnum_new, 'up') -              call s:Log('    >>>>') -            endif - -            let [success, i] = s:GetIndtokenAtCol(indtokens, col_new) -            if !success | return i | endif -            let [token, curr_vcol, curr_col] = indtokens[i] -            call s:Log('    Match in line ' . lnum_new . ': ' . -                      \string(indtokens[i])) - -            " Go back to the beginning of the loop and handle the opening paren -            continue -          endif -        endif - -      elseif token ==# ';' - -        if empty(stack) -          call s:Push(stack, ';') -        elseif index([';', '->', 'when', 'end', 'after', 'catch'], -                    \stack[0]) != -1 -          " Pass: -          " -          " - If the stack top is another ';', then one ';' is -          "   enough. -          " - If the stack top is an '->' or a 'when', then we -          "   should keep that, because they signify the type of the -          "   LTI (branch, condition or guard). -          " - From the indentation point of view, the keyword -          "   (of/catch/after/end) before the LTI is what counts, so -          "   if the stack already has a catch/after/end, we don't -          "   modify it. This way when we reach case/try/receive, -          "   there will be at most one of/catch/after/end token in -          "   the stack. -        else -          return s:UnexpectedToken(token, stack) -        endif - -      elseif token ==# '->' - -        if empty(stack) && !last_token_of_line -          call s:Log('    LTI is in expression after arrow -> return') -          return stored_vcol -        elseif empty(stack) || stack[0] ==# ';' || stack[0] ==# 'end' -          " stack = [';']  -> LTI is either a branch or in a guard -          " stack = ['->']  ->  LTI is a condition -          " stack = ['->', ';']  -> LTI is a branch -          call s:Push(stack, '->') -        elseif index(['->', 'when', 'end', 'after', 'catch'], stack[0]) != -1 -          " Pass: -          " -          " - If the stack top is another '->', then one '->' is -          "   enough. -          " - If the stack top is a 'when', then we should keep -          "   that, because this signifies that LTI is a in a guard. -          " - From the indentation point of view, the keyword -          "   (of/catch/after/end) before the LTI is what counts, so -          "   if the stack already has a catch/after/end, we don't -          "   modify it. This way when we reach case/try/receive, -          "   there will be at most one of/catch/after/end token in -          "   the stack. -        else -          return s:UnexpectedToken(token, stack) -        endif - -      elseif token ==# 'when' - -        " Pop all ';' from the top of the stack -        while !empty(stack) && stack[0] ==# ';' -          call s:Pop(stack) -        endwhile - -        if empty(stack) -          if semicolon_abscol != '' -            let stored_vcol = semicolon_abscol -          endif -          if !last_token_of_line -            " Example: -            "   when A, -            "        LTI -            let [ret, res] = s:BeginElementFoundIfEmpty(stack, token, curr_vcol, -                                                       \stored_vcol, shiftwidth()) -            if ret | return res | endif -          else -            " Example: -            "   when -            "       LTI -            call s:Push(stack, token) -          endif -        elseif index(['->', 'when', 'end', 'after', 'catch'], stack[0]) != -1 -          " Pass: -          " - If the stack top is another 'when', then one 'when' is -          "   enough. -          " - If the stack top is an '->' or a 'when', then we -          "   should keep that, because they signify the type of the -          "   LTI (branch, condition or guard). -          " - From the indentation point of view, the keyword -          "   (of/catch/after/end) before the LTI is what counts, so -          "   if the stack already has a catch/after/end, we don't -          "   modify it. This way when we reach case/try/receive, -          "   there will be at most one of/catch/after/end token in -          "   the stack. -        else -          return s:UnexpectedToken(token, stack) -        endif - -      elseif token ==# 'of' || token ==# 'after' || -           \ (token ==# 'catch' && !s:IsCatchStandalone(lnum, i)) - -        if token ==# 'after' -          " If LTI is between an 'after' and the corresponding -          " 'end', then let's return -          let [ret, res] = s:BeginElementFoundIfEmpty(stack, token, curr_vcol, -                                                     \stored_vcol, shiftwidth()) -          if ret | return res | endif -        endif - -        if empty(stack) || stack[0] ==# '->' || stack[0] ==# 'when' -          call s:Push(stack, token) -        elseif stack[0] ==# 'catch' || stack[0] ==# 'after' || stack[0] ==# 'end' -          " Pass: From the indentation point of view, the keyword -          " (of/catch/after/end) before the LTI is what counts, so -          " if the stack already has a catch/after/end, we don't -          " modify it. This way when we reach case/try/receive, -          " there will be at most one of/catch/after/end token in -          " the stack. -        else -          return s:UnexpectedToken(token, stack) -        endif - -      elseif token ==# '||' && empty(stack) && !last_token_of_line - -        call s:Log('    LTI is in expression after "||" -> return') -        return stored_vcol - -      else -        call s:Log('    Misc token, stack unchanged = ' . string(stack)) - -      endif - -      if empty(stack) || stack[0] ==# '->' || stack[0] ==# 'when' -        let stored_vcol = curr_vcol -        let semicolon_abscol = '' -        call s:Log('    Misc token when the stack is empty or has "->" ' . -                  \'-> setting stored_vcol to ' . stored_vcol) -      elseif stack[0] ==# ';' -        let semicolon_abscol = curr_vcol -        call s:Log('    Setting semicolon-stored_vcol to ' . stored_vcol) -      endif - -      let i -= 1 -      call s:Log('    Token processed. stored_vcol=' . stored_vcol) - -      let last_token_of_line = 0 - -    endwhile " iteration on tokens in a line - -    call s:Log('  Line analyzed. stored_vcol=' . stored_vcol) - -    if empty(stack) && stored_vcol != -1 && -     \ (!empty(indtokens) && indtokens[0][0] != '<string_end>' && -     \                       indtokens[0][0] != '<quoted_atom_end>') -      call s:Log('    Empty stack at the beginning of the line -> return') -      return stored_vcol -    endif - -    let lnum -= 1 - -  endwhile " iteration on lines - -endfunction - -" ErlangIndent function {{{1 -" ===================== - -function! ErlangIndent() - -  call s:ClearTokenCacheIfNeeded() - -  let currline = getline(v:lnum) -  call s:Log('Indenting line ' . v:lnum . ': ' . currline) - -  if s:IsLineStringContinuation(v:lnum) || s:IsLineAtomContinuation(v:lnum) -    call s:Log('String or atom continuation found -> ' . -              \'leaving indentation unchanged') -    return -1 -  endif - -  let ml = matchlist(currline, -                    \'^\(\s*\)\(\%(end\|of\|catch\|after\)\>\|[)\]}]\|>>\)') - -  " If the line has a special beginning, but not a standalone catch -  if !empty(ml) && !(ml[2] ==# 'catch' && s:IsCatchStandalone(v:lnum, 0)) - -    let curr_col = len(ml[1]) - -    " If we can be sure that there is synchronization in the Erlang -    " syntax, we use searchpair to make the script quicker. -    if ml[2] ==# 'end' && exists('b:erlang_syntax_synced') - -      let [lnum, col] = s:SearchEndPair(v:lnum, curr_col) - -      if lnum ==# 0 -        return s:IndentError('Matching token for "end" not found', -                            \'end', []) -      else -        call s:Log('    Tokenize for "end" <<<<') -        let [lnum, indtokens] = s:TokenizeLine(lnum, 'up') -        call s:Log('    >>>> Tokenize for "end"') - -        let [success, i] = s:GetIndtokenAtCol(indtokens, col) -        if !success | return i | endif -        let [token, curr_vcol, curr_col] = indtokens[i] -        call s:Log('    Match for "end" in line ' . lnum . ': ' . -                   \string(indtokens[i])) -        return curr_vcol -      endif - -    else - -      call s:Log("  Line type = 'end'") -      let new_col = s:ErlangCalcIndent(v:lnum - 1, -                                      \[ml[2], 'align_to_begin_element']) -    endif -  else -    call s:Log("  Line type = 'normal'") - -    let new_col = s:ErlangCalcIndent(v:lnum - 1, []) -    if currline =~# '^\s*when\>' -      let new_col += 2 -    endif -  endif - -  if new_col < -1 -    call s:Log('WARNING: returning new_col == ' . new_col) -    return g:erlang_unexpected_token_indent -  endif - -  return new_col - -endfunction - -" Cleanup {{{1 -" ======= - -let &cpo = s:cpo_save -unlet s:cpo_save - -" vim: sw=2 et fdm=marker - -endif  if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'erlang') == -1  " Vim indent file | 
