private void PrintGlyph(ColoredGlyph glyph, ColoredString settings) { var cell = editor.TextSurface.Cells[position.Y * editor.TextSurface.Width + position.X]; if (!PrintOnlyCharacterData) { if (!settings.IgnoreGlyph) { cell.Glyph = glyph.GlyphCharacter; } if (!settings.IgnoreBackground) { cell.Background = glyph.Background; } if (!settings.IgnoreForeground) { cell.Foreground = glyph.Foreground; } if (!settings.IgnoreMirror) { cell.Mirror = glyph.Mirror; } if (!settings.IgnoreEffect) { editor.SetEffect(cell, glyph.Effect); } } else if (!settings.IgnoreGlyph) { cell.Glyph = glyph.GlyphCharacter; } position.X += 1; if (position.X >= editor.TextSurface.Width) { position.X = 0; position.Y += 1; if (position.Y >= editor.TextSurface.Height) { position.Y -= 1; if (AutomaticallyShiftRowsUp) { editor.ShiftUp(); } } } editor.TextSurface.IsDirty = true; }
/// <summary> /// Creates a colored string by parsing commands embedded in the string. /// </summary> /// <param name="value">The string to parse.</param> /// <param name="surfaceIndex">Index of where this string will be printed.</param> /// <param name="surface">The surface the string will be printed to.</param> /// <param name="editor">A surface editor associated with the text surface.</param> /// <param name="initialBehaviors">Any initial defaults.</param> /// <returns></returns> public static ColoredString Parse(string value, int surfaceIndex = -1, Surfaces.ISurface surface = null, SurfaceEditor editor = null, ParseCommandStacks initialBehaviors = null) { var commandStacks = initialBehaviors != null ? initialBehaviors : new ParseCommandStacks(); List <ColoredGlyph> glyphs = new List <ColoredGlyph>(value.Length); for (int i = 0; i < value.Length; i++) { var existingGlyphs = glyphs.ToArray(); if (value[i] == '`' && i + 1 < value.Length && value[i + 1] == '[') { continue; } if (value[i] == '[' && (i == 0 || value[i - 1] != '`')) { try { if (i + 4 < value.Length && value[i + 1] == 'c' && value[i + 2] == ':' && value.IndexOf(']', i + 2) != -1) { int commandExitIndex = value.IndexOf(']', i + 2); string command = value.Substring(i + 3, commandExitIndex - (i + 3)); string commandParams = ""; if (command.Contains(" ")) { var commandSections = command.Split(new char[] { ' ' }, 2); command = commandSections[0].ToLower(); commandParams = commandSections[1]; } // Check for custom command ParseCommandBase commandObject = CustomProcessor != null?CustomProcessor(command, commandParams, existingGlyphs, surface, editor, commandStacks) : null; // No custom command found, run build in ones if (commandObject == null) { switch (command) { case "recolor": case "r": commandObject = new ParseCommandRecolor(commandParams); break; case "mirror": case "m": commandObject = new ParseCommandMirror(commandParams); break; case "undo": case "u": commandObject = new ParseCommandUndo(commandParams, commandStacks); break; case "grad": case "g": commandObject = new ParseCommandGradient(commandParams); break; case "blink": case "b": commandObject = new ParseCommandBlink(commandParams, existingGlyphs, commandStacks, editor); break; case "sglyph": case "sg": commandObject = new ParseCommandSetGlyph(commandParams); break; default: break; } } if (commandObject != null && commandObject.CommandType != CommandTypes.Invalid) { commandStacks.AddSafe(commandObject); i = commandExitIndex; continue; } } } catch (System.Exception e1) { #if DEBUG throw e1; #endif } } int fixedSurfaceIndex; if (surfaceIndex == -1 || surface == null) { fixedSurfaceIndex = -1; } else { fixedSurfaceIndex = i + surfaceIndex < surface.Cells.Length ? i + surfaceIndex : -1; } ColoredGlyph newGlyph; if (fixedSurfaceIndex != -1) { newGlyph = new ColoredGlyph(surface[i + surfaceIndex]) { Glyph = value[i] } } ; else { newGlyph = new ColoredGlyph(new Cell()) { Glyph = value[i] } }; // Foreground if (commandStacks.Foreground.Count != 0) { commandStacks.Foreground.Peek().Build(ref newGlyph, existingGlyphs, fixedSurfaceIndex, surface, editor, ref i, value, commandStacks); } // Background if (commandStacks.Background.Count != 0) { commandStacks.Background.Peek().Build(ref newGlyph, existingGlyphs, fixedSurfaceIndex, surface, editor, ref i, value, commandStacks); } if (commandStacks.Glyph.Count != 0) { commandStacks.Glyph.Peek().Build(ref newGlyph, existingGlyphs, fixedSurfaceIndex, surface, editor, ref i, value, commandStacks); } // SpriteEffect if (commandStacks.Mirror.Count != 0) { commandStacks.Mirror.Peek().Build(ref newGlyph, existingGlyphs, fixedSurfaceIndex, surface, editor, ref i, value, commandStacks); } // Effect if (commandStacks.Effect.Count != 0) { commandStacks.Effect.Peek().Build(ref newGlyph, existingGlyphs, fixedSurfaceIndex, surface, editor, ref i, value, commandStacks); } glyphs.Add(newGlyph); } return(new ColoredString(glyphs.ToArray()) { IgnoreEffect = !commandStacks.TurnOnEffects }); } }
/// <summary> /// Prints text to the console using the appearance of the colored string. /// </summary> /// <param name="text">The text to print.</param> /// <returns>Returns this cursor object.</returns> public Cursor Print(ColoredString text) { // If we don't want the pretty print, or we're printing a single character (for example, from keyboard input) // Then use the pretty print system. if (!DisableWordBreak && text.String.Length != 1) { // Prep ColoredGlyph glyph; ColoredGlyph spaceGlyph = text[0].Clone(); spaceGlyph.GlyphCharacter = ' '; string stringText = text.String.TrimEnd(' '); // Pull any starting spaces off var newStringText = stringText.TrimStart(' '); int spaceCount = stringText.Length - newStringText.Length; for (int i = 0; i < spaceCount; i++) { PrintGlyph(spaceGlyph, text); } if (spaceCount != 0) { text = text.SubString(spaceCount, text.Count - spaceCount); } stringText = newStringText; string[] parts = stringText.Split(' '); // Start processing the string int c = 0; for (int wordMajor = 0; wordMajor < parts.Length; wordMajor++) { // Words broken up by spaces = parts if (parts[wordMajor].Length != 0) { // Parts broken by new lines = newLineParts string[] newlineParts = parts[wordMajor].Split('\n'); for (int indexNL = 0; indexNL < newlineParts.Length; indexNL++) { if (newlineParts[indexNL].Length != 0) { int currentLine = position.Y; // New line parts broken up by carriage returns = returnParts string[] returnParts = newlineParts[indexNL].Split('\r'); for (int indexR = 0; indexR < returnParts.Length; indexR++) { // If the text we'll print will move off the edge, fill with spaces to get a fresh line if (returnParts[indexR].Length > editor.Width - position.X && position.X != 0) { var spaces = editor.Width - position.X; // Fill rest of line with spaces for (int i = 0; i < spaces; i++) { PrintGlyph(spaceGlyph, text); } } // Print the rest of the text as normal. for (int i = 0; i < returnParts[indexR].Length; i++) { glyph = text[c]; PrintGlyph(glyph, text); c++; } // If we had a \r in the string, handle it by going back if (returnParts.Length != 1 && indexR != returnParts.Length - 1) { // Wrapped to a new line through print glyph, which triggerd \r\n. We don't want the \n so return back. if (position.X == 0 && position.Y != currentLine) { position.Y -= 1; } else { CarriageReturn(); } c++; } } } // We had \n in the string, handle them. if (newlineParts.Length != 1 && indexNL != newlineParts.Length - 1) { if (!UseLinuxLineEndings) { LineFeed(); } else { NewLine(); } c++; } } } // Not last part if (wordMajor != parts.Length - 1 && position.X != 0) { PrintGlyph(spaceGlyph, text); c++; } else { c++; } } } else { bool movedLines = false; int oldLine = position.Y; foreach (var glyph in text) { // Check if the previous print moved us down a line (from print at end of the line) and move use back for the \r if (movedLines) { if (position.X == 0 && glyph.GlyphCharacter == '\r') { position.Y -= 1; continue; } else { movedLines = false; } } if (glyph.GlyphCharacter == '\r') { CarriageReturn(); } else if (glyph.GlyphCharacter == '\n') { if (!UseLinuxLineEndings) { LineFeed(); } else { NewLine(); } } else { PrintGlyph(glyph, text); // Lines changed and it wasn't a \n that caused it, so it was a print that did it. movedLines = position.Y != oldLine; } } } return(this); }