internal FileItem(CommentTaskProvider provider, string fileName) { // Note: The caller should check FileUtility.IsValidPath(fileName) before invoking this constructor. this.provider = provider; this.FileName = fileName; this.hierarchyItems = EmptySet; this.lastModifiedTimeScannedUtc = MinDateTimeUtc; try { this.fileInfo = new FileInfo(fileName); this.scanInfo = ScanInfo.Get(this); } catch (Exception ex) { // We might not have access to the file, or the fileName parameter might contain a non-file name. // The latter condition should be very rare now since the caller is using FileUtility.IsValidPath. // An invalid file name should only get through to here if it's valid per Windows standard naming // rules but invalid on the target file system (e.g., if it's on a Unix system or on a CD). if (!IsAccessException(ex) && !(ex is NotSupportedException || ex is ArgumentException)) { throw; } // Make sure this FileItem is unscannable so nothing will try to use its null this.fileInfo member. this.scanInfo = ScanInfo.Unscannable; } }
private void MergeExtensions( List <string> extensionList, HashSet <Delimiter> delimiters, HashSet <Language> languageValues, HashSet <string> binaryExtensions) { ScanInfo scanInfo = new ScanInfo(delimiters, languageValues); foreach (string extension in extensionList) { if (binaryExtensions.Contains(extension)) { // If we get this error, then ScanInfo.xml has assigned the extension as both binary and non-binary. throw new InvalidOperationException(extension + " has already been listed as a binary extension in ScanInfo.xml."); } ScanInfo existingScanInfo; if (this.extensions.TryGetValue(extension, out existingScanInfo)) { ScanInfo mergedScanInfo = ScanInfo.Merge(scanInfo, existingScanInfo); this.extensions[extension] = mergedScanInfo; } else { this.extensions.TryAdd(extension, scanInfo); } } }
private static ScanInfo Merge(ScanInfo scanInfo1, ScanInfo scanInfo2) { ScanInfo result = new ScanInfo( scanInfo1.delimiters.Concat(scanInfo2.delimiters), scanInfo1.languages.Concat(scanInfo2.languages)); return(result); }
private static bool TryGetCustomExtensionScanInfo(string extension, Cache cache, ref ScanInfo scanInfo) { bool result = false; MainPackage package = MainPackage.Instance; if (package != null && !string.IsNullOrEmpty(extension) && extension.Length > 1 && extension[0] == '.') { using (RegistryKey studioUserRoot = package.UserRegistryRoot) { if (studioUserRoot != null) { // See if this is a custom file extension mapped to a language service. string extLogViewId = null; using (RegistryKey extKey = studioUserRoot.OpenSubKey(@"FileExtensionMapping\" + extension.Substring(1))) { if (extKey != null) { extLogViewId = (string)extKey.GetValue("LogViewID"); } } // If we found a LogViewID, then find which language service it goes with (if any). if (!string.IsNullOrEmpty(extLogViewId)) { ScanInfo matchedScanInfo = null; ScanLanguageServices( studioUserRoot, (langName, langGuid) => { bool matched = false; if (string.Equals(langGuid, extLogViewId, StringComparison.OrdinalIgnoreCase)) { Language language = Utilities.GetLanguage(langName, extension); ScanInfo languageScanInfo; if (cache.TryGet(language, out languageScanInfo)) { matchedScanInfo = languageScanInfo; matched = true; } } return(matched); }); if (matchedScanInfo != null) { scanInfo = matchedScanInfo; result = true; } } } } } return(result); }
public static bool TryGet(Language language, out ScanInfo scanInfo) { scanInfo = null; bool result = language != Language.Unknown && language != Language.PlainText && LazyCache.Value.TryGet(language, out scanInfo) && scanInfo != null && scanInfo.IsScannable; return(result); }
public static ScanInfo Get(FileItem file) { ScanInfo result; Cache cache = LazyCache.Value; string extension = Path.GetExtension(file.FileName); if (cache.TryGet(extension, out result)) { // Binary extensions will return the Unscannable instance. if (result.IsScannable) { // If the file is open in a document that is using a language that doesn't match one // associated with its file extension, then we need to include the language's info too. // We won't do this for PlainText because it has no comment delimiter, which can // cause ambiguities and duplicates if it's paired with an extension with known // delimiters. For example, .bat files have delimiters, but they open as PlainText. Language docLanguage = file.DocumentLanguage; if (docLanguage != Language.Unknown && docLanguage != Language.PlainText && !result.languages.Contains(docLanguage)) { ScanInfo languageScanInfo; if (cache.TryGet(docLanguage, out languageScanInfo)) { result = ScanInfo.Merge(result, languageScanInfo); } } } } else { // The file's extension is unknown, so try to match it by language if a document is open. // This allows us to handle user-assigned extensions (e.g., .scs for C#). Language docLanguage = file.DocumentLanguage; if (docLanguage != Language.Unknown) { cache.TryGet(docLanguage, out result); } if (result == null) { result = Infer(file, cache); } } return(result ?? Unscannable); }
private static ScanInfo Infer(FileItem file, Cache cache) { ScanInfo result = Unscannable; try { FileInfo fileInfo = new FileInfo(file.FileName); // The largest hand-maintained source code file I've ever encountered was almost 900K (in G. Millennium), // and it was over 25000 lines of spaghetti code. So I'm going to assume any file that's over 1MB // in size is either generated text or a binary file. const long MaxTextFileSize = 1048576; if (fileInfo.Exists && fileInfo.Length > 0 && fileInfo.Length <= MaxTextFileSize) { string extension = fileInfo.Extension; if (TryGetCustomExtensionScanInfo(extension, cache, ref result)) { cache.TryAdd(extension, result); } else { byte[] buffer = ReadInitialBlock(file, fileInfo); if (buffer != null && IsTextBuffer(buffer)) { // Use Language instead of .xml or .txt extensions here since a user could override those extensions. Language language = IsXmlBuffer(buffer) ? Language.XML : Language.PlainText; result = cache.Get(language); // Since we were actually able to read a buffer from the file, we'll save // this ScanInfo for use with other files using the same extension. cache.TryAdd(extension, result); } } } } catch (Exception ex) { if (!FileItem.IsAccessException(ex)) { throw; } result = Unscannable; } return(result); }
public bool TryAdd(string extension, ScanInfo scanInfo) { bool result = this.extensions.TryAdd(extension, scanInfo); return(result); }
public bool TryGet(Language language, out ScanInfo scanInfo) { bool result = this.languages.TryGetValue(language, out scanInfo); return(result); }
public bool TryGet(string extension, out ScanInfo scanInfo) { bool result = this.extensions.TryGetValue(extension, out scanInfo); return(result); }