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]);