37b706d108ef261a9ccb7273afbbdb5eda4241ef
[stack/conf/vim.git] / addons / TagHighlight / plugin / TagHighlight / module / generation.py
1 #!/usr/bin/env python
2 # Tag Highlighter:
3 #   Author:  A. S. Budden <abudden _at_ gmail _dot_ com>
4 # Copyright: Copyright (C) 2009-2011 A. S. Budden
5 #            Permission is hereby granted to use and distribute this code,
6 #            with or without modifications, provided that this copyright
7 #            notice is copied with it. Like anything else that's free,
8 #            the TagHighlight plugin is provided *as is* and comes with no
9 #            warranty of any kind, either expressed or implied. By using
10 #            this plugin, you agree that in no event will the copyright
11 #            holder be liable for any damages resulting from the use
12 #            of this software.
13
14 # ---------------------------------------------------------------------
15 from __future__ import print_function
16 import os
17 import re
18 from .utilities import GenerateValidKeywordRange, IsValidKeyword
19 from .debug import Debug
20
21 vim_synkeyword_arguments = [
22         'contains',
23         'oneline',
24         'fold',
25         'display',
26         'extend',
27         'contained',
28         'containedin',
29         'nextgroup',
30         'transparent',
31         'skipwhite',
32         'skipnl',
33         'skipempty'
34         ]
35
36 def CreateTypesFile(options, language, tags):
37     tag_types = list(tags.keys())
38     tag_types.sort()
39
40     Debug("Writing types file", "Information")
41
42     language_handler = options['language_handler'].GetLanguageHandler(language)
43
44     if options['check_keywords']:
45         iskeyword = GenerateValidKeywordRange(language_handler['IsKeyword'])
46         Debug("Is Keyword is {0!r}".format(iskeyword), "Information")
47
48     matchEntries = set()
49     vimtypes_entries = []
50
51
52     typesUsedByLanguage = list(options['language_handler'].GetKindList(language).values())
53     # TODO: This may be included elsewhere, but we'll leave it in for now
54     #clear_string = 'silent! syn clear ' + " ".join(typesUsedByLanguage)
55
56     vimtypes_entries = []
57     #vimtypes_entries.append(clear_string)
58
59     # Get the priority list from the language handler
60     priority = language_handler['Priority'][:]
61     # Reverse the priority such that highest priority
62     # is last.
63     priority.reverse()
64
65     fullTypeList = list(reversed(sorted(tags.keys())))
66     # Reorder type list according to priority sort order
67     allTypes = []
68     for thisType in priority:
69         if thisType in fullTypeList:
70             allTypes.append(thisType)
71             fullTypeList.remove(thisType)
72     # Add the ones not specified in priority
73     allTypes = fullTypeList + allTypes
74
75     Debug("Type priority list: " + repr(allTypes), "Information")
76
77     patternREs = []
78     for pattern in options['skip_patterns']:
79         patternREs.append(re.compile(pattern))
80
81     for thisType in allTypes:
82         keystarter = 'syn keyword ' + thisType
83         keycommand = keystarter
84         for keyword in tags[thisType]:
85             skip_this = False
86             if options['skip_reserved_keywords']:
87                 if keyword in language_handler['ReservedKeywords']:
88                     Debug('Skipping reserved word ' + keyword, 'Information')
89                     # Ignore this keyword
90                     continue
91             for pattern in patternREs:
92                 if pattern.search(keyword) != None:
93                     skip_this = True
94                     break
95             if skip_this:
96                 continue
97
98             if options['check_keywords']:
99                 # In here we should check that the keyword only matches
100                 # vim's \k parameter (which will be different for different
101                 # languages).  This is quite slow so is turned off by
102                 # default; however, it is useful for some things where the
103                 # default generated file contains a lot of rubbish.  It may
104                 # be worth optimising IsValidKeyword at some point.
105                 if not IsValidKeyword(keyword, iskeyword):
106                     matchDone = False
107                     if options['include_matches']:
108
109                         patternCharacters = "/@#':"
110                         charactersToEscape = '\\' + '~[]*.$^'
111
112                         for patChar in patternCharacters:
113                             if keyword.find(patChar) == -1:
114                                 escapedKeyword = keyword
115                                 for ch in charactersToEscape:
116                                     escapedKeyword = escapedKeyword.replace(ch, '\\' + ch)
117                                 if options['include_matches']:
118                                     matchEntries.add('syn match ' + thisType + ' ' + patChar + escapedKeyword + patChar)
119                                 matchDone = True
120                                 break
121
122                     if not matchDone:
123                         Debug("Skipping keyword '" + keyword + "'", "Information")
124
125                     continue
126
127
128             if keyword.lower() in vim_synkeyword_arguments:
129                 if not options['skip_vimkeywords']:
130                     matchEntries.add('syn match ' + thisType + ' /' + keyword + '/')
131                 continue
132
133             temp = keycommand + " " + keyword
134             if len(temp) >= 512:
135                 vimtypes_entries.append(keycommand)
136                 keycommand = keystarter
137             keycommand = keycommand + " " + keyword
138         if keycommand != keystarter:
139             vimtypes_entries.append(keycommand)
140
141     # Sort the matches
142     matchEntries = sorted(list(matchEntries))
143
144     if (len(matchEntries) + len(vimtypes_entries)) == 0:
145         # All keywords have been filtered out, give up
146         return
147
148     vimtypes_entries.append('')
149     vimtypes_entries += matchEntries
150
151     if options['include_locals']:
152         LocalTagType = ',CTagsLocalVariable'
153     else:
154         LocalTagType = ''
155
156     if options['types_file_name_override'] is not None and options['types_file_name_override'] != 'None':
157         type_file_name = options['types_file_name_override']
158     else:
159         type_file_name = options['types_file_prefix'] + '_' + language_handler['Suffix'] + '.' + options['types_file_extension']
160     filename = os.path.join(options['types_file_location'], type_file_name)
161     Debug("Filename is {0}\n".format(filename), "Information")
162
163     try:
164         # Have to open in binary mode as we want to write with Unix line endings
165         # The resulting file will then work with any Vim (Windows, Linux, Cygwin etc)
166         fh = open(filename, 'wb')
167     except IOError:
168         Debug("ERROR: Couldn't create {file}\n".format(file=outfile), "Error")
169         sys.exit(1)
170
171     try:
172         for line in vimtypes_entries:
173             try:
174                 fh.write(line.encode('ascii'))
175             except UnicodeDecodeError:
176                 Debug("Error decoding line '{0!r}'".format(line), "Error")
177                 fh.write('echoerr "Types generation error"\n'.encode('ascii'))
178             fh.write('\n'.encode('ascii'))
179     except IOError:
180         Debug("ERROR: Couldn't write {file} contents\n".format(file=outfile), "Error")
181         sys.exit(1)
182     finally:
183         fh.close()