/** * Prepares the given string s for presentation on an html * page. * * Html encodes the special characters as follows: * * single quote: "'" * double quote: """ * less than: "<" * greater than: ">" * ampersand: "&" * * Replaces tabs by blanks relative to the given tabsize. * Default: tabsize = 4 * * Prefaces each line with a line number if desired. * Default: showlinenumbers = false * * Line numbers displayed start at 1 to follow the pattern * used in Visual Studio. * * Will return the original string s if s does not need any * of the following transformations: * html encoding * tabs to blanks * line numbering * * If any transformations take place then the return string * normalizes the line breaks to '\n'. * * The result of this method should be displayed using * preformatted text, that is, via a pre-tag or via the css * setting white-space:pre. */ public static string TextToHtml (string s, int tabsize = 4, bool showlinenumbers = false) { if (IsTrivial(s)) { return(s); } bool replaceHtml = hasHtmlSpecialRegex.IsMatch(s); bool replaceTabs = (tabsize > 0) && (hasTabRegex.IsMatch(s)); bool needsWork = replaceHtml || replaceTabs || showlinenumbers; if (!needsWork) { return(s); } StringBuilder builder = new StringBuilder(); int length = s.Length; List <Range> linerangelist = StringTools.LineRangeList(s); int linecount = linerangelist.Count; int lineindex = 0; while (lineindex < linecount) { // process the line at the lineindex Range linerange = linerangelist[lineindex]; int start = linerange.start; int limit = linerange.limit; // increment lineindex here // since visible line numbers start at 1 lineindex++; // if showlinenumbers is true, add the line number if (showlinenumbers) { builder.Append(lineindex.ToString("000000 ")); } // index is the character position in the string int index = start; // position is the character position on the line // after any earlier replacement of tabs by blanks // // characters used for the line number are ignored int position = 0; while (index < limit) { char c = s[index]; if (c == '\t') { if (tabsize > 0) { int spaces = tabsize - (position % tabsize); for (int i = 0; i < spaces; i++) { builder.Append(' '); } position += spaces; } else { builder.Append(c); position++; } } else { if (isHtmlSpecial(c)) { builder.Append(HtmlEncode(c)); } else { builder.Append(c); } position++; } index++; } if (limit < length) { builder.Append('\n'); } } return(builder.ToString()); }
/** * Prepares the given string s for presentation on an html * page. * * Enhances the method TextToHtml by permitting ranges of * the text to be highlighted. Each range is placed in a * span-tag with css class 'highlight'. Thus, the nature * of the highlighting is controlled by the css on the * page. * * Html encodes the special characters as follows: * * single quote: "'" * double quote: """ * less than: "<" * greater than: ">" * ampersand: "&" * * Replaces tabs by blanks relative to the given tabsize. * Default: tabsize = 4 * * Prefaces each line with a line number if desired. * Default: showlinenumbers = true * * Permits the caller to decide whether to show all lines or * to show only the lines with highlights. * Default: showall = false * * The reason for these defaults is that this method is used * to show the results of a search. In this situation, the * user is most interested in seeing the lines that contain * search results and not all other lines. By setting * showlinenumbers = true * showall = false * the lines that contain search results are identified and * no other lines are displayed. * * Line numbers displayed start at 1 to follow the pattern * used in Visual Studio. * * There is an interesting edge case if no ranges are given * to be highlighted. In that case: * * If showall=false, there is nothing to show and this * method returns an empty string. * * If showall=true, this method simply calls TextToHtml. * * If any transformations take place then the return string * normalizes the line breaks to '\n'. * * The result of this method should be displayed using * preformatted text, that is, via a pre-tag or via the css * setting white-space:pre. */ public static string HighlightMarkup (string s, List <Range> highlightlist, int tabsize = 4, bool showlinenumbers = true, bool showall = false) { if (IsTrivial(s)) { return(s); } if (IsTrivial(highlightlist)) { if (showall) { return(TextToHtml(s, tabsize, showlinenumbers)); } else { return(""); } } StringBuilder builder = new StringBuilder(); int length = s.Length; // Set up for line processing List <Range> linerangelist = StringTools.LineRangeList(s); int linecount = linerangelist.Count; int lineindex = 0; // Set up for highlight processing int highcount = highlightlist.Count; int highindex = 0; // data for dealing with the highlight overlap range list // for hightlight ranges than intersect a line range // overlap: the list of highlight range overlaps // overlapcount = overlap.Count // next: next highlight overlap range to process // nextrange = overlap[next] // open: nextrange.start // shut: nextrange.limit List <Range> overlap = null; int overlapcount = 0; int next = 0; Range nextrange; int open = -1; int shut = -1; while (lineindex < linecount) { // process the line at the lineindex Range linerange = linerangelist[lineindex]; int start = linerange.start; int limit = linerange.limit; // increment lineindex here // since visible line numbers start at 1 // // this guarantees that lineindex is updated // if this line will be skipped later because // it has no highlights lineindex++; // construct the overlap highlight ranges that // intersect this line range, if any overlap = null; overlapcount = 0; if (highindex < highcount) { while ((highindex < highcount) && (highlightlist[highindex].limit < start)) { highindex++; } while ((highindex < highcount) && (highlightlist[highindex].start < limit)) { Range?r = Range.Intersect(linerange, highlightlist[highindex]); if (r.HasValue) { Range rv = r.Value; if (rv.length > 0) { if (overlap == null) { overlap = new List <Range>(); } overlap.Add(rv); } if (highlightlist[highindex].limit <= limit) { highindex++; } else { break; } } else { break; } } } if (overlap != null) { overlapcount = overlap.Count; } // skip this line if // showall is false // and // there is no highlight to do if ((!showall) && (overlapcount == 0)) { continue; } // if showlinenumbers is true, add the line number // at this stage of the processing if (showlinenumbers) { builder.Append(lineindex.ToString("000000 ")); } // index is the character position in the string int index = start; // position is the character position on the line // after any earlier replacement of tabs by blanks // // characters used for the line number are ignored int position = 0; // get set to process highlights next = 0; if (next < overlapcount) { nextrange = overlap[next]; open = nextrange.start; shut = nextrange.limit; } else { open = -1; shut = -1; } while (index < limit) { // step 1: deal with highlight at this index if (index == shut) { builder.Append(highlightshut); next++; if (next < overlapcount) { nextrange = overlap[next]; open = nextrange.start; shut = nextrange.limit; } else { open = -1; shut = -1; } } if (index == open) { builder.Append(highlightopen); } // step 2: deal with character at this index char c = s[index]; if (c == '\t') { if (tabsize > 0) { int spaces = tabsize - (position % tabsize); for (int i = 0; i < spaces; i++) { builder.Append(' '); } position += spaces; } else { builder.Append(c); position++; } } else { if (isHtmlSpecial(c)) { builder.Append(HtmlEncode(c)); } else { builder.Append(c); } position++; } index++; } if (limit == shut) { builder.Append(highlightshut); } if (limit < length) { builder.Append('\n'); } } return(builder.ToString()); }
/* * Returns a string with the tabs in s converted to blanks * based on the given tabsize. * * If omitted, tabsize defaults to 4. * * Returns the original string if: * s is trivial * s does not contain a tab character * The given tabsize is less than or equal to 0 * * This method simply converts tabs and does no other task. * * If tabs are converted then the return string normalizes * the line breaks to '\n'. */ public static string TabsToBlanks (string s, int tabsize = 4) { if (IsTrivial(s)) { return(s); } if (tabsize <= 0) { return(s); } if (!hasTabRegex.IsMatch(s)) { return(s); } StringBuilder builder = new StringBuilder(); int length = s.Length; List <Range> linerangelist = StringTools.LineRangeList(s); int linecount = linerangelist.Count; int lineindex = 0; while (lineindex < linecount) { // process the line at the lineindex Range linerange = linerangelist[lineindex]; int start = linerange.start; int limit = linerange.limit; // increment lineindex here lineindex++; // index is the character position in the string int index = start; // position is the character position on the line // after any earlier replacement of tabs by blanks int position = 0; while (index < limit) { char c = s[index]; if (c == '\t') { int spaces = tabsize - (position % tabsize); for (int i = 0; i < spaces; i++) { builder.Append(' '); } position += spaces; } else { builder.Append(c); position++; } index++; } if (limit < length) { builder.Append('\n'); } } return(builder.ToString()); }