master
rasul 5 years ago
commit 2598efc9ff

@ -0,0 +1,6 @@
[*]
indent_style = tab
tab_width = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

2
.gitignore vendored

@ -0,0 +1,2 @@
/target
**/*.rs.bk

1968
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
[package]
name = "pastebucket"
version = "0.7.0"
authors = ["rasul <rascul3@gmail.com>"]
edition = "2018"
[dependencies]
askama = "0.9"
chrono = { version = "0.4", features = ["serde"] }
colored = "1.9"
fern = { version = "0.5", features = ["colored"] }
futures = "0.1"
getopts = "0.2"
gotham = "0.4"
gotham_derive = "0.4"
harsh = "0.1.6"
hyper = "0.12"
lazy_static = "1.4"
log = "0.4"
mime = "0.3"
pulldown-cmark = "0.6"
serde = "1.0"
serde_derive = "1.0"
syntect = "3.3"
toml = "0.5"
url = "1.6"

@ -0,0 +1,5 @@
work in progress
mostly works though but needs more works
https://p.rascul.xyz

@ -0,0 +1,5 @@
max_width = 100
hard_tabs = true
newline_style = "unix"
use_try_shorthand = true
edition = "2018"

@ -0,0 +1,58 @@
pub mod loglevel;
use std::default::Default;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use gotham_derive::StateData;
use serde_derive::Deserialize;
use toml;
pub use crate::config::loglevel::LogLevel;
use crate::result::Result;
#[derive(Clone, Debug, Deserialize, StateData)]
pub struct Config {
#[serde(default)]
pub address: String,
#[serde(default)]
pub url: String,
#[serde(default)]
pub log_level: LogLevel,
#[serde(default)]
pub log_file: Option<String>,
#[serde(default)]
pub data_directory: PathBuf,
#[serde(default)]
pub template_directory: PathBuf,
#[serde(default)]
pub static_directory: PathBuf,
}
impl Default for Config {
fn default() -> Self {
Self {
address: "127.0.0.1:9214".into(),
url: "http://127.0.0.1:9214".into(),
log_level: LogLevel::info,
log_file: None,
data_directory: PathBuf::from("data"),
template_directory: PathBuf::from("templates"),
static_directory: PathBuf::from("static"),
}
}
}
impl Config {
pub fn load<T: AsRef<Path>>(path: T) -> Result<Config> {
if let Ok(mut file) = File::open(path.as_ref()) {
let mut buf = String::new();
file.read_to_string(&mut buf)?;
let config: Config = toml::from_str(&buf)?;
Ok(config)
} else {
Ok(Config::default())
}
}
}

@ -0,0 +1,36 @@
use std::default::Default;
use log::LevelFilter;
use serde_derive::Deserialize;
#[derive(Clone, Debug, Deserialize)]
pub enum LogLevel {
#[allow(non_camel_case_types)]
error,
#[allow(non_camel_case_types)]
warn,
#[allow(non_camel_case_types)]
info,
#[allow(non_camel_case_types)]
debug,
#[allow(non_camel_case_types)]
trace,
}
impl Default for LogLevel {
fn default() -> LogLevel {
LogLevel::info
}
}
impl LogLevel {
pub fn level(&self) -> LevelFilter {
match &self {
LogLevel::error => LevelFilter::Error,
LogLevel::warn => LevelFilter::Warn,
LogLevel::info => LevelFilter::Info,
LogLevel::debug => LevelFilter::Debug,
LogLevel::trace => LevelFilter::Trace,
}
}
}

@ -0,0 +1,35 @@
use chrono::Local;
use colored::Colorize;
use fern::colors::{Color, ColoredLevelConfig};
use fern::Dispatch;
use crate::config::LogLevel;
use crate::result::Result;
pub fn setup(level: &LogLevel) -> Result<()> {
Dispatch::new()
.format(|out, message, record| {
let colors = ColoredLevelConfig::new()
.error(Color::Red)
.warn(Color::Magenta)
.info(Color::Cyan)
.debug(Color::Yellow)
.trace(Color::Green);
out.finish(format_args!(
"{} {} {}",
Local::now()
.format("%Y-%m-%dT%H:%M:%S%.3f%z")
.to_string()
.white()
.bold(),
colors.color(record.level()),
message
))
})
.level(level.level())
.chain(std::io::stdout())
.apply()?;
Ok(())
}

@ -0,0 +1,15 @@
mod config;
mod logger;
mod paste;
mod result;
mod routes;
mod syntax;
use result::Result;
fn main() -> Result<()> {
let config = config::Config::load("config.toml")?;
logger::setup(&config.log_level)?;
gotham::start(config.address.clone(), routes::build(config));
Ok(())
}

@ -0,0 +1,81 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufWriter, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use chrono::{DateTime, Utc};
use harsh::HarshBuilder;
use serde::{Deserialize, Serialize};
use toml;
use crate::result::Result;
#[derive(Debug, Deserialize, Serialize)]
pub struct Paste {
pub id: String,
pub dt: DateTime<Utc>,
pub lang: String,
pub text: String,
}
impl Paste {
pub fn from_file(path: PathBuf) -> Result<Self> {
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
let paste: Paste = toml::from_str(&buf)?;
Ok(paste)
}
pub fn from_text(text: String) -> Result<Self> {
let dt = Utc::now();
let harsh = HarshBuilder::new().salt("salt and pepper").init()?;
let encoded = harsh.encode(&[dt.timestamp_millis() as u64]);
if let Some(id) = encoded {
Ok(Paste {
id,
dt,
text,
lang: "Plain Text".into(),
})
} else {
Err(Box::new(Error::new(ErrorKind::Other, "couldn't generate hash")))
}
}
pub fn from_form(form: HashMap<String, String>) -> Result<Self> {
let dt = Utc::now();
let harsh = HarshBuilder::new().salt("salt and pepper").init()?;
let encoded = harsh.encode(&[dt.timestamp_millis() as u64]);
if let Some(id) = encoded {
let text: String = if let Some(t) = form.get("paste") {
t.into()
} else {
"".into()
};
let lang: String = if let Some(l) = form.get("lang") {
l.into()
} else {
"Plain Text".into()
};
Ok(Paste { id, dt, lang, text })
} else {
Err(Box::new(Error::new(ErrorKind::Other, "empty hash")))
}
}
pub fn to_file(&self, path: PathBuf) -> Result<()> {
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
writer.write_all(toml::to_string_pretty(&self)?.as_bytes())?;
Ok(())
}
}

@ -0,0 +1 @@
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

@ -0,0 +1,45 @@
mod edit;
mod index;
mod raw;
mod submit;
mod view;
use gotham::handler::assets::FileOptions;
use gotham::middleware::logger::RequestLogger;
use gotham::middleware::state::StateMiddleware;
use gotham::pipeline::new_pipeline;
use gotham::pipeline::single::single_pipeline;
use gotham::router::builder::*;
use gotham::router::Router;
use crate::config::Config;
pub fn build(config: Config) -> Router {
let (chain, pipeline) = single_pipeline(
new_pipeline()
.add(RequestLogger::new(log::Level::Info))
.add(StateMiddleware::new(config.clone()))
.build(),
);
build_router(chain, pipeline, |route| {
route.get("/").to(index::route);
route.post("/").to(submit::post);
route.put("/").to(submit::put);
route
.get("/s/*")
.to_dir(FileOptions::new(config.static_directory));
route
.get("/:id")
.with_path_extractor::<view::Params>()
.to(view::get);
route
.get("/:id/edit")
.with_path_extractor::<edit::Params>()
.to(edit::route);
route
.get("/:id/raw")
.with_path_extractor::<raw::Params>()
.to(raw::get);
})
}

@ -0,0 +1,70 @@
use askama::Template;
use futures::future;
use gotham::handler::{HandlerFuture, IntoHandlerError};
use gotham::helpers::http::response::{create_empty_response, create_response};
use gotham::state::{FromState, State};
use gotham_derive::{StateData, StaticResponseExtender};
use hyper::StatusCode;
use mime;
use serde_derive::Deserialize;
use crate::config::Config;
use crate::paste::Paste;
use crate::syntax::SYNTAXES;
#[derive(Deserialize, StateData, StaticResponseExtender)]
pub struct Params {
id: String,
}
#[derive(Debug, Template)]
#[template(path = "edit.html")]
pub struct Edit {
id: String,
dt: String,
text: String,
site_url: String,
syntaxes: Vec<String>,
syntax: String,
}
pub fn route(mut state: State) -> Box<HandlerFuture> {
Box::new({
let config = Config::take_from(&mut state);
let Params { id } = Params::take_from(&mut state);
let mut path = config.data_directory.clone();
path.push(id.clone());
match Paste::from_file(path) {
Ok(paste) => {
let template = Edit {
id,
dt: paste.dt.format("%Y-%m-%dT%H:%MZ").to_string(),
text: paste.text,
site_url: config.url,
syntaxes: SYNTAXES.to_vec(),
syntax: paste.lang,
};
let res = match template.render() {
Ok(content) => create_response(
&state,
StatusCode::OK,
mime::TEXT_HTML_UTF_8,
content.into_bytes(),
),
Err(_) => create_empty_response(&state, StatusCode::INTERNAL_SERVER_ERROR),
};
future::ok((state, res))
}
Err(e) => {
let io_error = std::io::Error::new(std::io::ErrorKind::Other, e.description());
future::err((state, io_error.into_handler_error()))
}
}
})
}

@ -0,0 +1,42 @@
use askama::Template;
use futures::future;
use gotham::handler::HandlerFuture;
use gotham::helpers::http::response::{create_empty_response, create_response};
use gotham::state::{FromState, State};
use hyper::StatusCode;
use mime;
use crate::config::Config;
use crate::syntax::SYNTAXES;
#[derive(Debug, Template)]
#[template(path = "index.html")]
pub struct Index {
syntaxes: Vec<String>,
site_url: String,
}
pub fn route(mut state: State) -> Box<HandlerFuture> {
Box::new({
let config = Config::take_from(&mut state);
let template = Index {
syntaxes: SYNTAXES.to_vec(),
site_url: config.url,
};
let res = match template.render() {
Ok(content) => create_response(
&state,
StatusCode::OK,
mime::TEXT_HTML_UTF_8,
content.into_bytes(),
),
Err(_) => create_empty_response(&state, StatusCode::INTERNAL_SERVER_ERROR),
};
future::ok((state, res))
})
}

@ -0,0 +1,45 @@
use futures::future;
use gotham::handler::{HandlerFuture, IntoHandlerError};
use gotham::helpers::http::response::create_response;
use gotham::state::{FromState, State};
use gotham_derive::{StateData, StaticResponseExtender};
use hyper::StatusCode;
use mime;
use serde_derive::Deserialize;
use crate::config::Config;
use crate::paste::Paste;
#[derive(Deserialize, StateData, StaticResponseExtender)]
pub struct Params {
id: String,
}
pub fn get(mut state: State) -> Box<HandlerFuture> {
Box::new({
let config = Config::take_from(&mut state);
let Params { id } = Params::take_from(&mut state);
let mut path = config.data_directory;
path.push(id);
match Paste::from_file(path) {
Ok(paste) => {
let res = create_response(
&state,
StatusCode::OK,
mime::TEXT_PLAIN,
paste.text,
);
future::ok((state, res))
},
Err(e) => {
let io_error = std::io::Error::new(std::io::ErrorKind::Other, e.description());
future::err((state, io_error.into_handler_error()))
},
}
})
}

@ -0,0 +1,103 @@
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use futures::{future, Future, Stream};
use gotham::handler::{HandlerFuture, IntoHandlerError};
use gotham::helpers::http::response::create_response;
use gotham::state::{FromState, State};
use hyper::Response;
use hyper::{Body, StatusCode};
use mime;
use url::form_urlencoded;
use crate::config::Config;
use crate::paste::Paste;
pub fn put(mut state: State) -> Box<HandlerFuture> {
Box::new({
Body::take_from(&mut state).concat2().then(|body| {
let config = Config::take_from(&mut state);
match body {
Ok(b) => {
let body_content = b.into_bytes();
let text = String::from_utf8(body_content.as_ref().to_vec()).unwrap();
match Paste::from_text(text) {
Ok(paste) => {
let mut path = config.data_directory.clone();
path.push(paste.id.clone());
if let Err(e) = paste.to_file(path) {
let err = Error::new(ErrorKind::Other, e.description());
future::err((state, err.into_handler_error()))
} else {
let res = create_response(
&state,
StatusCode::OK,
mime::TEXT_PLAIN,
format!("{}/{}\n", config.url, paste.id),
);
future::ok((state, res))
}
},
Err(e) => {
let err = Error::new(ErrorKind::Other, e.description());
future::err((state, err.into_handler_error()))
}
}
},
Err(e) => future::err((state, e.into_handler_error())),
}
})
})
}
pub fn post(mut state: State) -> Box<HandlerFuture> {
Box::new({
Body::take_from(&mut state).concat2().then(|body| {
let config = Config::take_from(&mut state);
match body {
Ok(b) => {
let body_content = b.into_bytes();
let form_map: HashMap<String, String> = form_urlencoded::parse(&body_content)
.into_owned()
.map(|x| x)
.collect();
if let Ok(paste) = Paste::from_form(form_map) {
let mut path = config.data_directory;
path.push(paste.id.clone());
if let Err(e) = paste.to_file(path) {
let err = Error::new(ErrorKind::Other, e.description());
return future::err((state, err.into_handler_error()));
}
let res = Response::builder()
.status(303)
.header("Location", format!("/{}", paste.id))
.body(Body::empty())
.unwrap();
future::ok((state, res))
} else {
let res = create_response(
&state,
StatusCode::OK,
mime::TEXT_PLAIN,
"ERR"
);
future::ok((state, res))
}
}
Err(e) => future::err((state, e.into_handler_error())),
}
})
})
}

@ -0,0 +1,85 @@
use askama::Template;
use futures::future;
use gotham::handler::{HandlerFuture, IntoHandlerError};
use gotham::helpers::http::response::{create_empty_response, create_response};
use gotham::state::{FromState, State};
use gotham_derive::{StateData, StaticResponseExtender};
use hyper::StatusCode;
use mime;
use serde_derive::Deserialize;
use syntect::html::ClassedHTMLGenerator;
use crate::config::Config;
use crate::paste::Paste;
use crate::syntax::SYNTAX_SET;
#[derive(Deserialize, StateData, StaticResponseExtender)]
pub struct Params {
id: String,
}
#[derive(Debug, Template)]
#[template(path = "view.html")]
pub struct View {
id: String,
dt: String,
text_lines: Vec<String>,
index_len: usize,
site_url: String,
syntax: String,
}
pub fn get(mut state: State) -> Box<HandlerFuture> {
Box::new({
let config = Config::take_from(&mut state);
let Params { id } = Params::take_from(&mut state);
let mut path = config.data_directory.clone();
path.push(id.clone());
match Paste::from_file(path) {
Ok(paste) => {
let text_lines: Vec<String> = paste.text.lines().map(|s| s.into()).collect();
let index_len = format!("{}", text_lines.len()).len();
let syntax = SYNTAX_SET
.find_syntax_by_name(&paste.lang)
.unwrap_or_else(|| SYNTAX_SET.find_syntax_plain_text());
let mut high_lines: Vec<String> = Vec::new();
for line in text_lines {
let mut html_generator = ClassedHTMLGenerator::new(&syntax, &SYNTAX_SET);
html_generator.parse_html_for_line(&line);
high_lines.push(html_generator.finalize());
}
let template = View {
id,
dt: paste.dt.format("%Y-%m-%dT%H:%MZ").to_string(),
text_lines: high_lines,
index_len,
site_url: config.url,
syntax: paste.lang,
};
let res = match template.render() {
Ok(content) => create_response(
&state,
StatusCode::OK,
mime::TEXT_HTML_UTF_8,
content.into_bytes(),
),
Err(_) => create_empty_response(&state, StatusCode::INTERNAL_SERVER_ERROR),
};
future::ok((state, res))
}
Err(e) => {
let io_error = std::io::Error::new(std::io::ErrorKind::Other, e.description());
future::err((state, io_error.into_handler_error()))
}
}
})
}

@ -0,0 +1,33 @@
use std::fmt;
use lazy_static::lazy_static;
use syntect::parsing::SyntaxSet;
lazy_static! {
pub static ref SYNTAX_SET: SyntaxSet = SyntaxSet::load_defaults_newlines();
pub static ref SYNTAXES: Vec<String> = {
let syntax_set = SyntaxSet::load_defaults_newlines();
let mut syntaxes: Vec<String> = Vec::new();
for syntax in syntax_set.syntaxes() {
if ! syntax.hidden {
syntaxes.push(syntax.name.clone());
}
}
syntaxes.sort();
syntaxes
};
}
#[derive(Debug)]
pub struct Syntax {
pub name: String,
pub ext: String,
}
impl fmt::Display for Syntax {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}

@ -0,0 +1,539 @@
/*
* theme "Solarized (light)" generated by syntect
*/
.code {
color: #657b83;
}
.comment {
color: #93a1a1;
}
.meta.documentation {
color: #93a1a1;
}
.string {
color: #2aa198;
}
.string.regexp {
color: #2aa198;
}
.constant.character.escape {
color: #dc322f;
}
.constant.numeric {
color: #6c71c4;
}
.variable {
color: #268bd2;
}
.variable.function {
color: #b58900;
}
.variable.language {
color: #d33682;
}
.keyword {
color: #859900;
}
.meta.import {
color: #cb4b16;
}
.keyword {
color: #cb4b16;
}
.keyword.control.import {
color: #cb4b16;
}
.keyword.control.import.from {
color: #cb4b16;
}
.keyword.other.import {
color: #cb4b16;
}
.keyword.control.at-rule.include {
color: #cb4b16;
}
.keyword.control.at-rule.import {
color: #cb4b16;
}
.keyword.operator.comparison {
color: #657b83;
}
.keyword.operator.assignment {
color: #657b83;
}
.keyword.operator.arithmetic {
color: #657b83;
}
.storage {
color: #859900;
}
.storage.modifier {
color: #586e75;
}
.keyword.control.class {
color: #b58900;
}
.entity.name {
color: #b58900;
}
.entity.name.class {
color: #b58900;
}
.entity.name.type.class {
color: #b58900;
}
.entity.other.inherited-class {
color: #268bd2;
}
.entity.other.attribute-name {
color: #b58900;
}
.support {
color: #859900;
}
.support.type {
color: #859900;
}
.support.class {
color: #859900;
}
.entity.name.function {
color: #b58900;
}
.punctuation.definition.variable {
color: #859900;
}
.constant {
color: #b58900;
}
.constant.language {
color: #b58900;
}
.meta.preprocessor {
color: #b58900;
}
.entity.name.section {
color: #cb4b16;
}
.support.function.construct {
color: #dc322f;
}
.keyword.other.new {
color: #dc322f;
}
.constant.character {
color: #cb4b16;
}
.constant.other {
color: #cb4b16;
}
.entity.name.tag {
color: #268bd2;
}
.punctuation.definition.tag.html {
color: #93a1a1;
}
.punctuation.definition.tag.begin {
color: #93a1a1;
}
.punctuation.definition.tag.end {
color: #93a1a1;
}
.support.function {
color: #859900;
}
.punctuation.separator.continuation {
color: #dc322f;
}
.storage.type {
color: #268bd2;
}
.support.type.exception {
color: #cb4b16;
}
.keyword.other.special-method {
color: #cb4b16;
}
.string.quoted.double {
color: #2aa198;
}
.string.quoted.single {
color: #2aa198;
}
.punctuation.definition.string {
color: #839496;
}
.meta.brace.square {
color: #268bd2;
}
.punctuation.section.brackets {
color: #268bd2;
}
.meta.brace.round {
color: #657b83;
}
.meta.brace.curly {
color: #657b83;
}
.punctuation.section {
color: #657b83;
}
.punctuation.section.block {
color: #657b83;
}
.punctuation.definition.parameters {
color: #657b83;
}
.punctuation.section.group {
color: #657b83;
}
.support.constant.color {
color: #b58900;
}
.invalid.deprecated.color.w3c-non-standard-color-name.scss {
color: #b58900;
}
.meta.selector.css {
color: #657b83;
}
.entity.name.tag.css {
color: #b58900;
}
.entity.name.tag.scss {
color: #b58900;
}
.source.less {
color: #b58900;
}
.keyword.control.html.elements {
color: #b58900;
}
.source.sass {
color: #b58900;
}
.keyword.control.untitled {
color: #b58900;
}
.entity.other.attribute-name.class {
color: #b58900;
}
.entity.other.attribute-name.id {
color: #b58900;
}
.entity.other.attribute-name.pseudo-element {
color: #268bd2;
}
.entity.other.attribute-name.tag.pseudo-element {
color: #268bd2;
}
.entity.other.attribute-name.pseudo-class {
color: #268bd2;
}
.entity.other.attribute-name.tag.pseudo-class {
color: #268bd2;
}
.text.html.basic {
color: #657b83;
}
.meta.tag.other.html {
color: #657b83;
}
.text.html.basic {
color: #657b83;
}
.meta.tag.any.html {
color: #657b83;
}
.text.html.basic {
color: #657b83;
}
.meta.tag.block.any {
color: #657b83;
}
.text.html.basic {
color: #657b83;
}
.meta.tag.inline.any {
color: #657b83;
}
.text.html.basic {
color: #657b83;
}
.meta.tag.structure.any.html {
color: #657b83;
}
.text.html.basic {
color: #657b83;
}
.source.js.embedded.html {
color: #657b83;
}
.punctuation.separator.key-value.html {
color: #657b83;
}
.text.html.basic {
color: #b58900;
}
.entity.other.attribute-name.html {
color: #b58900;
}
.meta.tag.xml {
color: #b58900;
}
.entity.other.attribute-name {
color: #b58900;
}
.keyword.other.special-method.ruby {
color: #859900;
}
.variable.other.constant.ruby {
color: #b58900;
}
.constant.other.symbol.ruby {
color: #2aa198;
}
.keyword.other.special-method.ruby {
color: #cb4b16;
}
.meta.array {
color: #b58900;
}
.support.function.construct.php {
color: #b58900;
}
.entity.name.function.preprocessor.c {
color: #cb4b16;
}
.meta.preprocessor.c.include {
color: #cb4b16;
}
.meta.preprocessor.macro.c {
color: #cb4b16;
}
.meta.preprocessor.c.include {
color: #2aa198;
}
.string.quoted.other.lt-gt.include.c {
color: #2aa198;
}
.meta.preprocessor.c.include {
color: #2aa198;
}
.punctuation.definition.string.begin.c {
color: #2aa198;
}
.meta.preprocessor.c.include {
color: #2aa198;
}
.punctuation.definition.string.end.c {
color: #2aa198;
}
.other.package.exclude {
color: #dc322f;
}
.other.remove {
color: #dc322f;
}
.other.add {
color: #2aa198;
}
.punctuation.section.group.tex {
color: #dc322f;
}
.punctuation.definition.arguments.begin.latex {
color: #dc322f;
}
.punctuation.definition.arguments.end.latex {
color: #dc322f;
}
.punctuation.definition.arguments.latex {
color: #dc322f;
}
.meta.group.braces.tex {
color: #b58900;
}
.string.other.math.tex {
color: #b58900;
}
.variable.parameter.function.latex {
color: #cb4b16;
}
.punctuation.definition.constant.math.tex {
color: #dc322f;
}
.text.tex.latex {
color: #2aa198;
}
.constant.other.math.tex {
color: #2aa198;
}
.constant.other.general.math.tex {
color: #2aa198;
}
.constant.other.general.math.tex {
color: #2aa198;
}
.constant.character.math.tex {
color: #2aa198;
}
.string.other.math.tex {
color: #b58900;
}
.punctuation.definition.string.begin.tex {
color: #dc322f;
}
.punctuation.definition.string.end.tex {
color: #dc322f;
}
.keyword.control.label.latex {
color: #2aa198;
}
.text.tex.latex {
color: #2aa198;
}
.constant.other.general.math.tex {
color: #2aa198;
}
.variable.parameter.definition.label.latex {
color: #dc322f;
}
.support.function.be.latex {
color: #859900;
}
.support.function.section.latex {
color: #cb4b16;
}
.support.function.general.tex {
color: #2aa198;
}
.keyword.control.ref.latex {
color: #2aa198;
}
.storage.type.class.python {
color: #859900;
}
.storage.type.function.python {
color: #859900;
}
.storage.modifier.global.python {
color: #859900;
}
.support.type.exception.python {
color: #b58900;
}
.meta.scope.for-in-loop.shell {
color: #586e75;
}
.variable.other.loop.shell {
color: #586e75;
}
.meta.scope.case-block.shell {
color: #586e75;
}
.meta.scope.case-body.shell {
color: #586e75;
}
.punctuation.definition.logical-expression.shell {
color: #dc322f;
}
.storage.modifier.c++ {
color: #859900;
}
.support.function.perl {
color: #268bd2;
}
.meta.diff {
color: #93a1a1;
}
.meta.diff.header {
color: #93a1a1;
}
.meta.diff.range {
color: #268bd2;
}
.markup.deleted {
color: #dc322f;
}
.markup.changed {
color: #2aa198;
}
.markup.inserted {
color: #859900;
}
.markup.heading {
color: #b58900;
}
.punctuation.definition.heading.markdown {
color: #b58900;
}
.markup.quote {
color: #859900;
}
.markup.italic {
font-style: italic;
}
.markup.bold {
font-weight: bold;
}
.markup.underline.link.markdown {
color: #2aa198;
}
.meta.link.reference {
color: #2aa198;
}
.constant.other.reference.link.markdown {
color: #2aa198;
}
.constant.other.reference.link.markdown {
color: #6c71c4;
}
.sublimelinter.notes {
color: #eee8d5;
}
.sublimelinter.outline.illegal {
color: #93a1a1;
}
.sublimelinter.outline.warning {
color: #839496;
}
.sublimelinter.outline.violation {
color: #657b83;
}
.sublimelinter.mark.warning {
color: #b58900;
}
.sublimelinter.mark.error {
color: #dc322f;
}
.sublimelinter.gutter-mark {
color: #657b83;
}
.brackethighlighter.all {
color: #93a1a1;
}
.entity.name.filename.find-in-files {
color: #2aa198;
}
.constant.numeric.line-number.find-in-files {
color: #93a1a1;
}
.markup.deleted.git_gutter {
color: #dc322f;
}
.markup.inserted.git_gutter {
color: #859900;
}
.markup.changed.git_gutter {
color: #b58900;
}
.variable.other.readwrite.js {
color: #657b83;
}
.variable.other.object.js {
color: #657b83;
}
.variable.other.constant.js {
color: #657b83;
}

@ -0,0 +1,169 @@
body {
background-color: #f8f8f8;
font-family: monospace;
text-align: center;
}
.no-select {
/*-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;*/
user-select: none;
}
a {
color: blue;
text-decoration: none;
}
a:hover {
color: royalblue;
}
div.error_description {
margin: 0 auto;
max-width: 90vw;
}
div.error_description > h2 {
color: red;
}
header > hr {
border: 0;
border-top: 1px solid lightgray;
width: 90vw;
}
header > ul {
padding: 0;
}
header > ul > li {
list-style: none;
}
header > ul > li > code {
background-color: floralwhite;
color: firebrick;
padding: 2px 5px;
}
header > ul > li > code > span {
display: inline-block;
}
nav {
display: block;
}
nav > ul {
padding: 0;
}
nav > ul > li {
display: inline-block;
list-style: none;
padding: 0 2ch;
}
form > textarea {
background-color: white;
border: 1px solid lightgray;
border-radius: .5ch;
box-shadow: .1ch .1ch .25ch rgba(0, 0, 0, .45);
height: 400px;
padding: .5ch;
tab-size: 4;
-moz-tab-size: 4;
-o-tab-size: 4;
width: 120ch;
}
form > p > input {
background-color: white;
border: 1px lightgray solid;
border-radius: .5ch;
box-shadow: .1ch .1ch .25ch rgba(0, 0, 0, .45);
color: blue;
padding: .5ch;
}
form > p > input:hover {
background-color: #fcfcfc;
box-shadow: .1ch .1ch .25ch rgba(0, 0, 128, .45);
color: royalblue;
}
main {
text-align: center;
}
main > div {
overflow-wrap: break-word;
background-color: white;
border: 1px solid lightgray;
border-radius: .5ch;
box-shadow: .1ch .1ch .25ch rgba(0, 0, 0, .45);
counter-reset: line;
display: inline-block;
padding: .5rem;
text-align: left;
white-space: nowrap;
}
main > div > div {
border-bottom: 1px dashed #eee;
}
main > div > div:last-child {
border-bottom: none;
}
main > div > div:hover {
background-color: floralwhite;
}
main > div > div > div {
display: inline-block;
line-height: 1rem;
vertical-align: middle;
}
main > div > div > div.index {
text-align: right;
height: 100%;
}
main > div > div > div.index > a {
color: lightcoral;
}
main > div > div > div.index > a:hover {
color: red;
}
main > div > div > div.line {
white-space: pre-wrap;
max-width: 80vw;
tab-size: 4;
-moz-tab-size: 4;
-o-tab-size: 4;
padding: 0 !important;
padding-left: 1ch !important;
border-left: 1px solid lightgray;
margin-left: 1ch;
min-height: 1rem;
background-color: white !important;
}
.hljs {
display: inline-block !important;
}
span.hljs {
padding: 0 !important;
}

