Initial commit

This commit is contained in:
Jordan Johnson-Doyle 2019-02-10 21:35:04 +00:00
parent 0676fb3cd5
commit 2aeb2d5e19
No known key found for this signature in database
GPG key ID: A95F87B578CE79B6
11 changed files with 1761 additions and 4 deletions

110
src/main.rs Normal file
View file

@ -0,0 +1,110 @@
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate rocket;
extern crate rocket_contrib;
extern crate gpw;
extern crate syntect;
extern crate chashmap;
use rocket_contrib::templates::Template;
use rocket::response::Redirect;
use rocket::request::Form;
use serde::Serialize;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::ThemeSet;
use syntect::easy::HighlightLines;
use syntect::html::{styled_line_to_highlighted_html, IncludeBackground};
use chashmap::CHashMap;
use std::borrow::Cow;
use std::cell::RefCell;
lazy_static! {
static ref ENTRIES: CHashMap<String, String> = CHashMap::new();
}
#[derive(FromForm)]
struct IndexForm {
val: String
}
#[get("/")]
fn index() -> Template {
#[derive(Serialize)]
struct Index {}
Template::render("index", Index {})
}
/// Generates a randomly generated id, stores the given paste under that id and then returns the id.
fn store_paste(content: String) -> String {
thread_local!(static KEYGEN: RefCell<gpw::PasswordGenerator> = RefCell::new(gpw::PasswordGenerator::default()));
let id = KEYGEN.with(|k| k.borrow_mut().next().unwrap());
ENTRIES.insert(id.clone(), content);
id
}
#[post("/", data = "<input>")]
fn submit(input: Form<IndexForm>) -> Redirect {
let id = store_paste(input.into_inner().val);
Redirect::to(format!("/{}", id))
}
#[put("/", data = "<input>")]
fn submit_raw(input: String) -> String {
format!("https://{}/{}", "localhost:8000", store_paste(input))
}
/// 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.
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();
}
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);
Some(styled_line_to_highlighted_html(&regions[..], IncludeBackground::No))
}
#[get("/<key>")]
fn render<'a>(key: String) -> Option<Template> {
let mut splitter = key.splitn(2, ".");
let key = splitter.next().unwrap();
let ext = splitter.next();
// get() returns a read-only lock, we're not going to be writing to this key
// again so we can hold this for as long as we want
let entry = ENTRIES.get(key)?;
#[derive(Serialize)]
struct Render<'a> {
content: Cow<'a, String>
}
Some(Template::render("paste", Render {
content: match ext {
None => Cow::Borrowed(&*entry),
Some(extension) => Cow::Owned(highlight(&*entry, extension)?)
}
}))
}
fn main() {
rocket::ignite()
.attach(Template::fairing())
.mount("/", routes![index, submit, submit_raw, render])
.launch();
}

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>bin.</title>
<style>
* { box-sizing: border-box; }
html, body { margin: 0; }
body {
min-height: 100vh;
padding: 2rem;
background: #263238;
color: #B0BEC5;
display: flex;
}
{% block styles %}
{% endblock styles %}
</style>
</head>
<body>
{% block content %}
{% endblock content %}
</body>
</html>

View file

@ -0,0 +1,59 @@
{% extends "base" %}
{% block styles %}
form { flex: 1; }
textarea {
height: 100%;
width: 100%;
background: none;
border: none;
color: inherit;
font-family: monospace;
resize: none;
}
button[type="submit"] {
position: absolute;
bottom: 1rem;
right: 1rem;
height: 3rem;
width: 3rem;
border: none;
border-radius: 50%;
background: #2196F3;
color: white;
font-size: 2rem;
cursor: pointer;
}
button[type="submit"].hidden { display: none; }
{% endblock styles %}
{% block content %}
<form action="/" method="post">
<textarea name="val" placeholder="bin something" autofocus autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
<button type="submit" title="&#x2318;+&#x23ce;">&#x270e;</button>
</form>
<script>
const form = document.querySelector('form');
const input = document.querySelector('textarea');
const button = document.querySelector('button[type="submit"]');
const onInput = () => button.classList.toggle('hidden', !input.value);
input.addEventListener('input', onInput);
onInput();
document.body.addEventListener('keydown', (e) => {
if (e.keyCode == 13 && e.metaKey) {
form.submit();
}
});
</script>
{% endblock content %}

View file

@ -0,0 +1,16 @@
{% extends "base" %}
{% block styles %}
pre {
height: 100%;
width: 100%;
margin: 0;
overflow: scroll;
font-family: Courier;
line-height: 1.1;
}
{% endblock styles %}
{% block content %}
<pre><code>{{ content | safe }}</code></pre>
{% endblock content %}