home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / runtime / autoload / syntaxcomplete.vim < prev    next >
Encoding:
Text File  |  2012-05-31  |  17.4 KB  |  474 lines

  1. " Vim completion script
  2. " Language:    All languages, uses existing syntax highlighting rules
  3. " Maintainer:  David Fishburn <dfishburn dot vim at gmail dot com>
  4. " Version:     8.0
  5. " Last Change: 2011 Nov 02
  6. " Usage:       For detailed help, ":help ft-syntax-omni" 
  7.  
  8. " History
  9. "
  10. " Version 8.0
  11. "     Updated SyntaxCSyntaxGroupItems()
  12. "         - Some additional syntax items were also allowed
  13. "           on nextgroup= lines which were ignored by default.
  14. "           Now these lines are processed independently.
  15. "
  16. " Version 7.0
  17. "     Updated syntaxcomplete#OmniSyntaxList()
  18. "         - Looking up the syntax groups defined from a syntax file
  19. "           looked for only 1 format of {filetype}GroupName, but some 
  20. "           syntax writers use this format as well:
  21. "               {b:current_syntax}GroupName
  22. "           OmniSyntaxList() will now check for both if the first
  23. "           method does not find a match.
  24. "
  25. " Version 6.0
  26. "     Added syntaxcomplete#OmniSyntaxList()
  27. "         - Allows other plugins to use this for their own 
  28. "           purposes.
  29. "         - It will return a List of all syntax items for the
  30. "           syntax group name passed in.  
  31. "         - XPTemplate for SQL will use this function via the 
  32. "           sqlcomplete plugin to populate a Choose box.
  33. "
  34. " Version 5.0
  35. "     Updated SyntaxCSyntaxGroupItems()
  36. "         - When processing a list of syntax groups, the final group
  37. "           was missed in function SyntaxCSyntaxGroupItems.
  38. "
  39. " Set completion with CTRL-X CTRL-O to autoloaded function.
  40. " This check is in place in case this script is
  41. " sourced directly instead of using the autoload feature. 
  42. if exists('+omnifunc')
  43.     " Do not set the option if already set since this
  44.     " results in an E117 warning.
  45.     if &omnifunc == ""
  46.         setlocal omnifunc=syntaxcomplete#Complete
  47.     endif
  48. endif
  49.  
  50. if exists('g:loaded_syntax_completion')
  51.     finish 
  52. endif
  53. let g:loaded_syntax_completion = 80
  54.  
  55. " Set ignorecase to the ftplugin standard
  56. " This is the default setting, but if you define a buffer local
  57. " variable you can override this on a per filetype.
  58. if !exists('g:omni_syntax_ignorecase')
  59.     let g:omni_syntax_ignorecase = &ignorecase
  60. endif
  61.  
  62. " Indicates whether we should use the iskeyword option to determine
  63. " how to split words.
  64. " This is the default setting, but if you define a buffer local
  65. " variable you can override this on a per filetype.
  66. if !exists('g:omni_syntax_use_iskeyword')
  67.     let g:omni_syntax_use_iskeyword = 1
  68. endif
  69.  
  70. " Only display items in the completion window that are at least
  71. " this many characters in length.
  72. " This is the default setting, but if you define a buffer local
  73. " variable you can override this on a per filetype.
  74. if !exists('g:omni_syntax_minimum_length')
  75.     let g:omni_syntax_minimum_length = 0
  76. endif
  77.  
  78. " This script will build a completion list based on the syntax
  79. " elements defined by the files in $VIMRUNTIME/syntax.
  80. let s:syn_remove_words = 'match,matchgroup=,contains,'.
  81.             \ 'links to,start=,end='
  82.             " \ 'links to,start=,end=,nextgroup='
  83.  
  84. let s:cache_name = []
  85. let s:cache_list = []
  86. let s:prepended  = ''
  87.  
  88. " This function is used for the 'omnifunc' option.
  89. function! syntaxcomplete#Complete(findstart, base)
  90.  
  91.     " Only display items in the completion window that are at least
  92.     " this many characters in length
  93.     if !exists('b:omni_syntax_ignorecase')
  94.         if exists('g:omni_syntax_ignorecase')
  95.             let b:omni_syntax_ignorecase = g:omni_syntax_ignorecase
  96.         else
  97.             let b:omni_syntax_ignorecase = &ignorecase
  98.         endif
  99.     endif
  100.  
  101.     if a:findstart
  102.         " Locate the start of the item, including "."
  103.         let line = getline('.')
  104.         let start = col('.') - 1
  105.         let lastword = -1
  106.         while start > 0
  107.             " if line[start - 1] =~ '\S'
  108.             "     let start -= 1
  109.             " elseif line[start - 1] =~ '\.'
  110.             if line[start - 1] =~ '\k'
  111.                 let start -= 1
  112.                 let lastword = a:findstart
  113.             else
  114.                 break
  115.             endif
  116.         endwhile
  117.  
  118.         " Return the column of the last word, which is going to be changed.
  119.         " Remember the text that comes before it in s:prepended.
  120.         if lastword == -1
  121.             let s:prepended = ''
  122.             return start
  123.         endif
  124.         let s:prepended = strpart(line, start, (col('.') - 1) - start)
  125.         return start
  126.     endif
  127.  
  128.     " let base = s:prepended . a:base
  129.     let base = s:prepended
  130.  
  131.     let filetype = substitute(&filetype, '\.', '_', 'g')
  132.     let list_idx = index(s:cache_name, filetype, 0, &ignorecase)
  133.     if list_idx > -1
  134.         let compl_list = s:cache_list[list_idx]
  135.     else
  136.         let compl_list   = OmniSyntaxList()
  137.         let s:cache_name = add( s:cache_name,  filetype )
  138.         let s:cache_list = add( s:cache_list,  compl_list )
  139.     endif
  140.  
  141.     " Return list of matches.
  142.  
  143.     if base != ''
  144.         " let compstr    = join(compl_list, ' ')
  145.         " let expr       = (b:omni_syntax_ignorecase==0?'\C':'').'\<\%('.base.'\)\@!\w\+\s*'
  146.         " let compstr    = substitute(compstr, expr, '', 'g')
  147.         " let compl_list = split(compstr, '\s\+')
  148.  
  149.         " Filter the list based on the first few characters the user
  150.         " entered
  151.         let expr = 'v:val '.(g:omni_syntax_ignorecase==1?'=~?':'=~#')." '^".escape(base, '\\/.*$^~[]').".*'"
  152.         let compl_list = filter(deepcopy(compl_list), expr)
  153.     endif
  154.  
  155.     return compl_list
  156. endfunc
  157.  
  158. function! syntaxcomplete#OmniSyntaxList(...)
  159.     if a:0 > 0
  160.         let parms = []
  161.         if 3 == type(a:1) 
  162.             let parms = a:1
  163.         elseif 1 == type(a:1)
  164.             let parms = split(a:1, ',')
  165.         endif
  166.         return OmniSyntaxList( parms )
  167.     else
  168.         return OmniSyntaxList()
  169.     endif
  170. endfunc
  171.  
  172. function! OmniSyntaxList(...)
  173.     let list_parms = []
  174.     if a:0 > 0
  175.         if 3 == type(a:1) 
  176.             let list_parms = a:1
  177.         elseif 1 == type(a:1)
  178.             let list_parms = split(a:1, ',')
  179.         endif
  180.     endif
  181.  
  182.     " Default to returning a dictionary, if use_dictionary is set to 0
  183.     " a list will be returned.
  184.     " let use_dictionary = 1
  185.     " if a:0 > 0 && a:1 != ''
  186.     "     let use_dictionary = a:1
  187.     " endif
  188.  
  189.     " Only display items in the completion window that are at least
  190.     " this many characters in length
  191.     if !exists('b:omni_syntax_use_iskeyword')
  192.         if exists('g:omni_syntax_use_iskeyword')
  193.             let b:omni_syntax_use_iskeyword = g:omni_syntax_use_iskeyword
  194.         else
  195.             let b:omni_syntax_use_iskeyword = 1
  196.         endif
  197.     endif
  198.  
  199.     " Only display items in the completion window that are at least
  200.     " this many characters in length
  201.     if !exists('b:omni_syntax_minimum_length')
  202.         if exists('g:omni_syntax_minimum_length')
  203.             let b:omni_syntax_minimum_length = g:omni_syntax_minimum_length
  204.         else
  205.             let b:omni_syntax_minimum_length = 0
  206.         endif
  207.     endif
  208.  
  209.     let saveL = @l
  210.     let filetype = substitute(&filetype, '\.', '_', 'g')
  211.     
  212.     if empty(list_parms)
  213.         " Default the include group to include the requested syntax group
  214.         let syntax_group_include_{filetype} = ''
  215.         " Check if there are any overrides specified for this filetype
  216.         if exists('g:omni_syntax_group_include_'.filetype)
  217.             let syntax_group_include_{filetype} =
  218.                         \ substitute( g:omni_syntax_group_include_{filetype},'\s\+','','g') 
  219.             let list_parms = split(g:omni_syntax_group_include_{filetype}, ',')
  220.             if syntax_group_include_{filetype} =~ '\w'
  221.                 let syntax_group_include_{filetype} = 
  222.                             \ substitute( syntax_group_include_{filetype}, 
  223.                             \ '\s*,\s*', '\\|', 'g'
  224.                             \ )
  225.             endif
  226.         endif
  227.     else
  228.         " A specific list was provided, use it
  229.     endif
  230.  
  231.     " Loop through all the syntax groupnames, and build a
  232.     " syntax file which contains these names.  This can 
  233.     " work generically for any filetype that does not already
  234.     " have a plugin defined.
  235.     " This ASSUMES the syntax groupname BEGINS with the name
  236.     " of the filetype.  From my casual viewing of the vim7\syntax 
  237.     " directory this is true for almost all syntax definitions.
  238.     " As an example, the SQL syntax groups have this pattern:
  239.     "     sqlType
  240.     "     sqlOperators
  241.     "     sqlKeyword ...
  242.     redir @l
  243.     silent! exec 'syntax list '.join(list_parms)
  244.     redir END
  245.  
  246.     let syntax_full = "\n".@l
  247.     let @l = saveL
  248.  
  249.     if syntax_full =~ 'E28' 
  250.                 \ || syntax_full =~ 'E411'
  251.                 \ || syntax_full =~ 'E415'
  252.                 \ || syntax_full =~ 'No Syntax items'
  253.         return []
  254.     endif
  255.  
  256.     let filetype = substitute(&filetype, '\.', '_', 'g')
  257.  
  258.     let list_exclude_groups = []
  259.     if a:0 > 0 
  260.         " Do nothing since we have specific a specific list of groups
  261.     else
  262.         " Default the exclude group to nothing
  263.         let syntax_group_exclude_{filetype} = ''
  264.         " Check if there are any overrides specified for this filetype
  265.         if exists('g:omni_syntax_group_exclude_'.filetype)
  266.             let syntax_group_exclude_{filetype} =
  267.                         \ substitute( g:omni_syntax_group_exclude_{filetype},'\s\+','','g') 
  268.             let list_exclude_groups = split(g:omni_syntax_group_exclude_{filetype}, ',')
  269.             if syntax_group_exclude_{filetype} =~ '\w' 
  270.                 let syntax_group_exclude_{filetype} = 
  271.                             \ substitute( syntax_group_exclude_{filetype}, 
  272.                             \ '\s*,\s*', '\\|', 'g'
  273.                             \ )
  274.             endif
  275.         endif
  276.     endif
  277.  
  278.     " Sometimes filetypes can be composite names, like c.doxygen
  279.     " Loop through each individual part looking for the syntax
  280.     " items specific to each individual filetype.
  281.     let syn_list = ''
  282.     let ftindex  = 0
  283.     let ftindex  = match(&filetype, '\w\+', ftindex)
  284.  
  285.     while ftindex > -1
  286.         let ft_part_name = matchstr( &filetype, '\w\+', ftindex )
  287.  
  288.         " Syntax rules can contain items for more than just the current 
  289.         " filetype.  They can contain additional items added by the user
  290.         " via autocmds or their vimrc.
  291.         " Some syntax files can be combined (html, php, jsp).
  292.         " We want only items that begin with the filetype we are interested in.
  293.         let next_group_regex = '\n' .
  294.                     \ '\zs'.ft_part_name.'\w\+\ze'.
  295.                     \ '\s\+xxx\s\+' 
  296.         let index    = 0
  297.         let index    = match(syntax_full, next_group_regex, index)
  298.  
  299.         if index == -1 && exists('b:current_syntax') && ft_part_name != b:current_syntax
  300.             " There appears to be two standards when writing syntax files.
  301.             " Either items begin as:
  302.             "     syn keyword {filetype}Keyword         values ...
  303.             "     let b:current_syntax = "sql"
  304.             "     let b:current_syntax = "sqlanywhere"
  305.             " Or
  306.             "     syn keyword {syntax_filename}Keyword  values ...
  307.             "     let b:current_syntax = "mysql"
  308.             " So, we will make the format of finding the syntax group names
  309.             " a bit more flexible and look for both if the first fails to 
  310.             " find a match.
  311.             let next_group_regex = '\n' .
  312.                         \ '\zs'.b:current_syntax.'\w\+\ze'.
  313.                         \ '\s\+xxx\s\+' 
  314.             let index    = 0
  315.             let index    = match(syntax_full, next_group_regex, index)
  316.         endif
  317.  
  318.         while index > -1
  319.             let group_name = matchstr( syntax_full, '\w\+', index )
  320.  
  321.             let get_syn_list = 1
  322.             for exclude_group_name in list_exclude_groups
  323.                 if '\<'.exclude_group_name.'\>' =~ '\<'.group_name.'\>'
  324.                     let get_syn_list = 0
  325.                 endif
  326.             endfor
  327.         
  328.             " This code is no longer needed in version 6.0 since we have
  329.             " augmented the syntax list command to only retrieve the syntax 
  330.             " groups we are interested in.
  331.             "
  332.             " if get_syn_list == 1
  333.             "     if syntax_group_include_{filetype} != ''
  334.             "         if '\<'.syntax_group_include_{filetype}.'\>' !~ '\<'.group_name.'\>'
  335.             "             let get_syn_list = 0
  336.             "         endif
  337.             "     endif
  338.             " endif
  339.  
  340.             if get_syn_list == 1
  341.                 " Pass in the full syntax listing, plus the group name we 
  342.                 " are interested in.
  343.                 let extra_syn_list = s:SyntaxCSyntaxGroupItems(group_name, syntax_full)
  344.                 let syn_list = syn_list . extra_syn_list . "\n"
  345.             endif
  346.  
  347.             let index = index + strlen(group_name)
  348.             let index = match(syntax_full, next_group_regex, index)
  349.         endwhile
  350.  
  351.         let ftindex  = ftindex + len(ft_part_name)
  352.         let ftindex  = match( &filetype, '\w\+', ftindex )
  353.     endwhile
  354.  
  355.     " Convert the string to a List and sort it.
  356.     let compl_list = sort(split(syn_list))
  357.  
  358.     if &filetype == 'vim'
  359.         let short_compl_list = []
  360.         for i in range(len(compl_list))
  361.             if i == len(compl_list)-1
  362.                 let next = i
  363.             else
  364.                 let next = i + 1
  365.             endif
  366.             if  compl_list[next] !~ '^'.compl_list[i].'.$'
  367.                 let short_compl_list += [compl_list[i]]
  368.             endif
  369.         endfor
  370.  
  371.         return short_compl_list
  372.     else
  373.         return compl_list
  374.     endif
  375. endfunction
  376.  
  377. function! s:SyntaxCSyntaxGroupItems( group_name, syntax_full )
  378.  
  379.     let syn_list = ""
  380.  
  381.     " From the full syntax listing, strip out the portion for the
  382.     " request group.
  383.     " Query:
  384.     "     \n           - must begin with a newline
  385.     "     a:group_name - the group name we are interested in
  386.     "     \s\+xxx\s\+  - group names are always followed by xxx
  387.     "     \zs          - start the match
  388.     "     .\{-}        - everything ...
  389.     "     \ze          - end the match
  390.     "     \(           - start a group or 2 potential matches
  391.     "     \n\w         - at the first newline starting with a character
  392.     "     \|           - 2nd potential match
  393.     "     \%$          - matches end of the file or string
  394.     "     \)           - end a group
  395.     let syntax_group = matchstr(a:syntax_full, 
  396.                 \ "\n".a:group_name.'\s\+xxx\s\+\zs.\{-}\ze\(\n\w\|\%$\)'
  397.                 \ )
  398.  
  399.     if syntax_group != ""
  400.         " let syn_list = substitute( @l, '^.*xxx\s*\%(contained\s*\)\?', "", '' )
  401.         " let syn_list = substitute( @l, '^.*xxx\s*', "", '' )
  402.  
  403.         " We only want the words for the lines begining with
  404.         " containedin, but there could be other items.
  405.         
  406.         " Tried to remove all lines that do not begin with contained
  407.         " but this does not work in all cases since you can have
  408.         "    contained nextgroup=...
  409.         " So this will strip off the ending of lines with known
  410.         " keywords.
  411.         let syn_list = substitute( 
  412.                     \    syntax_group, '\<\('.
  413.                     \    substitute(
  414.                     \      escape(s:syn_remove_words, '\\/.*$^~[]')
  415.                     \      , ',', '\\|', 'g'
  416.                     \    ).
  417.                     \    '\).\{-}\%($\|'."\n".'\)'
  418.                     \    , "\n", 'g' 
  419.                     \  )
  420.  
  421.         " Now strip off the newline + blank space + contained.
  422.         " Also include lines with nextgroup=@someName skip_key_words syntax_element
  423.         let syn_list = substitute( 
  424.                     \    syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\|nextgroup=\)'
  425.                     \    , "", 'g' 
  426.                     \ )
  427.  
  428.         " This can leave lines like this
  429.         "     =@vimMenuList  skipwhite onoremenu
  430.         " Strip the special option keywords first
  431.         "     :h :syn-skipwhite*
  432.         let syn_list = substitute( 
  433.                     \    syn_list, '\<\(skipwhite\|skipnl\|skipempty\)\>'
  434.                     \    , "", 'g' 
  435.                     \ )
  436.  
  437.         " Now remove the remainder of the nextgroup=@someName lines
  438.         let syn_list = substitute( 
  439.                     \    syn_list, '\%(^\|\n\)\@<=\s*\(@\w\+\)'
  440.                     \    , "", 'g' 
  441.                     \ )
  442.  
  443.         if b:omni_syntax_use_iskeyword == 0
  444.             " There are a number of items which have non-word characters in
  445.             " them, *'T_F1'*.  vim.vim is one such file.
  446.             " This will replace non-word characters with spaces.
  447.             let syn_list = substitute( syn_list, '[^0-9A-Za-z_ ]', ' ', 'g' )
  448.         else
  449.             let accept_chars = ','.&iskeyword.','
  450.             " Remove all character ranges
  451.             " let accept_chars = substitute(accept_chars, ',[^,]\+-[^,]\+,', ',', 'g')
  452.             let accept_chars = substitute(accept_chars, ',\@<=[^,]\+-[^,]\+,', '', 'g')
  453.             " Remove all numeric specifications
  454.             " let accept_chars = substitute(accept_chars, ',\d\{-},', ',', 'g')
  455.             let accept_chars = substitute(accept_chars, ',\@<=\d\{-},', '', 'g')
  456.             " Remove all commas
  457.             let accept_chars = substitute(accept_chars, ',', '', 'g')
  458.             " Escape special regex characters
  459.             let accept_chars = escape(accept_chars, '\\/.*$^~[]' )
  460.             " Remove all characters that are not acceptable
  461.             let syn_list = substitute( syn_list, '[^0-9A-Za-z_ '.accept_chars.']', ' ', 'g' )
  462.         endif
  463.  
  464.         if b:omni_syntax_minimum_length > 0
  465.             " If the user specified a minimum length, enforce it
  466.             let syn_list = substitute(' '.syn_list.' ', ' \S\{,'.b:omni_syntax_minimum_length.'}\ze ', ' ', 'g')
  467.         endif
  468.     else
  469.         let syn_list = ''
  470.     endif
  471.  
  472.     return syn_list
  473. endfunction
  474.