private bool MatchTitle(BlockProcessor processor, ref StringSlice slice, ref CodeSnippet codeSnippet) { if (slice.CurrentChar != '"') { return(false); } var title = StringBuilderCache.Local(); var c = slice.NextChar(); var hasEscape = false; while (c != '\0' && (c != '"' || hasEscape)) { if (c == '\\' && !hasEscape) { hasEscape = true; } else { title.Append(c); hasEscape = false; } c = slice.NextChar(); } codeSnippet.Title = title.ToString().Trim(); if (c == '"') { slice.NextChar(); return(true); } return(false); }
public override BlockState TryOpen(BlockProcessor processor) { if (processor.IsCodeIndent) { return(BlockState.None); } // Sample: [!code-javascript[Main](../jquery.js?name=testsnippet#tag "title")] var slice = processor.Line; if (!ExtensionsHelper.MatchStart(ref slice, StartString, false)) { return(BlockState.None); } var codeSnippet = new CodeSnippet(this); MatchLanguage(processor, ref slice, ref codeSnippet); if (!MatchName(processor, ref slice, ref codeSnippet)) { return(BlockState.None); } if (!MatchPath(processor, ref slice, ref codeSnippet)) { return(BlockState.None); } MatchQuery(processor, ref slice, ref codeSnippet); MatchTitle(processor, ref slice, ref codeSnippet); ExtensionsHelper.SkipWhitespace(ref slice); if (slice.CurrentChar == ')') { slice.NextChar(); ExtensionsHelper.SkipWhitespace(ref slice); if (slice.CurrentChar == ']') { var codeSnippetEnd = slice.Start; slice.NextChar(); ExtensionsHelper.SkipWhitespace(ref slice); if (slice.CurrentChar == '\0') { // slice finished its task, re-use it for Raw content slice.Start = processor.Line.Start; slice.End = codeSnippetEnd; codeSnippet.Raw = slice.ToString(); codeSnippet.Column = processor.Column; codeSnippet.Line = processor.LineIndex; processor.NewBlocks.Push(codeSnippet); return(BlockState.BreakDiscard); } } } return(BlockState.None); }
private bool MatchQuery(BlockProcessor processor, ref StringSlice slice, ref CodeSnippet codeSnippet) { var questionMarkMatched = MatchQuestionMarkQuery(processor, ref slice, ref codeSnippet); var bookMarkMatched = MatchBookMarkQuery(processor, ref slice, ref codeSnippet); return(questionMarkMatched || bookMarkMatched); }
private bool MatchLanguage(BlockProcessor processor, ref StringSlice slice, ref CodeSnippet codeSnippet) { if (slice.CurrentChar != '-') { return(false); } var language = StringBuilderCache.Local(); var c = slice.NextChar(); while (c != '\0' && c != '[') { language.Append(c); c = slice.NextChar(); } codeSnippet.Language = language.ToString().Trim(); return(true); }
private bool MatchPath(BlockProcessor processor, ref StringSlice slice, ref CodeSnippet codeSnippet) { ExtensionsHelper.SkipWhitespace(ref slice); if (slice.CurrentChar != '(') { return(false); } var c = slice.NextChar(); var bracketNeedToMatch = 0; var path = StringBuilderCache.Local(); var hasEscape = false; while (c != '\0' && (hasEscape || (c != '#' && c != '?' && c != '"' && (c != ')' || bracketNeedToMatch > 0)))) { if (c == '\\' && !hasEscape) { hasEscape = true; } else { if (c == '(' && !hasEscape) { bracketNeedToMatch++; } if (c == ')' && !hasEscape) { bracketNeedToMatch--; } path.Append(c); hasEscape = false; } c = slice.NextChar(); } codeSnippet.CodePath = path.ToString().Trim(); return(true); }
public bool Render(HtmlRenderer renderer, MarkdownObject markdownObject, Action <string> logWarning) { var block = (TripleColonBlock)markdownObject; block.Attributes.TryGetValue("id", out var currentId); //it's okay if this is null block.Attributes.TryGetValue("range", out var currentRange); //it's okay if this is null block.Attributes.TryGetValue("source", out var currentSource); //source has already been checked above var(code, codePath) = _context.ReadFile(currentSource, block); if (string.IsNullOrEmpty(code)) { logWarning($"The code snippet \"{currentSource}\" could not be found."); return(false); } //var updatedCode = GetCodeSnippet(currentRange, currentId, code, logError).TrimEnd(); var htmlCodeSnippetRenderer = new HtmlCodeSnippetRenderer(_context); var snippet = new CodeSnippet(null); snippet.CodePath = currentSource; snippet.TagName = currentId; HtmlCodeSnippetRenderer.TryGetLineRanges(currentRange, out var ranges); snippet.CodeRanges = ranges; var updatedCode = htmlCodeSnippetRenderer.GetContent(code, snippet); updatedCode = ExtensionsHelper.Escape(updatedCode).TrimEnd(); if (updatedCode == string.Empty) { logWarning($"It looks like your code snippet was not rendered. Try range instead."); return(false); } renderer.WriteLine("<pre>"); renderer.Write("<code").WriteAttributes(block).Write(">"); renderer.WriteLine(updatedCode); renderer.WriteLine("</code></pre>"); return(true); }
private bool TryParseQuery(string queryString, ref CodeSnippet codeSnippet) { if (string.IsNullOrEmpty(queryString)) { return(false); } var splitQueryItems = queryString.Split(new[] { '&' }); int start = -1, end = -1; foreach (var queryItem in splitQueryItems) { var keyValueSplit = queryItem.Split(new[] { '=' }); if (keyValueSplit.Length != 2) { return(false); } var key = keyValueSplit[0]; var value = keyValueSplit[1]; List <CodeRange> temp; switch (key.ToLower()) { case "name": codeSnippet.TagName = value; break; case "start": if (!int.TryParse(value, out start)) { return(false); } end = start; break; case "end": if (!int.TryParse(value, out end)) { return(false); } break; case "range": if (!TryGetLineRanges(value, out temp)) { return(false); } codeSnippet.CodeRanges = temp; break; case "highlight": if (!TryGetLineRanges(value, out temp)) { return(false); } codeSnippet.HighlightRanges = temp; break; case "dedent": int dedent; if (!int.TryParse(value, out dedent)) { return(false); } codeSnippet.DedentLength = dedent; break; default: return(false); } } if (start != -1 && end != -1) { codeSnippet.StartEndRange = new CodeRange { Start = start, End = end }; } return(true); }
private bool MatchBookMarkQuery(BlockProcessor processor, ref StringSlice slice, ref CodeSnippet codeSnippet) { if (slice.CurrentChar != '#') { return(false); } var queryChar = slice.CurrentChar; var query = StringBuilderCache.Local(); var c = slice.NextChar(); while (c != '\0' && c != '"' && c != ')') { query.Append(c); c = slice.NextChar(); } var queryString = query.ToString().Trim(); CodeRange codeRange; if (TryGetLineRange(queryString, out codeRange)) { codeSnippet.BookMarkRange = codeRange; } else { codeSnippet.TagName = queryString; } return(true); }
private bool MatchQuestionMarkQuery(BlockProcessor processor, ref StringSlice slice, ref CodeSnippet codeSnippet) { if (slice.CurrentChar != '?') { return(false); } var queryChar = slice.CurrentChar; var query = StringBuilderCache.Local(); var c = slice.NextChar(); while (c != '\0' && c != '"' && c != ')' && c != '#') { query.Append(c); c = slice.NextChar(); } var queryString = query.ToString().Trim(); return(TryParseQuery(queryString, ref codeSnippet)); }
private string GetGitUrl(CodeSnippet obj) { // TODO: Disable to get git URL of code snippet return(null); }
public bool TryProcessAttributes(IDictionary <string, string> attributes, out HtmlAttributes htmlAttributes, out IDictionary <string, string> renderProperties, Action <string> logError, Action <string> logWarning, TripleColonBlock block) { htmlAttributes = null; renderProperties = new Dictionary <string, string>(); var source = string.Empty; var range = string.Empty; var id = string.Empty; var highlight = string.Empty; var language = string.Empty; var interactive = string.Empty; foreach (var attribute in attributes) { var name = attribute.Key; var value = attribute.Value; switch (name) { case "source": source = value; break; case "range": range = value; break; case "id": id = value; break; case "highlight": highlight = value; break; case "language": language = value; break; case "interactive": interactive = value; break; default: logError($"Unexpected attribute \"{name}\"."); return(false); } } if (string.IsNullOrEmpty(source)) { logError("source is a required attribute. Please ensure you have specified a source attribute"); return(false); } if (string.IsNullOrEmpty(language)) { language = InferLanguageFromFile(source, logError); } htmlAttributes = new HtmlAttributes(); htmlAttributes.AddProperty("class", $"lang-{language}"); if (!string.IsNullOrEmpty(interactive)) { htmlAttributes.AddProperty("data-interactive", language); htmlAttributes.AddProperty("data-interactive-mode", interactive); } if (!string.IsNullOrEmpty(highlight)) { htmlAttributes.AddProperty("highlight-lines", highlight); } RenderDelegate = (renderer, obj) => { var currentId = string.Empty; var currentRange = string.Empty; var currentSource = string.Empty; obj.Attributes.TryGetValue("id", out currentId); //it's okay if this is null obj.Attributes.TryGetValue("range", out currentRange); //it's okay if this is null obj.Attributes.TryGetValue("source", out currentSource); //source has already been checked above var(code, codePath) = _context.ReadFile(currentSource, obj); if (string.IsNullOrEmpty(code)) { logWarning($"The code snippet \"{currentSource}\" could not be found."); return(false); } //var updatedCode = GetCodeSnippet(currentRange, currentId, code, logError).TrimEnd(); var htmlCodeSnippetRenderer = new HtmlCodeSnippetRenderer(_context); var snippet = new CodeSnippet(null); snippet.CodePath = source; snippet.TagName = currentId; List <CodeRange> ranges; HtmlCodeSnippetRenderer.TryGetLineRanges(currentRange, out ranges); snippet.CodeRanges = ranges; var updatedCode = htmlCodeSnippetRenderer.GetContent(code, snippet); updatedCode = ExtensionsHelper.Escape(updatedCode).TrimEnd(); if (updatedCode == string.Empty) { return(false); } renderer.WriteLine("<pre>"); renderer.Write("<code").WriteAttributes(obj).Write(">"); renderer.WriteLine(updatedCode); renderer.WriteLine("</code></pre>"); return(true); }; return(true); }