6ae4b8fbe776d1ba04ce05e4c28054190183d750
[stack/conf/vim.git] / addons / TagHighlight / autoload / TagHighlight / Find.vim
1 " Tag Highlighter:
2 "   Author:  A. S. Budden <abudden _at_ gmail _dot_ com>
3 " Copyright: Copyright (C) 2009-2011 A. S. Budden
4 "            Permission is hereby granted to use and distribute this code,
5 "            with or without modifications, provided that this copyright
6 "            notice is copied with it. Like anything else that's free,
7 "            the TagHighlight plugin is provided *as is* and comes with no
8 "            warranty of any kind, either expressed or implied. By using
9 "            this plugin, you agree that in no event will the copyright
10 "            holder be liable for any damages resulting from the use
11 "            of this software.
12
13 " ---------------------------------------------------------------------
14 try
15         if &cp || v:version < 700 || (exists('g:loaded_TagHLFind') && (g:plugin_development_mode != 1))
16                 throw "Already loaded"
17         endif
18 catch
19         finish
20 endtry
21 let g:loaded_TagHLFind = 1
22
23 " Tools for finding files.  When generating the tags and types file, we need
24 " to decide where to place it.  If the user has configured the mode in which
25 " everything is based on the current directory (which works well with the
26 " project plugin), the current directory is what we use.  If the user wants to
27 " search up for a tags file, we can look for an existing tags file and stop
28 " when we find one, starting either from the current directory or source
29 " directory.  If we don't, either use the current directory or the source file
30 " directory (configuration).
31 "
32 " It should also be possible to place the tags file in a remote location and
33 " use either the current directory, source directory or explicitly set
34 " directory for the base of the scan.
35
36 " Option structure:
37 "
38 " [gb]:TagHighlightSettings:
39 "       DefaultDirModePriority:[Explicit,UpFromCurrent,UpFromFile,CurrentDirectory,FileDirectory]
40 "       TagFileDirModePriority:["Default"] or as above
41 "       TypesFileDirModePriority:As tag file
42 "       ConfigFileDirModePriority:As tag file
43 "       DefaultDirModeSearchWildcard:'' (look for tags file) or something specific (*.uvopt)?
44 "       MaxDirSearchLevels: (integer)
45 "
46 " Explicit Locations:
47 "
48 "  [gb]:TagHighlightSettings:
49 "    TagFileDirectory:str (NONE)
50 "    TagFileName:str (tags)
51 "    TypesFileDirectory:str (NONE)
52 "    TypesPrefix:str (types)
53 "    ProjectConfigFileName:str (taghl_config.txt)
54 "    ProjectConfigFileDirectory:str (NONE)
55
56 function! TagHighlight#Find#LocateFile(which, suffix)
57         call TagHLDebug("Locating file " . a:which . " with suffix " . a:suffix, 'Information')
58
59         " a:which is 'TAGS', 'TYPES', 'CONFIG'
60         let default_priority = TagHighlight#Option#GetOption('DefaultDirModePriority')
61         call TagHLDebug("Priority: " . string(default_priority), "Information")
62         let default_search_wildcards = TagHighlight#Option#GetOption('DefaultDirModeSearchWildcards')
63
64
65         let file = expand('<afile>')
66         if len(file) == 0
67                 let file = expand('%')
68         endif
69
70         if a:which == 'TAGS'
71                 " Suffix is ignored here
72                 let filename = TagHighlight#Option#GetOption('TagFileName')
73                 let search_priority = TagHighlight#Option#GetOption('TagFileDirModePriority')
74                 let explicit_location = TagHighlight#Option#GetOption('TagFileDirectory')
75                 let search_wildcards = TagHighlight#Option#GetOption('TagFileSearchWildcards')
76         elseif a:which == 'TYPES'
77                 let filename = TagHighlight#Option#GetOption('TypesFilePrefix') . '_' .
78                                         \ a:suffix . "." .
79                                         \ TagHighlight#Option#GetOption('TypesFileExtension')
80                 let search_priority = TagHighlight#Option#GetOption('TypesFileDirModePriority')
81                 let explicit_location = TagHighlight#Option#GetOption('TypesFileDirectory')
82                 let search_wildcards = TagHighlight#Option#GetOption('TypesFileSearchWildcards')
83         elseif a:which == 'CONFIG'
84                 " Suffix is ignored here
85                 let filename = TagHighlight#Option#GetOption('ProjectConfigFileName')
86                 let search_priority = TagHighlight#Option#GetOption('ProjectConfigFileDirModePriority')
87                 let explicit_location = TagHighlight#Option#GetOption('ProjectConfigFileDirectory')
88                 let search_wildcards = TagHighlight#Option#GetOption('ProjectConfigFileSearchWildcards')
89         else
90                 throw "Unrecognised file"
91         endif
92
93         if search_wildcards[0] == 'Default'
94                 let search_wildcards = default_search_wildcards
95         endif
96
97         if search_priority[0] == 'Default'
98                 let search_priority = default_priority
99         endif
100
101         " Ensure there's no trailing slash on 'explicit location'
102         if explicit_location[len(explicit_location)-1] == '/'
103                 let explicit_location = explicit_location[:len(explicit_location)-2]
104         endif
105
106         " Result contains 'Found','FullPath','Directory','Filename','Exists']
107         let result = {}
108
109         for search_mode in search_priority
110                 if search_mode == 'Explicit' && explicit_location != 'None'
111                         " Use explicit location, overriding everything else
112                         call TagHLDebug('Using explicit location', 'Information')
113                         let result['Directory'] = explicit_location
114                         let result['Filename'] = filename
115                 elseif search_mode == 'UpFromCurrent'
116                         " Start in the current directory and search up
117                         let dir = fnamemodify('.',':p:h')
118                         let result = s:ScanUp(dir, search_wildcards)
119                         if has_key(result, 'Directory')
120                                 call TagHLDebug('Found location with UpFromCurrent', 'Information')
121                                 let result['Filename'] = filename
122                         endif
123                 elseif search_mode == 'UpFromFile'
124                         " Start in the directory containing the current file and search up
125                         let dir = fnamemodify(file,':p:h')
126                         let result = s:ScanUp(dir, search_wildcards)
127                         if has_key(result, 'Directory')
128                                 call TagHLDebug('Found location with UpFromFile', 'Information')
129                                 let result['Filename'] = filename
130                         endif
131                 elseif search_mode == 'CurrentDirectory'
132                         call TagHLDebug('Using current directory: ' . fnamemodify('.', ':p:h'), 'Information')
133                         let result['Directory'] = fnamemodify('.',':p:h')
134                         let result['Filename'] = filename
135                 elseif search_mode == 'FileDirectory'
136                         call TagHLDebug('Using file directory: ' . fnamemodify(file, ':p:h'), 'Information')
137                         let result['Directory'] = fnamemodify(file,':p:h')
138                         let result['Filename'] = filename
139                 endif
140                 if has_key(result, 'Directory')
141                         let result['FullPath'] = result['Directory'] . '/' . result['Filename']
142                         let result['Found'] = 1
143                         call TagHLDebug('Found file location: ' . result['FullPath'], 'Information')
144                         if filereadable(result['FullPath'])
145                                 call TagHLDebug('File exists', 'Information')
146                                 let result['Exists'] = 1
147                         else
148                                 " Handle wildcards
149                                 let expansion = split(glob(result['FullPath'], 1), '\n')
150                                 let wildcard_match = 0
151                                 if len(expansion) > 0
152                                         for entry in expansion
153                                                 if filereadable(entry)
154                                                         let result['FullPath'] = entry
155                                                         let result['Exists'] = 1
156                                                         let wildcard_match = 1
157                                                         break
158                                                 endif
159                                         endfor
160                                 endif
161
162                                 if wildcard_match == 0
163                                         call TagHLDebug('File does not exist', 'Information')
164                                         let result['Exists'] = 0
165                                 endif
166                         endif
167                         break
168                 endif
169         endfor
170
171         if ! has_key(result, 'Directory')
172                 call TagHLDebug("Couldn't find path", 'Warning')
173                 let result = {'Found': 0, 'Exists': 0}
174         endif
175
176         return result
177 endfunction
178
179 function! s:ScanUp(dir, wildcards)
180         let result = {}
181         let max_levels = TagHighlight#Option#GetOption('MaxDirSearchLevels')
182         let levels = 0
183         let new_dir = a:dir
184         let dir = ''
185         let found = 0
186
187         call TagHLDebug("Searching up from " . a:dir . " for " . string(a:wildcards), 'Information')
188
189         " new_dir != dir check looks for the root directory
190         while new_dir != dir
191                 let dir = new_dir
192                 let new_dir = fnamemodify(dir, ':h')
193                 
194                 call TagHLDebug("Trying " . dir, "Information")
195                 for wildcard in a:wildcards
196                         let glob_pattern = dir
197                         if glob_pattern[len(glob_pattern)-1] != '/'
198                                 let glob_pattern .= '/'
199                         endif
200                         let glob_pattern .= wildcard
201                         let glob_result = split(glob(glob_pattern), "\n")
202                         if len(glob_result) > 0
203                                 for r in glob_result
204                                         if filereadable(r)
205                                                 let found = 1
206                                         endif
207                                 endfor
208                                 if found
209                                         call TagHLDebug("Found match: " . dir . " (" . glob_pattern . ")", "Information")
210                                         let result['Directory'] = dir
211                                         let found = 1
212                                         break
213                                 else
214                                         call TagHLDebug("Wildcard matches were not readable (directory?)", "Information")
215                                 endif
216                         endif
217                 endfor
218                 if found
219                         break
220                 endif
221
222                 " Check for recursion limit
223                 let levels += 1
224                 if (max_levels > 0) && (levels >= max_levels)
225                         call TagHLDebug("Hit recursion limit", "Information")
226                         break
227                 endif
228         endwhile
229         if new_dir == dir
230                 " Must have reached root directory
231                 call TagHLDebug("Reached root directory and stopped", "Information")
232         endif
233         return result
234 endfunction