Compare commits
No commits in common. "27a2bea7054f59135aec342b3f8866765418666a" and "91e9645c371288bac9aaeda4dab5afd79e3b8027" have entirely different histories.
27a2bea705
...
91e9645c37
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -394,7 +394,6 @@ dependencies = [
|
|||||||
"nom",
|
"nom",
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower",
|
|
||||||
"tower-http",
|
"tower-http",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -8,5 +8,4 @@ axum = { git = "https://github.com/tokio-rs/axum.git", rev = "52a90390195e884bcc
|
|||||||
nom = "7.1.1"
|
nom = "7.1.1"
|
||||||
serde = { version = "1.0.183", features = ["derive"] }
|
serde = { version = "1.0.183", features = ["derive"] }
|
||||||
tokio = { version = "1.30.0", default-features = false, features = ["macros", "process", "rt", "rt-multi-thread"] }
|
tokio = { version = "1.30.0", default-features = false, features = ["macros", "process", "rt", "rt-multi-thread"] }
|
||||||
tower = "0.4.13"
|
tower-http = { version = "0.4.3", features = ["fs"] }
|
||||||
tower-http = { version = "0.4.3", features = ["fs", "set-header"] }
|
|
||||||
|
29
src/main.rs
29
src/main.rs
@ -1,13 +1,8 @@
|
|||||||
#![feature(exit_status_error)]
|
#![feature(exit_status_error)]
|
||||||
use axum::http::header::CACHE_CONTROL;
|
|
||||||
use axum::http::HeaderValue;
|
|
||||||
use axum::response::IntoResponse;
|
|
||||||
use axum::{http::StatusCode, routing::post, Json, Router};
|
use axum::{http::StatusCode, routing::post, Json, Router};
|
||||||
use owner_tree::build_owner_tree;
|
use owner_tree::{build_owner_tree, OwnerTree};
|
||||||
use parse::emacs_parse_org_document;
|
use parse::emacs_parse_org_document;
|
||||||
use tower::ServiceBuilder;
|
|
||||||
use tower_http::services::{ServeDir, ServeFile};
|
use tower_http::services::{ServeDir, ServeFile};
|
||||||
use tower_http::set_header::SetResponseHeaderLayer;
|
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod owner_tree;
|
mod owner_tree;
|
||||||
@ -16,32 +11,26 @@ mod sexp;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let static_files_service = {
|
let serve_dir = ServeDir::new("static").not_found_service(ServeFile::new("static/index.html"));
|
||||||
let serve_dir =
|
|
||||||
ServeDir::new("static").not_found_service(ServeFile::new("static/index.html"));
|
|
||||||
|
|
||||||
ServiceBuilder::new()
|
|
||||||
.layer(SetResponseHeaderLayer::if_not_present(
|
|
||||||
CACHE_CONTROL,
|
|
||||||
HeaderValue::from_static("public, max-age=120"),
|
|
||||||
))
|
|
||||||
.service(serve_dir)
|
|
||||||
};
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/parse", post(parse_org_mode))
|
.route("/parse", post(parse_org_mode))
|
||||||
.fallback_service(static_files_service);
|
.fallback_service(serve_dir);
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
axum::serve(listener, app).await.unwrap();
|
axum::serve(listener, app).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_org_mode(body: String) -> Result<impl IntoResponse, (StatusCode, String)> {
|
async fn parse_org_mode(
|
||||||
|
body: String,
|
||||||
|
) -> Result<(StatusCode, Json<OwnerTree>), (StatusCode, String)> {
|
||||||
_parse_org_mode(body)
|
_parse_org_mode(body)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))
|
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn _parse_org_mode(body: String) -> Result<impl IntoResponse, Box<dyn std::error::Error>> {
|
async fn _parse_org_mode(
|
||||||
|
body: String,
|
||||||
|
) -> Result<(StatusCode, Json<OwnerTree>), Box<dyn std::error::Error>> {
|
||||||
let ast = emacs_parse_org_document(&body).await?;
|
let ast = emacs_parse_org_document(&body).await?;
|
||||||
let owner_tree = build_owner_tree(body.as_str(), ast.as_str()).map_err(|e| e.to_string())?;
|
let owner_tree = build_owner_tree(body.as_str(), ast.as_str()).map_err(|e| e.to_string())?;
|
||||||
Ok((StatusCode::OK, Json(owner_tree)))
|
Ok((StatusCode::OK, Json(owner_tree)))
|
||||||
|
@ -1,21 +1,5 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="reset.css">
|
|
||||||
<link rel="stylesheet" href="style.css">
|
|
||||||
<script type="text/javascript" src="script.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<h2>Input org-mode source:</h2>
|
Test html file.
|
||||||
<textarea id="org-input" rows="24" cols="80"></textarea>
|
|
||||||
<hr/>
|
|
||||||
<div class="output_container">
|
|
||||||
<div>
|
|
||||||
<div id="parse-output" class="code_block" style="counter-set: code_line_number 0;"></div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
tree goes here
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
/* http://meyerweb.com/eric/tools/css/reset/
|
|
||||||
v2.0 | 20110126
|
|
||||||
License: none (public domain)
|
|
||||||
*/
|
|
||||||
|
|
||||||
html, body, div, span, applet, object, iframe,
|
|
||||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
|
||||||
a, abbr, acronym, address, big, cite, code,
|
|
||||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
|
||||||
small, strike, strong, sub, sup, tt, var,
|
|
||||||
b, u, i, center,
|
|
||||||
dl, dt, dd, ol, ul, li,
|
|
||||||
fieldset, form, label, legend,
|
|
||||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
|
||||||
article, aside, canvas, details, embed,
|
|
||||||
figure, figcaption, footer, header, hgroup,
|
|
||||||
menu, nav, output, ruby, section, summary,
|
|
||||||
time, mark, audio, video {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
font-size: 100%;
|
|
||||||
font: inherit;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
/* HTML5 display-role reset for older browsers */
|
|
||||||
article, aside, details, figcaption, figure,
|
|
||||||
footer, header, hgroup, menu, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
ol, ul {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
blockquote, q {
|
|
||||||
quotes: none;
|
|
||||||
}
|
|
||||||
blockquote:before, blockquote:after,
|
|
||||||
q:before, q:after {
|
|
||||||
content: '';
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
let inFlightRequest = null;
|
|
||||||
const inputElement = document.querySelector("#org-input");
|
|
||||||
const outputElement = document.querySelector("#parse-output");
|
|
||||||
|
|
||||||
function abortableFetch(request, options) {
|
|
||||||
const controller = new AbortController();
|
|
||||||
const signal = controller.signal;
|
|
||||||
|
|
||||||
return {
|
|
||||||
abort: () => controller.abort(),
|
|
||||||
ready: fetch(request, { ...options, signal })
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderParseResponse(response) {
|
|
||||||
console.log(response);
|
|
||||||
outputElement.innerHTML = "";
|
|
||||||
const lines = response.input.split(/\r?\n/);
|
|
||||||
const numLines = lines.length;
|
|
||||||
const numDigits = Math.log10(numLines) + 1;
|
|
||||||
|
|
||||||
outputElement.style.paddingLeft = `calc(${numDigits + 1}ch + 10px)`;
|
|
||||||
|
|
||||||
for (let line of lines) {
|
|
||||||
let wrappedLine = document.createElement("code");
|
|
||||||
wrappedLine.textContent = line ? line : "\n";
|
|
||||||
outputElement.appendChild(wrappedLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inputElement.addEventListener("input", async () => {
|
|
||||||
let orgSource = inputElement.value;
|
|
||||||
if (inFlightRequest != null) {
|
|
||||||
inFlightRequest.abort();
|
|
||||||
inFlightRequest = null;
|
|
||||||
}
|
|
||||||
outputElement.innerHTML = "";
|
|
||||||
|
|
||||||
let newRequest = abortableFetch("/parse", {
|
|
||||||
method: "POST",
|
|
||||||
cache: "no-cache",
|
|
||||||
body: orgSource,
|
|
||||||
});
|
|
||||||
inFlightRequest = newRequest;
|
|
||||||
|
|
||||||
let response = null;
|
|
||||||
try {
|
|
||||||
response = await inFlightRequest.ready;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
if (err.name === "AbortError") return;
|
|
||||||
}
|
|
||||||
renderParseResponse(await response.json());
|
|
||||||
});
|
|
||||||
|
|
||||||
function highlightLine(htmlName, lineOffset) {
|
|
||||||
const childOffset = lineOffset + 1;
|
|
||||||
const codeLineElement = document.querySelector(`.${htmlName} > code:nth-child(${childOffset})`);
|
|
||||||
codeLineElement?.classList.add("highlighted")
|
|
||||||
}
|
|
||||||
|
|
||||||
function unhighlightLine(htmlName, lineOffset) {
|
|
||||||
const childOffset = lineOffset + 1;
|
|
||||||
const codeLineElement = document.querySelector(`.${htmlName} > code:nth-child(${childOffset})`);
|
|
||||||
codeLineElement?.classList.remove("highlighted")
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
h1, h2, h3, h4, h5, h6, h7 {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
font-size: 28px;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
h4 {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
h5 {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
h6 {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
h7 {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code_block {
|
|
||||||
font: 14px/1.4 "Cascadia Mono", monospace;
|
|
||||||
background: #272822ff;
|
|
||||||
color: #f8f8f2ff;
|
|
||||||
display: table;
|
|
||||||
white-space: break-spaces;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code_block > code {
|
|
||||||
display: table;
|
|
||||||
counter-increment: code_line_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code_block > code::before {
|
|
||||||
content: counter(code_line_number) " ";
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
transform: TranslateX(-100%);
|
|
||||||
padding-right: 5px;
|
|
||||||
color: #eeeeee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code_block > code.highlighted {
|
|
||||||
background: #307351ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code_block > code.highlighted::before {
|
|
||||||
background: #307351ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.output_container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.output_container > * {
|
|
||||||
flex: 1 0;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user