Skip to content

Commit

Permalink
Add bat for its extended syntax sets
Browse files Browse the repository at this point in the history
  • Loading branch information
w4 committed Mar 14, 2022
1 parent e8c3d1a commit e1639c0
Show file tree
Hide file tree
Showing 9 changed files with 1,026 additions and 1,124 deletions.
1,789 changes: 839 additions & 950 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,20 @@ edition = "2018"
argh = "0.1"
log = "0.4"
pretty_env_logger = "0.4"
owning_ref = "0.4"
linked-hash-map = "0.5"
lazy_static = "1.4"
once_cell = "1.10"
parking_lot = "0.12"
bytes = { version = "1.1", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
rand = { version = "0.8" }
gpw = "0.1"

actix = "0.12"
actix-web = "3.3"

actix = "0.13"
actix-web = "4.0"
htmlescape = "0.3"
askama = "0.11"
bat = "0.20"
syntect = "4.6"

tokio = { version = "1.15", features = ["sync"] }
tokio = { version = "1.17", features = ["sync"] }
futures = "0.3"

[profile.release]
Expand Down
52 changes: 27 additions & 25 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
use actix_web::{web, http::header, body::Body, HttpResponse, ResponseError, http::StatusCode};
use actix_web::{body::BoxBody, http::header, http::StatusCode, web, HttpResponse, ResponseError};

use std::fmt::{Write, Formatter};
use std::fmt::{Formatter, Write};

macro_rules! impl_response_error_for_http_resp {
($tt:tt) => {
impl ResponseError for $tt {
($ty:ty, $path:expr, $status:expr) => {
impl ResponseError for $ty {
fn error_response(&self) -> HttpResponse {
HtmlResponseError::error_response(self)
}
}
}

impl std::fmt::Display for $ty {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", include_str!($path))
}
}

impl HtmlResponseError for $ty {
fn status_code(&self) -> StatusCode {
$status
}
}
};
}

#[derive(Debug)]
pub struct NotFound;
impl std::fmt::Display for NotFound {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", include_str!("../templates/404.html"))
}
}
impl HtmlResponseError for NotFound {
fn status_code(&self) -> StatusCode {
StatusCode::NOT_FOUND
}
}
impl_response_error_for_http_resp!(NotFound);

impl_response_error_for_http_resp!(NotFound, "../templates/404.html", StatusCode::NOT_FOUND);

#[derive(Debug)]
pub struct InternalServerError(pub Box<dyn std::error::Error>);
impl std::fmt::Display for InternalServerError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", include_str!("../templates/500.html"))
}
}
impl HtmlResponseError for InternalServerError {}
impl_response_error_for_http_resp!(InternalServerError);

impl_response_error_for_http_resp!(
InternalServerError,
"../templates/500.html",
StatusCode::INTERNAL_SERVER_ERROR
);

pub trait HtmlResponseError: ResponseError {
fn status_code(&self) -> StatusCode {
Expand All @@ -49,6 +51,6 @@ pub trait HtmlResponseError: ResponseError {
header::CONTENT_TYPE,
header::HeaderValue::from_static("text/html; charset=utf-8"),
);
resp.set_body(Body::from(buf))
resp.set_body(BoxBody::new(buf))
}
}
}
51 changes: 35 additions & 16 deletions src/highlight.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,45 @@
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::html::{styled_line_to_highlighted_html, IncludeBackground};
use syntect::parsing::SyntaxSet;
use bat::assets::HighlightingAssets;
use once_cell::sync::Lazy;
use syntect::{
html::{ClassStyle, ClassedHTMLGenerator},
parsing::SyntaxSet,
};

use lazy_static::lazy_static;
thread_local!(pub static BAT_ASSETS: HighlightingAssets = HighlightingAssets::from_binary());

