diff --git a/.idea/.idea.unity-rich-debug/.idea/contentModel.xml b/.idea/.idea.unity-rich-debug/.idea/contentModel.xml
new file mode 100644
index 0000000..86d3310
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/contentModel.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/.idea/encodings.xml b/.idea/.idea.unity-rich-debug/.idea/encodings.xml
new file mode 100644
index 0000000..15a15b2
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/.idea/indexLayout.xml b/.idea/.idea.unity-rich-debug/.idea/indexLayout.xml
new file mode 100644
index 0000000..27ba142
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/.idea/misc.xml b/.idea/.idea.unity-rich-debug/.idea/misc.xml
new file mode 100644
index 0000000..1d8c84d
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/.idea/modules.xml b/.idea/.idea.unity-rich-debug/.idea/modules.xml
new file mode 100644
index 0000000..955077e
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/.idea/vcs.xml b/.idea/.idea.unity-rich-debug/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/.idea/workspace.xml b/.idea/.idea.unity-rich-debug/.idea/workspace.xml
new file mode 100644
index 0000000..44c264c
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/.idea/workspace.xml
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pink
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1561815728969
+
+
+ 1561815728969
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.unity-rich-debug/riderModule.iml b/.idea/.idea.unity-rich-debug/riderModule.iml
new file mode 100644
index 0000000..468d82c
--- /dev/null
+++ b/.idea/.idea.unity-rich-debug/riderModule.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FormattedStringBuilder.cs b/FormattedStringBuilder.cs
new file mode 100644
index 0000000..644d084
--- /dev/null
+++ b/FormattedStringBuilder.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace Skibitsky.Unity.StringFormatter
+{
+ public class FormattedStringBuilder
+ {
+ private readonly StringBuilder _openingTagsBuilder;
+ private readonly Stack _closingTagsStack;
+
+ private string String { get; }
+
+ public FormattedStringBuilder() : this(string.Empty)
+ {
+ }
+
+ public FormattedStringBuilder(string value)
+ {
+ String = value;
+
+ _openingTagsBuilder = new StringBuilder();
+ _closingTagsStack = new Stack();
+ }
+
+ public void Append(string value)
+ {
+ _openingTagsBuilder.Append(value);
+ }
+
+ public void PushToEnd(string value)
+ {
+ _closingTagsStack.Push(value);
+ }
+
+ public string Apply(string value)
+ {
+ var builder = new StringBuilder(_openingTagsBuilder.ToString());
+
+ builder.Append(value);
+
+ foreach (var s in _closingTagsStack)
+ builder.Append(s);
+
+ return builder.ToString();
+ }
+
+ public override string ToString() => Apply(String);
+
+ public static implicit operator string(FormattedStringBuilder fsb) => fsb.ToString();
+ public static implicit operator FormattedStringBuilder(string str) => new FormattedStringBuilder(str);
+ }
+}
\ No newline at end of file
diff --git a/FormattedStringBuilder.cs.meta b/FormattedStringBuilder.cs.meta
new file mode 100644
index 0000000..7743afc
--- /dev/null
+++ b/FormattedStringBuilder.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e62a0fd5b3a72440e931e189b9d5a3f3
+timeCreated: 1616843668
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d95016a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 skibitsky
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/LICENSE.meta b/LICENSE.meta
new file mode 100644
index 0000000..2f3efe6
--- /dev/null
+++ b/LICENSE.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4f652e2c4810e479ba92ea28462aa4ac
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b994ed7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,59 @@
+# String Formatter
+> Format strings with HTML-like tags (Unity's Rich Text) in LINQ fashion
+
+## Usage
+
+```csharp
+// Without String Formatter
+Debug.Log($"Player's name: {name}");
+
+// With String Formatter
+Debug.Log($"Player's name: {name.Bold().Italic().Size(16).Red()});
+
+// Reuse
+var nameFormat = new FormattedStringBuilder().Bold().Italic().Size(16).Red();
+Debug.Log($"Player One name: {nameFormat.Appy(name1)});
+Debug.Log($"Player Two name: {nameFormat.Appy(name2)});
+
+// Extend
+public static FormattedStringBuilder Dead(this FormattedStringBuilder source)
+{
+ source.Append("Player "); // Add before string. Used for opening tags
+ source.PushToEnd(" is dead!"); // Add after string. Used for closing tags
+
+ return source.Bold().Italic(); // Also make string bold and italic
+}
+public static FormattedStringBuilder Dead(this string source) => new FormattedStringBuilder(source).Dead();
+
+```
+
+## Installation
+
+### Install via OpenUPM
+
+The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).
+
+```
+openupm add com.skibitsky.string-formatter
+```
+
+### Install via Git URL
+
+Open *Packages/manifest.json* with your favorite text editor. Add the following line to the dependencies block.
+
+ {
+ "dependencies": {
+ "com.skibitsky.unity-rich-text": "https://github.com/skibitsky/string-formatter.git"
+ }
+ }
+
+Notice: Unity Package Manager records the current commit to a lock entry of the *manifest.json*. To update to the latest version, change the hash value manually or remove the lock entry to resolve the package.
+
+ "lock": {
+ "com.skibitsky.string-formatter": {
+ "revision": "master",
+ "hash": "..."
+ }
+ }
+
+
diff --git a/README.md.meta b/README.md.meta
new file mode 100644
index 0000000..5be60b4
--- /dev/null
+++ b/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 575a29ec0da534a49b03fdfacf134edf
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/RichTextExtensions.cs b/RichTextExtensions.cs
new file mode 100644
index 0000000..7e7e161
--- /dev/null
+++ b/RichTextExtensions.cs
@@ -0,0 +1,95 @@
+namespace Skibitsky.Unity.StringFormatter
+{
+ public static class RichTextExtensions
+ {
+ public static FormattedStringBuilder Size(this string source, int size) => new FormattedStringBuilder(source).Size(size);
+ public static FormattedStringBuilder Bold(this string source) => new FormattedStringBuilder(source).Bold();
+ public static FormattedStringBuilder Italic(this string source) => new FormattedStringBuilder(source).Italic();
+ public static FormattedStringBuilder Color(this string source, string color) => new FormattedStringBuilder(source).Color(color);
+
+ public static FormattedStringBuilder Aqua(this string source) => new FormattedStringBuilder(source).Aqua();
+ public static FormattedStringBuilder Black(this string source) => new FormattedStringBuilder(source).Black();
+ public static FormattedStringBuilder Blue(this string source) => new FormattedStringBuilder(source).Blue();
+ public static FormattedStringBuilder Brown(this string source) => new FormattedStringBuilder(source).Brown();
+ public static FormattedStringBuilder Cyan(this string source) => new FormattedStringBuilder(source).Cyan();
+ public static FormattedStringBuilder DarkBlue(this string source) => new FormattedStringBuilder(source).DarkBlue();
+ public static FormattedStringBuilder Fuchsia(this string source) => new FormattedStringBuilder(source).Fuchsia();
+ public static FormattedStringBuilder Green(this string source) => new FormattedStringBuilder(source).Green();
+ public static FormattedStringBuilder Grey(this string source) => new FormattedStringBuilder(source).Grey();
+ public static FormattedStringBuilder LightBlue(this string source) => new FormattedStringBuilder(source).LightBlue();
+ public static FormattedStringBuilder Lime(this string source) => new FormattedStringBuilder(source).Lime();
+ public static FormattedStringBuilder Magenta(this string source) => new FormattedStringBuilder(source).Magenta();
+ public static FormattedStringBuilder Maroon(this string source) => new FormattedStringBuilder(source).Maroon();
+ public static FormattedStringBuilder Navy(this string source) => new FormattedStringBuilder(source).Navy();
+ public static FormattedStringBuilder Olive(this string source) => new FormattedStringBuilder(source).Olive();
+ public static FormattedStringBuilder Orange(this string source) => new FormattedStringBuilder(source).Orange();
+ public static FormattedStringBuilder Purple(this string source) => new FormattedStringBuilder(source).Purple();
+ public static FormattedStringBuilder Red(this string source) => new FormattedStringBuilder(source).Red();
+ public static FormattedStringBuilder Silver(this string source) => new FormattedStringBuilder(source).Silver();
+ public static FormattedStringBuilder Teal(this string source) => new FormattedStringBuilder(source).Teal();
+ public static FormattedStringBuilder White(this string source) => new FormattedStringBuilder(source).White();
+ public static FormattedStringBuilder Yellow(this string source) => new FormattedStringBuilder(source).Yellow();
+
+
+ public static FormattedStringBuilder Size(this FormattedStringBuilder source, int size)
+ {
+ source.Append("");
+
+ source.PushToEnd("");
+
+ return source;
+ }
+
+ public static FormattedStringBuilder Bold(this FormattedStringBuilder source)
+ {
+ source.Append("");
+ source.PushToEnd("");
+
+ return source.Italic();
+ }
+
+ public static FormattedStringBuilder Italic(this FormattedStringBuilder source)
+ {
+ source.Append("");
+ source.PushToEnd("");
+
+ return source;
+ }
+
+ public static FormattedStringBuilder Color(this FormattedStringBuilder source, string color)
+ {
+ source.Append("");
+
+ source.PushToEnd("");
+
+ return source;
+ }
+
+ public static FormattedStringBuilder Aqua(this FormattedStringBuilder source) => source.Color("aqua");
+ public static FormattedStringBuilder Black(this FormattedStringBuilder source) => source.Color("black");
+ public static FormattedStringBuilder Blue(this FormattedStringBuilder source) => source.Color("blue");
+ public static FormattedStringBuilder Brown(this FormattedStringBuilder source) => source.Color("brown");
+ public static FormattedStringBuilder Cyan(this FormattedStringBuilder source) => source.Color("cyan");
+ public static FormattedStringBuilder DarkBlue(this FormattedStringBuilder source) => source.Color("darkblue");
+ public static FormattedStringBuilder Fuchsia(this FormattedStringBuilder source) => source.Color("fuchsia");
+ public static FormattedStringBuilder Green(this FormattedStringBuilder source) => source.Color("green");
+ public static FormattedStringBuilder Grey(this FormattedStringBuilder source) => source.Color("grey");
+ public static FormattedStringBuilder LightBlue(this FormattedStringBuilder source) => source.Color("lightblue");
+ public static FormattedStringBuilder Lime(this FormattedStringBuilder source) => source.Color("lime");
+ public static FormattedStringBuilder Magenta(this FormattedStringBuilder source) => source.Color("magenta");
+ public static FormattedStringBuilder Maroon(this FormattedStringBuilder source) => source.Color("maroon");
+ public static FormattedStringBuilder Navy(this FormattedStringBuilder source) => source.Color("navy");
+ public static FormattedStringBuilder Olive(this FormattedStringBuilder source) => source.Color("olive");
+ public static FormattedStringBuilder Orange(this FormattedStringBuilder source) => source.Color("orange");
+ public static FormattedStringBuilder Purple(this FormattedStringBuilder source) => source.Color("purple");
+ public static FormattedStringBuilder Red(this FormattedStringBuilder source) => source.Color("red");
+ public static FormattedStringBuilder Silver(this FormattedStringBuilder source) => source.Color("silver");
+ public static FormattedStringBuilder Teal(this FormattedStringBuilder source) => source.Color("teal");
+ public static FormattedStringBuilder White(this FormattedStringBuilder source) => source.Color("white");
+ public static FormattedStringBuilder Yellow(this FormattedStringBuilder source) => source.Color("yellow");
+ }
+}
\ No newline at end of file
diff --git a/RichTextExtensions.cs.meta b/RichTextExtensions.cs.meta
new file mode 100644
index 0000000..6766cbd
--- /dev/null
+++ b/RichTextExtensions.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: cde1b2a3a3bb4715b556f134bfdda658
+timeCreated: 1616931726
\ No newline at end of file
diff --git a/Skibitsky.Unity.StringFormatter.asmdef b/Skibitsky.Unity.StringFormatter.asmdef
new file mode 100644
index 0000000..350da32
--- /dev/null
+++ b/Skibitsky.Unity.StringFormatter.asmdef
@@ -0,0 +1,3 @@
+{
+ "name": "Skibitsky.Unity.StringFormatter"
+}
diff --git a/Skibitsky.Unity.StringFormatter.asmdef.meta b/Skibitsky.Unity.StringFormatter.asmdef.meta
new file mode 100644
index 0000000..d0e5903
--- /dev/null
+++ b/Skibitsky.Unity.StringFormatter.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5ed40a3dd64f049eb862bb4c8fa18f8e
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..9c5a709
--- /dev/null
+++ b/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "com.skibitsky.string-formatter",
+ "version": "1.0.0",
+ "displayName": "String Formatter",
+ "description": "Format strings with HTML-like tags (Unity's Rich Text) in LINQ fashion",
+ "repository": "skibitsky/string-formatter",
+ "author": {
+ "name": "Gleb Skibitsky",
+ "email": "gleb@skibitsky.com",
+ "url": "https://skibitsky.com"
+ },
+ "unity": "2019.3",
+ "license": "MIT",
+ "dependencies": {}
+}
\ No newline at end of file
diff --git a/package.json.meta b/package.json.meta
new file mode 100644
index 0000000..0b7ca9c
--- /dev/null
+++ b/package.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4988b0caa7efa4fb2933e4225dbd58fc
+PackageManifestImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant: