public async Task Generate() { if (Configuration.CalculateRoslynSemantics) { this.Text = await Document.GetTextAsync(); this.Root = await Document.GetSyntaxRootAsync(); this.SemanticModel = await Document.GetSemanticModelAsync(); this.SemanticFactsService = WorkspaceHacks.GetSemanticFactsService(this.Document); this.SyntaxFactsService = WorkspaceHacks.GetSyntaxFactsService(this.Document); var semanticFactsServiceType = SemanticFactsService.GetType(); var isWrittenTo = semanticFactsServiceType.GetMethod("IsWrittenTo"); this.isWrittenToDelegate = (Func <SemanticModel, SyntaxNode, CancellationToken, bool>) Delegate.CreateDelegate(typeof(Func <SemanticModel, SyntaxNode, CancellationToken, bool>), SemanticFactsService, isWrittenTo); var syntaxFactsServiceType = SyntaxFactsService.GetType(); var getBindableParent = syntaxFactsServiceType.GetMethod("GetBindableParent"); this.getBindableParentDelegate = (Func <SyntaxToken, SyntaxNode>) Delegate.CreateDelegate(typeof(Func <SyntaxToken, SyntaxNode>), SyntaxFactsService, getBindableParent); this.DeclaredSymbols = new HashSet <ISymbol>(); Interlocked.Increment(ref projectGenerator.DocumentCount); Interlocked.Add(ref projectGenerator.LinesOfCode, Text.Lines.Count); Interlocked.Add(ref projectGenerator.BytesOfCode, Text.Length); } CalculateDocumentDestinationPath(); CalculateRelativePathToRoot(); // add the file itself as a "declared symbol", so that clicking on document in search // results redirects to the document ProjectGenerator.AddDeclaredSymbolToRedirectMap( this.projectGenerator.SymbolIDToListOfLocationsMap, SymbolIdService.GetId(this.Document), documentRelativeFilePathWithoutHtmlExtension, 0); if (File.Exists(documentDestinationFilePath)) { // someone already generated this file, likely a shared linked file from elsewhere return; } this.classifier = new Classification(); Log.Write(documentDestinationFilePath); try { var directoryName = Path.GetDirectoryName(documentDestinationFilePath); var sanitized = Paths.SanitizeFolder(directoryName); if (directoryName != sanitized) { Log.Exception("Illegal characters in path: " + directoryName + " Project: " + this.projectGenerator.AssemblyName); } if (Configuration.CreateFoldersOnDisk) { Directory.CreateDirectory(directoryName); } } catch (PathTooLongException) { // there's one case where a path is too long - we don't care enough about it return; } if (Configuration.WriteDocumentsToDisk) { using (var streamWriter = new StreamWriter( documentDestinationFilePath, append: false, encoding: Encoding.UTF8)) { await GenerateHtml(streamWriter); } } else { using (var memoryStream = new MemoryStream()) using (var streamWriter = new StreamWriter(memoryStream)) { await GeneratePre(streamWriter); } } }
private void CalculateRelativePathToRoot() { this.relativePathToRoot = Paths.CalculateRelativePathToRoot(documentDestinationFilePath, SolutionDestinationFolder); }
private void CalculateDocumentDestinationPath() { documentRelativeFilePathWithoutHtmlExtension = Paths.GetRelativeFilePathInProject(Document); documentDestinationFilePath = Path.Combine(ProjectDestinationFolder, documentRelativeFilePathWithoutHtmlExtension) + ".html"; }
private static void Main(string[] args) { if (args.Length == 0) { PrintUsage(); return; } var projects = new List <string>(); var properties = new Dictionary <string, string>(); var emitAssemblyList = false; var force = false; var noBuiltInFederations = false; var offlineFederations = new Dictionary <string, string>(); var federations = new HashSet <string>(); var serverPathMappings = new Dictionary <string, string>(); var pluginBlacklist = new List <string>(); foreach (var arg in args) { if (arg.StartsWith("/out:")) { Paths.SolutionDestinationFolder = Path.GetFullPath(arg.Substring("/out:".Length).StripQuotes()); continue; } if (arg.StartsWith("/serverPath:")) { var mapping = arg.Substring("/serverPath:".Length).StripQuotes(); var parts = mapping.Split('='); if (parts.Length != 2) { Log.Write($"Invalid Server Path: '{mapping}'", ConsoleColor.Red); continue; } serverPathMappings.Add(Path.GetFullPath(parts[0]), parts[1]); continue; } if (arg == "/force") { force = true; continue; } if (arg.StartsWith("/in:")) { string inputPath = arg.Substring("/in:".Length).StripQuotes(); try { if (!File.Exists(inputPath)) { continue; } string[] paths = File.ReadAllLines(inputPath); foreach (string path in paths) { AddProject(projects, path); } } catch { Log.Write("Invalid argument: " + arg, ConsoleColor.Red); } continue; } if (arg.StartsWith("/p:")) { var match = Regex.Match(arg, "/p:(?<name>[^=]+)=(?<value>.+)"); if (match.Success) { var propertyName = match.Groups["name"].Value; var propertyValue = match.Groups["value"].Value; properties.Add(propertyName, propertyValue); continue; } } if (arg == "/assemblylist") { emitAssemblyList = true; continue; } if (arg == "/nobuiltinfederations") { noBuiltInFederations = true; Log.Message("Disabling built-in federations."); continue; } if (arg.StartsWith("/federation:")) { string server = arg.Substring("/federation:".Length); Log.Message($"Adding federation '{server}'."); federations.Add(server); continue; } if (arg.StartsWith("/offlinefederation:")) { var match = Regex.Match(arg, "/offlinefederation:(?<server>[^=]+)=(?<file>.+)"); if (match.Success) { var server = match.Groups["server"].Value; var assemblyListFileName = match.Groups["file"].Value; offlineFederations[server] = assemblyListFileName; Log.Message($"Adding federation '{server}' (offline from '{assemblyListFileName}')."); continue; } continue; } if (string.Equals(arg, "/noplugins", StringComparison.OrdinalIgnoreCase)) { SolutionGenerator.LoadPlugins = false; continue; } if (arg.StartsWith("/noplugin:")) { pluginBlacklist.Add(arg.Substring("/noplugin:".Length)); continue; } try { AddProject(projects, arg); } catch (Exception ex) { Log.Write("Exception: " + ex.ToString(), ConsoleColor.Red); } } if (projects.Count == 0) { PrintUsage(); return; } AssertTraceListener.Register(); AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionHandler.HandleFirstChanceException; HelpMSBuildFindToolset(); if (Paths.SolutionDestinationFolder == null) { Paths.SolutionDestinationFolder = Path.Combine(Microsoft.SourceBrowser.Common.Paths.BaseAppFolder, "Index"); } var websiteDestination = Paths.SolutionDestinationFolder; // Warning, this will delete and recreate your destination folder Paths.PrepareDestinationFolder(force); Paths.SolutionDestinationFolder = Path.Combine(Paths.SolutionDestinationFolder, "index"); //The actual index files need to be written to the "index" subdirectory Directory.CreateDirectory(Paths.SolutionDestinationFolder); Log.ErrorLogFilePath = Path.Combine(Paths.SolutionDestinationFolder, Log.ErrorLogFile); Log.MessageLogFilePath = Path.Combine(Paths.SolutionDestinationFolder, Log.MessageLogFile); using (Disposable.Timing("Generating website")) { var federation = new Federation(); if (!noBuiltInFederations) { federation.AddFederations(Federation.DefaultFederatedIndexUrls); } federation.AddFederations(federations); foreach (var entry in offlineFederations) { federation.AddFederation(entry.Key, entry.Value); } IndexSolutions(projects, properties, federation, serverPathMappings, pluginBlacklist); FinalizeProjects(emitAssemblyList, federation); WebsiteFinalizer.Finalize(websiteDestination, emitAssemblyList, federation); } }
private static void Main(string[] args) { if (args.Length == 0) { PrintUsage(); return; } var projects = new List <string>(); var properties = new Dictionary <string, string>(); var emitAssemblyList = false; var force = false; var noBuiltInFederations = false; var offlineFederations = new Dictionary <string, string>(); var federations = new HashSet <string>(); foreach (var arg in args) { if (arg.StartsWith("/out:")) { Paths.SolutionDestinationFolder = Path.GetFullPath(arg.Substring("/out:".Length).StripQuotes()); continue; } if (arg == "/force") { force = true; continue; } if (arg.StartsWith("/in:")) { string inputPath = arg.Substring("/in:".Length).StripQuotes(); try { if (!File.Exists(inputPath)) { continue; } string[] paths = File.ReadAllLines(inputPath); foreach (string path in paths) { AddProject(projects, path); } } catch { Log.Write("Invalid argument: " + arg, ConsoleColor.Red); } continue; } if (arg.StartsWith("/p:")) { var match = Regex.Match(arg, "/p:(?<name>[^=]+)=(?<value>.+)"); if (match.Success) { var propertyName = match.Groups["name"].Value; var propertyValue = match.Groups["value"].Value; properties.Add(propertyName, propertyValue); continue; } } if (arg == "/assemblylist") { emitAssemblyList = true; continue; } if (arg == "/nobuiltinfederations") { noBuiltInFederations = true; Log.Message("Disabling built-in federations."); continue; } if (arg.StartsWith("/federation:")) { string server = arg.Substring("/federation:".Length); Log.Message($"Adding federation '{server}'."); federations.Add(server); } if (arg.StartsWith("/offlinefederation:")) { var match = Regex.Match(arg, "/offlinefederation:(?<server>[^=]+)=(?<file>.+)"); if (match.Success) { var server = match.Groups["server"].Value; var assemblyListFileName = match.Groups["file"].Value; offlineFederations[server] = assemblyListFileName; Log.Message($"Adding federation '{server}' (offline from '{assemblyListFileName}')."); continue; } } try { AddProject(projects, arg); } catch (Exception ex) { Log.Write("Exception: " + ex.ToString(), ConsoleColor.Red); } } if (projects.Count == 0) { PrintUsage(); return; } AssertTraceListener.Register(); AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionHandler.HandleFirstChanceException; if (Paths.SolutionDestinationFolder == null) { Paths.SolutionDestinationFolder = Path.Combine(Microsoft.SourceBrowser.Common.Paths.BaseAppFolder, "Index"); } Log.ErrorLogFilePath = Path.Combine(Paths.SolutionDestinationFolder, Log.ErrorLogFile); Log.MessageLogFilePath = Path.Combine(Paths.SolutionDestinationFolder, Log.MessageLogFile); // Warning, this will delete and recreate your destination folder Paths.PrepareDestinationFolder(force); using (Disposable.Timing("Generating website")) { var federation = noBuiltInFederations ? new Federation(null) : new Federation(); foreach (var entry in offlineFederations) { federation.AddFederation(entry.Key, entry.Value); } IndexSolutions(projects, properties, federation); FinalizeProjects(emitAssemblyList, federation); } }
private HtmlElementInfo TryProcessGuid(Classification.Range range) { var text = range.Text; var spanStart = range.ClassifiedSpan.TextSpan.Start; var spanEnd = range.ClassifiedSpan.TextSpan.End; if (text.StartsWith("@", StringComparison.Ordinal)) { text = text.Substring(1); spanStart++; } if (text.StartsWith("\"", StringComparison.Ordinal) && text.EndsWith("\"", StringComparison.Ordinal) && text.Length >= 2) { spanStart++; spanEnd--; text = text.Substring(1, text.Length - 2); } // quick check to reject non-Guids even before trying to parse if (text.Length != 32 && text.Length != 36 && text.Length != 38) { return(null); } if (!Guid.TryParse(text, out Guid guid)) { return(null); } var symbolId = guid.ToString(); var referencesFilePath = Path.Combine( SolutionDestinationFolder, Constants.GuidAssembly, Constants.ReferencesFileName, symbolId + ".html"); string href = Paths.MakeRelativeToFile(referencesFilePath, documentDestinationFilePath); href = href.Replace('\\', '/'); var link = new HtmlElementInfo { Name = "a", Attributes = { { "href", href }, { "target", "n" }, }, DeclaredSymbolId = symbolId }; projectGenerator.AddReference( this.documentDestinationFilePath, Text, Constants.GuidAssembly, null, symbolId, spanStart, spanEnd, ReferenceKind.GuidUsage); return(link); }