/// Takes the content of a paste and the extension passed in by the viewer and will return the content
/// highlighted in the appropriate format in HTML.
///
/// Returns `None` if the extension isn't supported.
pub fn highlight(content: &str, ext: &str) -> Option<String> {
lazy_static! {
static ref SS: SyntaxSet = SyntaxSet::load_defaults_newlines();
static ref TS: ThemeSet = ThemeSet::load_defaults();
}
static SS: Lazy<SyntaxSet> = Lazy::new(SyntaxSet::load_defaults_newlines);

BAT_ASSETS.with(|f| {
let ss = f.get_syntax_set().ok().unwrap_or(&SS);
let syntax = ss.find_syntax_by_extension(ext)?;
let mut html_generator =
ClassedHTMLGenerator::new_with_class_style(syntax, ss, ClassStyle::Spaced);
for line in LinesWithEndings(content.trim()) {
html_generator.parse_html_for_line_which_includes_newline(line);
}
Some(html_generator.finalize())
})
}

let syntax = SS.find_syntax_by_extension(ext)?;
let mut h = HighlightLines::new(syntax, &TS.themes["base16-ocean.dark"]);
let regions = h.highlight(content, &SS);
pub struct LinesWithEndings<'a>(&'a str);

Some(styled_line_to_highlighted_html(
&regions[..],
IncludeBackground::No,
))
impl<'a> Iterator for LinesWithEndings<'a> {
type Item = &'a str;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.0.is_empty() {
None
} else {
let split = self.0.find('\n').map_or(self.0.len(), |i| i + 1);
let (line, rest) = self.0.split_at(split);
self.0 = rest;
Some(line)
}
}
}
48 changes: 16 additions & 32 deletions src/io.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
use rand::{thread_rng, Rng, distributions::Alphanumeric};

use lazy_static::lazy_static;
use actix_web::web::Bytes;
use linked_hash_map::LinkedHashMap;
use owning_ref::OwningRef;
use tokio::sync::{RwLock, RwLockReadGuard};

use once_cell::sync::Lazy;
use parking_lot::RwLock;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use std::cell::RefCell;

type RwLockReadGuardRef<'a, T, U = T> = OwningRef<Box<RwLockReadGuard<'a, T>>, U>;
pub type PasteStore = RwLock<LinkedHashMap<String, Bytes>>;

pub type PasteStore = RwLock<LinkedHashMap<String, String>>;

lazy_static! {
static ref BUFFER_SIZE: usize = argh::from_env::<crate::BinArgs>().buffer_size;
}
static BUFFER_SIZE: Lazy<usize> = Lazy::new(|| argh::from_env::<crate::BinArgs>().buffer_size);

/// Ensures `ENTRIES` is less than the size of `BIN_BUFFER_SIZE`. If it isn't then
/// `ENTRIES.len() - BIN_BUFFER_SIZE` elements will be popped off the front of the map.
///
/// During the purge, `ENTRIES` is locked and the current thread will block.
async fn purge_old(entries: &PasteStore) {
let entries_len = entries.read().await.len();

if entries_len > *BUFFER_SIZE {
let to_remove = entries_len - *BUFFER_SIZE;

let mut entries = entries.write().await;
fn purge_old(entries: &mut LinkedHashMap<String, Bytes>) {
if entries.len() > *BUFFER_SIZE {
let to_remove = entries.len() - *BUFFER_SIZE;

for _ in 0..to_remove {
entries.pop_front();
Expand All @@ -47,24 +37,18 @@ pub fn generate_id() -> String {
}

/// Stores a paste under the given id
pub async fn store_paste(entries: &PasteStore, id: String, content: String) {
purge_old(&entries).await;
pub fn store_paste(entries: &PasteStore, id: String, content: Bytes) {
let mut entries = entries.write();

purge_old(&mut entries);

entries.write()
.await
.insert(id, content);
entries.insert(id, content);
}

/// Get a paste by id.
///
/// Returns `None` if the paste doesn't exist.
pub async fn get_paste<'a>(entries: &'a PasteStore, id: &str) -> Option<RwLockReadGuardRef<'a, LinkedHashMap<String, String>, String>> {
pub fn get_paste(entries: &PasteStore, id: &str) -> Option<Bytes> {
// need to box the guard until owning_ref understands Pin is a stable address
let or = RwLockReadGuardRef::new(Box::new(entries.read().await));

if or.contains_key(id) {
Some(or.map(|x| x.get(id).unwrap()))
} else {
None
}
entries.read().get(id).map(Bytes::clone)
}
Loading

0 comments on commit e1639c0

Please sign in to comment.