@ -0,0 +1,42 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>pastebucket :: {{id}}</title>
<link rel="stylesheet" href="/s/pastebucket.css">
</head>
<body>
<header>
<h1><a href="{{site_url|safe}}">pastebucket</a> :: <a href="/{{id}}">{{id}}</a></h1>
<hr>
</header>
<nav>
<ul>
<li><a href="/{{id}}/raw">raw</a></li>
<li><a href="/{{id}}/edit">edit</a></li>
<li>{{syntax}}</li>
<li>{{dt}}</li>
</ul>
</nav>
<form action="/" method="post">
<textarea id="paste_area" autofocus name="paste" onkeydown="ctrl_enter(event);">{{text|safe}}</textarea>
<p>
<select name="lang">
<option value="{{syntax}}" selected>{{syntax}}
<option value="Plain Text">Plain Text
{% for s in syntaxes %}
<option value="{{s}}">{{s}}
{% endfor %}
</select>
</p>
<p><input id="paste_button" type="submit" value="submit"></p>
</form>
<script>
function ctrl_enter(e) {
if (e.keyCode == 13 && e.ctrlKey) {
document.getElementById("paste_button").click();
}
}
</script>
</body>
</html>

@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>pastebucket</title>
<link rel="stylesheet" href="/s/pastebucket.css">
</head>
<body>
<header>
<h1><a href="{{site_url|safe}}">pastebucket</a></h1>
<hr>
<ul>
<li>
<code>
<span class="no-select">&lt;command&gt;</span><span>&nbsp;| curl -T- https://p.rascul.xyz</span>
</code>
</li>
<li>
<code>
<span class="no-select">-- or --</span>
</code>
</li>
<li>
<code>
<span>curl -T- https://p.rascul.xyz &lt;&nbsp;</span><span class="no-select">&lt;file&gt;</span>
</code>
</li>
</ul>
</header>
<form action="/" method="post">
<textarea id="paste_area" autofocus name="paste" onkeydown="ctrl_enter(event);"></textarea>
<p>
<select name="lang">
<option value="Plain Text">Plain Text
{% for syntax in syntaxes %}
<option value="{{syntax}}">{{syntax}}
{% endfor %}
</select>
</p>
<p><input id="paste_button" type="submit" value="submit"></p>
</form>
<script>
function ctrl_enter(e) {
if (e.keyCode == 13 && e.ctrlKey) {
document.getElementById("paste_button").click();
}
}
</script>
</body>
</html>

@ -0,0 +1,32 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>pastebucket :: {{id}}</title>
<link rel="stylesheet" href="/s/pastebucket.css">
<link rel="stylesheet" href="/s/code.css">
</head>
<body>
<header>
<h1><a href="{{site_url|safe}}">pastebucket</a> :: <a href="/{{id}}">{{id}}</a></h1>
<hr>
</header>
<nav>
<ul>
<li><a href="/{{id}}/raw">raw</a></li>
<li><a href="/{{id}}/edit">edit</a></li>
<li>{{syntax}}</li>
<li>{{dt}}</li>
</ul>
</nav>
<main>
<div>
{% for line in text_lines %}
<div id="{{loop.index}}" onmouseover="document.getElementById('{{loop.index}}').firstElementChild.firstElementChild.style = 'color: red'" onmouseout="document.getElementById('{{loop.index}}').firstElementChild.firstElementChild.style = 'color: lightcoral'">
<div class="index no-select" style="width: {{index_len}}ch"><a href="#{{loop.index}}">{{loop.index}}</a></div><div class="line">{{line|safe}}</div>
</div>
{% endfor %}
</div>
</main>
</body>
</html>
Loading…
Cancel
Save