aboutsummaryrefslogtreecommitdiff
path: root/vim/bundle/YouCompleteMe/python/ycm/syntax_parse.py
diff options
context:
space:
mode:
Diffstat (limited to 'vim/bundle/YouCompleteMe/python/ycm/syntax_parse.py')
-rw-r--r--vim/bundle/YouCompleteMe/python/ycm/syntax_parse.py224
1 files changed, 224 insertions, 0 deletions
diff --git a/vim/bundle/YouCompleteMe/python/ycm/syntax_parse.py b/vim/bundle/YouCompleteMe/python/ycm/syntax_parse.py
new file mode 100644
index 0000000..e6ea1d5
--- /dev/null
+++ b/vim/bundle/YouCompleteMe/python/ycm/syntax_parse.py
@@ -0,0 +1,224 @@
+# Copyright (C) 2013 Google Inc.
+#
+# This file is part of YouCompleteMe.
+#
+# YouCompleteMe is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# YouCompleteMe is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import unicode_literals
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from future import standard_library
+standard_library.install_aliases()
+from builtins import * # noqa
+
+from future.utils import itervalues
+import re
+import vim
+from ycm import vimsupport
+
+SYNTAX_GROUP_REGEX = re.compile(
+ r"""^
+ (?P<group_name>\w+)
+ \s+
+ xxx
+ \s+
+ (?P<content>.+?)
+ $""",
+ re.VERBOSE )
+
+KEYWORD_REGEX = re.compile( r'^[\w,]+$' )
+
+SYNTAX_ARGUMENT_REGEX = re.compile(
+ r"^\w+=.*$" )
+
+SYNTAX_ARGUMENTS = set([
+ 'cchar',
+ 'conceal',
+ 'contained',
+ 'containedin',
+ 'nextgroup',
+ 'skipempty',
+ 'skipnl',
+ 'skipwhite',
+ 'transparent',
+ 'concealends',
+ 'contains',
+ 'display',
+ 'extend',
+ 'fold',
+ 'oneline',
+ 'keepend',
+ 'excludenl',
+])
+
+# We want to parse lines starting with these args
+ALLOWED_SYNTAX_ARGUMENTS = set([
+ 'contained',
+])
+
+# These are the parent groups from which we want to extract keywords
+ROOT_GROUPS = set([
+ 'Statement',
+ 'Boolean',
+ 'Include',
+ 'Type',
+ 'Identifier',
+])
+
+
+class SyntaxGroup( object ):
+ def __init__( self, name, lines = None ):
+ self.name = name
+ self.lines = lines if lines else []
+ self.children = []
+
+
+def SyntaxKeywordsForCurrentBuffer():
+ vim.command( 'redir => b:ycm_syntax' )
+ vim.command( 'silent! syntax list' )
+ vim.command( 'redir END' )
+ syntax_output = vimsupport.VimExpressionToPythonType( 'b:ycm_syntax' )
+ return _KeywordsFromSyntaxListOutput( syntax_output )
+
+
+def _KeywordsFromSyntaxListOutput( syntax_output ):
+ group_name_to_group = _SyntaxGroupsFromOutput( syntax_output )
+ _ConnectGroupChildren( group_name_to_group )
+
+ groups_with_keywords = []
+ for root_group in ROOT_GROUPS:
+ groups_with_keywords.extend(
+ _GetAllDescendentats( group_name_to_group[ root_group ] ) )
+
+ keywords = []
+ for group in groups_with_keywords:
+ keywords.extend( _ExtractKeywordsFromGroup( group ) )
+ return set( keywords )
+
+
+def _SyntaxGroupsFromOutput( syntax_output ):
+ group_name_to_group = _CreateInitialGroupMap()
+ lines = syntax_output.split( '\n' )
+ looking_for_group = True
+
+ current_group = None
+ for line in lines:
+ if not line:
+ continue
+
+ match = SYNTAX_GROUP_REGEX.search( line )
+ if match:
+ if looking_for_group:
+ looking_for_group = False
+ else:
+ group_name_to_group[ current_group.name ] = current_group
+
+ current_group = SyntaxGroup( match.group( 'group_name' ),
+ [ match.group( 'content').strip() ] )
+ else:
+ if looking_for_group:
+ continue
+
+ if line[ 0 ] == ' ' or line[ 0 ] == '\t':
+ current_group.lines.append( line.strip() )
+
+ if current_group:
+ group_name_to_group[ current_group.name ] = current_group
+ return group_name_to_group
+
+
+def _CreateInitialGroupMap():
+ def AddToGroupMap( name, parent ):
+ new_group = SyntaxGroup( name )
+ group_name_to_group[ name ] = new_group
+ parent.children.append( new_group )
+
+ statement_group = SyntaxGroup( 'Statement' )
+ type_group = SyntaxGroup( 'Type' )
+ identifier_group = SyntaxGroup( 'Identifier' )
+
+ # See `:h group-name` for details on how the initial group hierarchy is built
+ group_name_to_group = {
+ 'Statement': statement_group,
+ 'Type': type_group,
+ 'Boolean': SyntaxGroup( 'Boolean' ),
+ 'Include': SyntaxGroup( 'Include' ),
+ 'Identifier': identifier_group,
+ }
+
+ AddToGroupMap( 'Conditional', statement_group )
+ AddToGroupMap( 'Repeat' , statement_group )
+ AddToGroupMap( 'Label' , statement_group )
+ AddToGroupMap( 'Operator' , statement_group )
+ AddToGroupMap( 'Keyword' , statement_group )
+ AddToGroupMap( 'Exception' , statement_group )
+
+ AddToGroupMap( 'StorageClass', type_group )
+ AddToGroupMap( 'Structure' , type_group )
+ AddToGroupMap( 'Typedef' , type_group )
+
+ AddToGroupMap( 'Function', identifier_group )
+
+ return group_name_to_group
+
+
+def _ConnectGroupChildren( group_name_to_group ):
+ def GetParentNames( group ):
+ links_to = 'links to '
+ parent_names = []
+ for line in group.lines:
+ if line.startswith( links_to ):
+ parent_names.append( line[ len( links_to ): ] )
+ return parent_names
+
+ for group in itervalues( group_name_to_group ):
+ parent_names = GetParentNames( group )
+
+ for parent_name in parent_names:
+ try:
+ parent_group = group_name_to_group[ parent_name ]
+ except KeyError:
+ continue
+ parent_group.children.append( group )
+
+
+def _GetAllDescendentats( root_group ):
+ descendants = []
+ for child in root_group.children:
+ descendants.append( child )
+ descendants.extend( _GetAllDescendentats( child ) )
+ return descendants
+
+
+def _ExtractKeywordsFromGroup( group ):
+ keywords = []
+ for line in group.lines:
+ if line.startswith( 'links to ' ):
+ continue
+
+ words = line.split()
+ if not words or ( words[ 0 ] in SYNTAX_ARGUMENTS and
+ words[ 0 ] not in ALLOWED_SYNTAX_ARGUMENTS ):
+ continue
+
+ for word in words:
+ if ( word not in SYNTAX_ARGUMENTS and
+ not SYNTAX_ARGUMENT_REGEX.match( word ) and
+ KEYWORD_REGEX.match( word ) ):
+
+ if word.endswith( ',' ):
+ word = word[ :-1 ]
+ keywords.append( word )
+ return keywords