mirror of https://github.com/w4/bin.git
Initial commit
This commit is contained in:
parent
0676fb3cd5
commit
2aeb2d5e19
|
@ -1,10 +1,8 @@
|
|||
.idea/
|
||||
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
This project is dual-licensed under the WTFPL and 0BSD licenses, copies of both are included.
|
||||
|
||||
You may use this code under the terms of either license.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "bin"
|
||||
version = "0.1.0"
|
||||
authors = ["Jordan Doyle <jordan@doyle.la>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.4"
|
||||
lazy_static = "1.2"
|
||||
gpw = "0.1"
|
||||
syntect = "3.0"
|
||||
chashmap = { git = "https://github.com/redox-os/tfs" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[dependencies.rocket_contrib]
|
||||
version = "*"
|
||||
default-features = false
|
||||
features = ["tera_templates"]
|
|
@ -0,0 +1,5 @@
|
|||
Copyright (C) 2019 by Jordan Doyle <jordan@doyle.la>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,13 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
|
@ -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(®ions[..], 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();
|
||||
}
|
|
@ -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>
|
|
@ -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="⌘+⏎">✎</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 %}
|
|
@ -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 %}
|
Loading…
Reference in New Issue