diff --git a/assets/css/app.css b/assets/css/app.css
index 15a4cb2..ddd93d5 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -54,4 +54,6 @@ textarea {
background-color: #ff9800;
color: black;
font-weight: bold;
-}
\ No newline at end of file
+}
+
+@import './highlight.css';
\ No newline at end of file
diff --git a/assets/css/highlight.css b/assets/css/highlight.css
new file mode 100644
index 0000000..475ca40
--- /dev/null
+++ b/assets/css/highlight.css
@@ -0,0 +1,235 @@
+.code {
+ color: #c0c5ce;
+ background-color: #2b303b;
+}
+.variable.parameter.function {
+ color: #c0c5ce;
+}
+.comment {
+ color: #65737e;
+}
+.punctuation.definition.comment {
+ color: #65737e;
+}
+.punctuation.definition.string {
+ color: #c0c5ce;
+}
+.punctuation.definition.variable {
+ color: #c0c5ce;
+}
+.punctuation.definition.string {
+ color: #c0c5ce;
+}
+.punctuation.definition.parameters {
+ color: #c0c5ce;
+}
+.punctuation.definition.string {
+ color: #c0c5ce;
+}
+.punctuation.definition.array {
+ color: #c0c5ce;
+}
+.none {
+ color: #c0c5ce;
+}
+.keyword.operator {
+ color: #c0c5ce;
+}
+.keyword {
+ color: #b48ead;
+}
+.variable {
+ color: #bf616a;
+}
+.variable.other.dollar.only.js {
+ color: #bf616a;
+}
+.entity.name.function {
+ color: #8fa1b3;
+}
+.meta.require {
+ color: #8fa1b3;
+}
+.support.function.any-method {
+ color: #8fa1b3;
+}
+.variable.function {
+ color: #8fa1b3;
+}
+.support.class {
+ color: #ebcb8b;
+}
+.entity.name.class {
+ color: #ebcb8b;
+}
+.entity.name.type.class {
+ color: #ebcb8b;
+}
+.meta.class {
+ color: #eff1f5;
+}
+.keyword.other.special-method {
+ color: #8fa1b3;
+}
+.storage {
+ color: #b48ead;
+}
+.support.function {
+ color: #96b5b4;
+}
+.string {
+ color: #a3be8c;
+}
+.constant.other.symbol {
+ color: #a3be8c;
+}
+.entity.other.inherited-class {
+ color: #a3be8c;
+}
+.constant.numeric {
+ color: #d08770;
+}
+.none {
+ color: #d08770;
+}
+.none {
+ color: #d08770;
+}
+.constant {
+ color: #d08770;
+}
+.entity.name.tag {
+ color: #bf616a;
+}
+.entity.other.attribute-name {
+ color: #d08770;
+}
+.entity.other.attribute-name.id {
+ color: #8fa1b3;
+}
+.punctuation.definition.entity {
+ color: #8fa1b3;
+}
+.meta.selector {
+ color: #b48ead;
+}
+.none {
+ color: #d08770;
+}
+.markup.heading {
+ color: #8fa1b3;
+}
+.punctuation.definition.heading {
+ color: #8fa1b3;
+}
+.entity.name.section {
+ color: #8fa1b3;
+}
+.keyword.other.unit {
+ color: #d08770;
+}
+.markup.bold {
+ color: #ebcb8b;
+ font-weight: 700;
+}
+.punctuation.definition.bold {
+ color: #ebcb8b;
+ font-weight: 700;
+}
+.markup.italic {
+ color: #b48ead;
+ font-style: italic;
+}
+.punctuation.definition.italic {
+ color: #b48ead;
+ font-style: italic;
+}
+.markup.raw.inline {
+ color: #a3be8c;
+}
+.string.other.link {
+ color: #bf616a;
+}
+.meta.link {
+ color: #d08770;
+}
+.meta.image {
+ color: #d08770;
+}
+.markup.list {
+ color: #bf616a;
+}
+.markup.quote {
+ color: #d08770;
+}
+.meta.separator {
+ color: #c0c5ce;
+ background-color: #4f5b66;
+}
+.markup.inserted {
+ color: #a3be8c;
+}
+.markup.inserted.git_gutter {
+ color: #a3be8c;
+}
+.markup.deleted {
+ color: #bf616a;
+}
+.markup.deleted.git_gutter {
+ color: #bf616a;
+}
+.markup.changed {
+ color: #b48ead;
+}
+.markup.changed.git_gutter {
+ color: #b48ead;
+}
+.markup.ignored {
+ color: #4f5b66;
+}
+.markup.ignored.git_gutter {
+ color: #4f5b66;
+}
+.markup.untracked {
+ color: #4f5b66;
+}
+.markup.untracked.git_gutter {
+ color: #4f5b66;
+}
+.constant.other.color {
+ color: #96b5b4;
+}
+.string.regexp {
+ color: #96b5b4;
+}
+.constant.character.escape {
+ color: #96b5b4;
+}
+.punctuation.section.embedded {
+ color: #ab7967;
+}
+.variable.interpolation {
+ color: #ab7967;
+}
+.invalid.illegal {
+ color: #2b303b;
+ background-color: #bf616a;
+}
+.markup.deleted.git_gutter {
+ color: #f92672;
+}
+.markup.inserted.git_gutter {
+ color: #a6e22e;
+}
+.markup.changed.git_gutter {
+ color: #967efb;
+}
+.markup.ignored.git_gutter {
+ color: #565656;
+}
+.markup.untracked.git_gutter {
+ color: #565656;
+}
+.source .block {
+ display: inline;
+}
diff --git a/lib/ketbin/utils/syntax.ex b/lib/ketbin/utils/syntax.ex
index 954cb6f..93c7587 100644
--- a/lib/ketbin/utils/syntax.ex
+++ b/lib/ketbin/utils/syntax.ex
@@ -2,5 +2,9 @@ defmodule Ketbin.Utils.Syntax do
use Rustler, otp_app: :ketbin, crate: "ketbin_utils_syntax"
# When your NIF is loaded, it will override this function.
- def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)
+ def add(_a, _b), do: error()
+
+ def highlight_text(_text, _lang), do: error()
+
+ defp error(), do: :erlang.nif_error(:nif_not_loaded)
end
diff --git a/lib/ketbin_web/templates/page/show.html.eex b/lib/ketbin_web/templates/page/show.html.eex
index dcb33b6..13e64de 100644
--- a/lib/ketbin_web/templates/page/show.html.eex
+++ b/lib/ketbin_web/templates/page/show.html.eex
@@ -8,5 +8,5 @@
<% end %>
- <%= @paste.content %>
+ <%= raw Ketbin.Utils.Syntax.highlight_text(@paste.content, "rs") %>
diff --git a/native/ketbin_utils_syntax/Cargo.lock b/native/ketbin_utils_syntax/Cargo.lock
index e622551..a9ab4a5 100644
--- a/native/ketbin_utils_syntax/Cargo.lock
+++ b/native/ketbin_utils_syntax/Cargo.lock
@@ -2,6 +2,94 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cc"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
+dependencies = [
+ "cfg-if",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
[[package]]
name = "heck"
version = "0.3.3"
@@ -11,11 +99,28 @@ dependencies = [
"unicode-segmentation",
]
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+
[[package]]
name = "ketbin_utils_syntax"
version = "0.1.0"
dependencies = [
"rustler",
+ "syntect",
]
[[package]]
@@ -24,6 +129,104 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765"
+
+[[package]]
+name = "line-wrap"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
+dependencies = [
+ "safemem",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "onig"
+version = "6.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b16fd3c0e73b516af509c13c4ba76ec0c987ce20d78b38cff356b8d01fc6a6c0"
+dependencies = [
+ "bitflags",
+ "lazy_static",
+ "libc",
+ "onig_sys",
+]
+
+[[package]]
+name = "onig_sys"
+version = "69.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fd9442a09e4fbd08d196ddf419b2c79a43c3a46c800320cc841d45c2449a240"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
+
+[[package]]
+name = "plist"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a38d026d73eeaf2ade76309d0c65db5a35ecf649e3cec428db316243ea9d6711"
+dependencies = [
+ "base64",
+ "chrono",
+ "indexmap",
+ "line-wrap",
+ "serde",
+ "xml-rs",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.28"
@@ -42,6 +245,12 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
[[package]]
name = "rustler"
version = "0.22.0"
@@ -74,6 +283,55 @@ dependencies = [
"unreachable",
]
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.127"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.127"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
[[package]]
name = "syn"
version = "1.0.74"
@@ -85,6 +343,28 @@ dependencies = [
"unicode-xid",
]
+[[package]]
+name = "syntect"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b20815bbe80ee0be06e6957450a841185fcf690fe0178f14d77a05ce2caa031"
+dependencies = [
+ "bincode",
+ "bitflags",
+ "flate2",
+ "fnv",
+ "lazy_static",
+ "lazycell",
+ "onig",
+ "plist",
+ "regex-syntax",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "walkdir",
+ "yaml-rust",
+]
+
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
@@ -111,3 +391,60 @@ name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "xml-rs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
diff --git a/native/ketbin_utils_syntax/Cargo.toml b/native/ketbin_utils_syntax/Cargo.toml
index cfb57ec..a1d3102 100644
--- a/native/ketbin_utils_syntax/Cargo.toml
+++ b/native/ketbin_utils_syntax/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "ketbin_utils_syntax"
version = "0.1.0"
-authors = []
+authors = ["SphericalKat "]
edition = "2018"
[lib]
@@ -11,3 +11,4 @@ crate-type = ["cdylib"]
[dependencies]
rustler = "0.22.0"
+syntect = "4.6"
diff --git a/native/ketbin_utils_syntax/src/lib.rs b/native/ketbin_utils_syntax/src/lib.rs
index ee4c00f..1007f4c 100644
--- a/native/ketbin_utils_syntax/src/lib.rs
+++ b/native/ketbin_utils_syntax/src/lib.rs
@@ -1,6 +1,26 @@
+use syntect::{html::{ClassStyle, ClassedHTMLGenerator}, parsing::SyntaxSet, util::LinesWithEndings};
+
#[rustler::nif]
fn add(a: i64, b: i64) -> i64 {
a + b
}
-rustler::init!("Elixir.Ketbin.Utils.Syntax", [add]);
+#[rustler::nif]
+pub fn highlight_text(text: String, lang: String) -> String {
+ let syntax_set = SyntaxSet::load_defaults_newlines();
+
+ let syntax = syntax_set
+ .find_syntax_by_extension(&lang)
+ .unwrap_or(syntax_set.find_syntax_plain_text());
+
+ let mut rs_html_generator =
+ ClassedHTMLGenerator::new_with_class_style(syntax, &syntax_set, ClassStyle::Spaced);
+
+ for line in LinesWithEndings::from(&text) {
+ rs_html_generator.parse_html_for_line_which_includes_newline(&line)
+ }
+
+ rs_html_generator.finalize()
+}
+
+rustler::init!("Elixir.Ketbin.Utils.Syntax", [add, highlight_text]);