diff --git a/Cargo.lock b/Cargo.lock index d08f358d..3fca9747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1062,6 +1062,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "litemap" version = "0.7.4" @@ -1730,6 +1736,7 @@ dependencies = [ "serde_json", "thiserror 1.0.69", "walkdir", + "yaml-rust", ] [[package]] @@ -2342,6 +2349,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index 6af5ecd6..2da651fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ rusqlite_migration = { version = "1", default-features = false } rust-argon2 = "2.0.0" sha2 = "0" serde = { version = "1", features = ["derive"] } -syntect = { version = "5", default-features = false, features = ["html", "plist-load", "regex-fancy"] } +syntect = { version = "5", default-features = false, features = ["html", "plist-load", "regex-fancy", "yaml-load"] } thiserror = "2" time = { version = "0.3", features = ["macros", "serde"] } tokio = { version = "1", features = ["full"] } diff --git a/assets/LinkHighlight.sublime-syntax b/assets/LinkHighlight.sublime-syntax new file mode 100644 index 00000000..44a6004f --- /dev/null +++ b/assets/LinkHighlight.sublime-syntax @@ -0,0 +1,33 @@ +%YAML 1.2 +--- +# http://www.sublimetext.com/docs/3/syntax.html +name: LinkHighlight +file_extensions: + - link_highlight +scope: text.highlighting +contexts: + main: + - match: (<)((?:https?|ftp)://.*?)(>) + scope: meta.link.inet.markdown + captures: + 1: punctuation.definition.link.begin.markdown + 2: markup.underline.link.markdown + 3: punctuation.definition.link.end.markdown + - match: (((https|http|ftp)://)|www\.)[\w-]+(\.[\w-]+)+ + scope: markup.underline.link.markdown + push: # After a valid domain, zero or more non-space non-< characters may follow + - match: (?=[?!.,:*_~]*[\s<]) # Trailing punctuation (specifically, ?, !, ., ,, :, *, _, and ~) will not be considered part of the autolink, though they may be included in the interior of the link + pop: true + - match: (?={{html_entity}}[?!.,:*_~]*[\s<]) # If an autolink ends in a semicolon (;), we check to see if it appears to resemble an entity reference; if the preceding text is & followed by one or more alphanumeric characters. If so, it is excluded from the autolink + pop: true + - match: \( # When an autolink ends in ), we scan the entire autolink for the total number of parentheses. If there is a greater number of closing parentheses than opening ones, we don’t consider the last character part of the autolink, in order to facilitate including an autolink inside a parenthesis + push: + - meta_scope: markup.underline.link.markdown + - match: (?=[?!.,:*_~]*[\s<]) + pop: true + - match: \) + pop: true + - match: (?=\)[?!.,:*_~]*[\s<]) + pop: true + - match: '[^?!.,:*_~\s<&()]+|\S' + scope: markup.underline.link.markdown diff --git a/src/highlight.rs b/src/highlight.rs index 99fe0a2b..d22f4f69 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -6,7 +6,7 @@ use std::io::Cursor; use std::sync::LazyLock; use syntect::highlighting::ThemeSet; use syntect::html::{css_for_theme_with_class_style, line_tokens_to_classed_spans, ClassStyle}; -use syntect::parsing::{ParseState, ScopeStack, SyntaxReference, SyntaxSet}; +use syntect::parsing::{ParseState, ScopeStack, SyntaxDefinition, SyntaxReference, SyntaxSet}; use syntect::util::LinesWithEndings; const HIGHLIGHT_LINE_LENGTH_CUTOFF: usize = 2048; @@ -32,6 +32,11 @@ pub static DATA: LazyLock = LazyLock::new(|| { let dark = Css::new("dark", &DARK_CSS); let syntax_set: SyntaxSet = syntect::dumps::from_binary(include_bytes!("../assets/newlines.packdump")); + let link_highlighting = SyntaxDefinition::load_from_str( + include_str!("../assets/LinkHighlight.sublime-syntax"), false, None).expect("loading link style"); + let mut builder = syntax_set.into_builder(); + builder.add(link_highlighting); + let syntax_set = builder.build(); let mut syntaxes = syntax_set.syntaxes().to_vec(); syntaxes.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap_or(Ordering::Less)); @@ -72,12 +77,13 @@ impl<'a> Css<'a> { } fn highlight(source: &str, ext: &str) -> Result { - let syntax_ref = DATA - .syntax_set - .find_syntax_by_extension(ext) + let syntax_ref = (ext != "txt").then(|| + DATA + .syntax_set + .find_syntax_by_extension(ext)).flatten() .unwrap_or_else(|| { DATA.syntax_set - .find_syntax_by_extension("txt") + .find_syntax_by_extension("link_highlight") .expect("finding txt syntax") }); @@ -86,12 +92,13 @@ fn highlight(source: &str, ext: &str) -> Result { let mut scope_stack = ScopeStack::new(); for (mut line_number, line) in LinesWithEndings::from(source).enumerate() { + // let mut links = HashMap::new(); let (formatted, delta) = if line.len() > HIGHLIGHT_LINE_LENGTH_CUTOFF { (line.to_string(), 0) } else { - let parsed = parse_state.parse_line(line, &DATA.syntax_set)?; + let parsed = parse_state.parse_line(&line, &DATA.syntax_set)?; line_tokens_to_classed_spans( - line, + &line, parsed.as_slice(), ClassStyle::Spaced, &mut scope_stack, diff --git a/src/themes/style.css b/src/themes/style.css index d7c18538..fd910f7f 100644 --- a/src/themes/style.css +++ b/src/themes/style.css @@ -239,6 +239,16 @@ td.line-number { user-select: text; } +.line a { + color: rgba(57, 186, 230, .7); +} +.line a:hover { + text-decoration: underline; +} +.line a:visited { + color: rgba(225, 57, 230, 0.7); +} + .center { position: absolute; left: 50%; diff --git a/templates/base.html b/templates/base.html index ff4ac602..0e1b1af6 100644 --- a/templates/base.html +++ b/templates/base.html @@ -23,6 +23,7 @@
{% block content %}{% endblock %} + {% block content_post %}{% endblock %}
diff --git a/templates/paste.html b/templates/paste.html index 763dd213..c5e0f92f 100644 --- a/templates/paste.html +++ b/templates/paste.html @@ -53,3 +53,26 @@
  • {% endblock %} + +{% block content_post %} + +{% endblock %}