Store program output

This commit is contained in:
Konrad Borowski 2019-11-23 21:17:26 +01:00
parent b3a473bef7
commit 1bb1782eea
13 changed files with 124 additions and 18 deletions

View File

@ -18,7 +18,7 @@ class Editor {
currentLanguage: string | null = null
abortEval: AbortController | null = null
async initialize(form) {
initialize(form) {
this.languageSelector = form.querySelector('#language')
this.wrapperButtons = new WrapperButtons(form.querySelector('#wrapper-buttons'), this.run.bind(this))
this.codeElement = form.querySelector('#code')
@ -26,16 +26,45 @@ class Editor {
onChange(editor => this.changeEditor(editor))
this.initConfiguredEditor()
this.output = new Output(form.querySelector('#output'))
const stdout = document.querySelector<HTMLInputElement>('#dbstdout')
if (stdout) {
this.output.display({}, {
stdout: stdout.value,
stderr: document.querySelector<HTMLInputElement>('#dbstderr').value,
status: +document.querySelector<HTMLInputElement>('#dbstatus')?.value,
})
}
this.autodeleteText = form.querySelector('#autodelete-text')
this.autodeleteCheckbox = form.querySelector('#automatically-hidden-label')
this.submit = form.querySelector('[type=submit]')
this.submit.disabled = true
form.addEventListener('submit', () => {
if (this.output.json && !this.output.wrapper.isFormatter) {
for (const name of ['stdout', 'stderr', 'status']) {
const elem = form.querySelector(`#${name}`) || document.createElement('input')
elem.type = 'hidden'
elem.name = name
elem.value = this.output.json[name]
form.append(elem)
}
} else {
this.stdinElement.value = ''
}
})
this.detailsElement = document.createElement('details')
const summary = document.createElement('summary')
summary.textContent = 'Standard input'
this.stdinElement = document.createElement('textarea')
this.stdinElement.name = 'stdin'
this.stdinElement.addEventListener('change', () => this.changeToLookLikeNewPaste())
this.detailsElement.append(summary, this.stdinElement)
this.detailsElement.style.display = 'none'
const dbStdin = document.querySelector<HTMLInputElement>('#dbstdin')?.value
if (dbStdin) {
this.stdinElement.value = dbStdin
this.detailsElement.open = true
} else {
this.detailsElement.style.display = 'none'
}
form.querySelector('#buttons').append(this.detailsElement)
if (this.autodeleteText) {
this.autodeleteCheckbox.style.display = 'none'
@ -71,6 +100,7 @@ class Editor {
this.autodeleteCheckbox.style.display = ''
}
this.submit.disabled = false
this.output.clear()
}
assignEvents() {
@ -134,5 +164,5 @@ class Editor {
}
export default function createEditor(form) {
return new Editor().initialize(form)
new Editor().initialize(form)
}

View File

@ -4,19 +4,13 @@ const filterRegex = /(?:\t\.(?:text|file|section|globl|p2align|type|cfi_.*|size|
export default class Output {
output: HTMLDivElement
filterAsm: HTMLLabelElement
filterAsmCheckbox: HTMLInputElement
wrapper: Wrapper
json: {
stdout: string,
stderr: string,
status: number | null,
}
filterAsm = document.createElement('label')
filterAsmCheckbox = document.createElement('input')
wrapper: Wrapper | null = null
json: { stdout: string, stderr: string, status: number | null } | null = null
constructor(output) {
this.output = output
this.filterAsm = document.createElement('label')
this.filterAsmCheckbox = document.createElement('input')
this.filterAsmCheckbox.type = 'checkbox'
this.filterAsmCheckbox.checked = true
this.filterAsmCheckbox.addEventListener('change', () => this.update())
@ -24,6 +18,7 @@ export default class Output {
}
clear() {
this.json = null
this.output.textContent = ''
}

View File

@ -0,0 +1,5 @@
ALTER TABLE pastes
DROP COLUMN stdin,
DROP COLUMN exit_code,
DROP COLUMN stdout,
DROP COLUMN stderr;

View File

@ -0,0 +1,5 @@
ALTER TABLE pastes
ADD COLUMN stdin text NOT NULL DEFAULT '',
ADD COLUMN exit_code integer,
ADD COLUMN stdout text,
ADD COLUMN stderr text;

6
package-lock.json generated
View File

@ -4061,9 +4061,9 @@
"dev": true
},
"typescript": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz",
"integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==",
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
"integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==",
"dev": true
},
"union-value": {

View File

@ -12,7 +12,7 @@
"prismjs": "^1.17.1",
"style-loader": "^1.0.0",
"ts-loader": "^6.2.0",
"typescript": "^3.6.4",
"typescript": "^3.7.2",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9",
"webpack-stats-plugin": "^0.3.0"

View File

@ -18,6 +18,10 @@ pub struct Paste {
pub language_id: i32,
pub delete_at: Option<DateTime<Utc>>,
pub identifier: String,
pub stdin: String,
pub exit_code: Option<i32>,
pub stdout: Option<String>,
pub stderr: Option<String>,
}
impl Paste {
@ -42,6 +46,10 @@ struct InsertPaste {
delete_at: Option<DateTime<Utc>>,
language_id: i32,
paste: String,
stdin: String,
stdout: Option<String>,
stderr: Option<String>,
exit_code: Option<i32>,
}
pub fn insert(
@ -49,6 +57,10 @@ pub fn insert(
delete_at: Option<DateTime<Utc>>,
language: &str,
paste: String,
stdin: String,
stdout: Option<String>,
stderr: Option<String>,
exit_code: Option<i32>,
) -> Result<String, Rejection> {
let mut rng = rand::thread_rng();
let identifier: String = (0..10)
@ -66,6 +78,10 @@ pub fn insert(
delete_at,
language_id,
paste,
stdin,
stdout,
stderr,
exit_code,
};
diesel::insert_into(pastes::table)
.values(&insert_paste)
@ -79,6 +95,10 @@ pub struct ExternPaste {
pub language_id: i32,
pub delete_at: Option<DateTime<Utc>>,
pub markdown: String,
pub stdin: String,
pub exit_code: Option<i32>,
pub stdout: Option<String>,
pub stderr: Option<String>,
}
impl ExternPaste {
@ -88,6 +108,10 @@ impl ExternPaste {
language_id,
identifier,
delete_at,
stdin,
exit_code,
stdout,
stderr,
} = paste;
let markdown = if identifier == "markdown" {
render_markdown(&paste)
@ -99,6 +123,10 @@ impl ExternPaste {
language_id,
delete_at,
markdown,
stdin,
exit_code,
stdout,
stderr,
}
}
}

View File

@ -69,6 +69,10 @@ pub fn insert_paste(
expiration.map(|expiration| Utc::now() + expiration.0),
&language,
code,
"".into(),
None,
None,
None,
)
})
.compat()

View File

@ -24,6 +24,10 @@ pub fn display_paste(
pastes::language_id,
pastes::delete_at,
languages::identifier,
pastes::stdin,
pastes::exit_code,
pastes::stdout,
pastes::stderr,
))
.filter(pastes::identifier.eq(requested_identifier))
.get_result(connection)

View File

@ -15,6 +15,11 @@ pub struct PasteForm {
language: String,
code: String,
autodelete: Option<IgnoredAny>,
#[serde(default)]
stdin: String,
stdout: Option<String>,
stderr: Option<String>,
status: Option<i32>,
}
pub fn insert_paste(
@ -22,12 +27,25 @@ pub fn insert_paste(
language,
code,
autodelete,
stdin,
stdout,
stderr,
status,
}: PasteForm,
connection: Connection,
) -> impl Future<Item = impl Reply, Error = Rejection> {
blocking::run(move || {
let delete_at = autodelete.map(|_| Utc::now() + Duration::hours(24));
let identifier = paste::insert(&connection, delete_at, &language, code)?;
let identifier = paste::insert(
&connection,
delete_at,
&language,
code,
stdin,
stdout,
stderr,
status,
)?;
Ok(reply::with_header(
StatusCode::SEE_OTHER,
LOCATION,

View File

@ -37,6 +37,10 @@ table! {
created_at -> Timestamptz,
language_id -> Int4,
paste -> Text,
stdin -> Text,
exit_code -> Nullable<Int4>,
stdout -> Nullable<Text>,
stderr -> Nullable<Text>,
}
}

View File

@ -47,6 +47,9 @@ textarea {
height: 372px;
resize: vertical;
}
[name=stdin] {
height: 124px;
}
#right-buttons {
float: right;
}

View File

@ -22,4 +22,14 @@
<p><textarea id=code name=code>@('\n')@paste.paste</textarea></p>
@:buttons()
</form>
<input type=hidden id=dbstdin value="@paste.stdin">
@if let Some(exit_code) = paste.exit_code {
<input type=hidden id=dbstatus value="@exit_code">
}
@if let Some(stdout) = paste.stdout {
<input type=hidden id=dbstdout value="@stdout">
}
@if let Some(stderr) = paste.stderr {
<input type=hidden id=dbstderr value="@stderr">
}
@:footer(session)