Highlight code, start code tooltip
This commit is contained in:
parent
331acd4574
commit
8deab1c2d5
139
Cargo.lock
generated
139
Cargo.lock
generated
@ -544,10 +544,25 @@ version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
@ -1067,8 +1082,8 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1077,13 +1092,23 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae91abf6555234338687bb47913978d275539235fcb77ba9863b779090b42b14"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fast_chemail"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4"
|
||||
dependencies = [
|
||||
"ascii_utils",
|
||||
"ascii_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1687,19 +1712,21 @@ dependencies = [
|
||||
name = "jirs_client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
"comrak",
|
||||
"futures 0.1.29",
|
||||
"jirs-data",
|
||||
"js-sys",
|
||||
"seed",
|
||||
"serde",
|
||||
"uuid 0.8.1",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
"web-sys",
|
||||
"wee_alloc",
|
||||
"bincode",
|
||||
"chrono",
|
||||
"comrak",
|
||||
"futures 0.1.29",
|
||||
"jirs-data",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"seed",
|
||||
"serde",
|
||||
"syntect",
|
||||
"uuid 0.8.1",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
"web-sys",
|
||||
"wee_alloc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1767,8 +1794,8 @@ dependencies = [
|
||||
"email",
|
||||
"lettre",
|
||||
"mime",
|
||||
"time 0.1.43",
|
||||
"uuid 0.7.4",
|
||||
"time 0.1.43",
|
||||
"uuid 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1777,6 +1804,15 @@ version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
|
||||
dependencies = [
|
||||
"safemem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.3"
|
||||
@ -2247,6 +2283,20 @@ version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b336d94e8e4ce29bf15bba393164629764744c567e8ad306cc1fdd0119967fd"
|
||||
dependencies = [
|
||||
"base64 0.12.3",
|
||||
"chrono",
|
||||
"indexmap",
|
||||
"line-wrap",
|
||||
"serde",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
@ -3003,10 +3053,32 @@ version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntect"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b57a45fdcf4891bc79f635be5c559210a4cfa464891f969724944c713282eedb"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
"fancy-regex",
|
||||
"flate2",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"plist",
|
||||
"regex-syntax",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3015,9 +3087,9 @@ version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand 0.7.3",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand 0.7.3",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi 0.3.9",
|
||||
@ -3686,8 +3758,8 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3696,6 +3768,15 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.1.0"
|
||||
|
@ -11,7 +11,7 @@ license = "MPL-2.0"
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
name = "jirs_client"
|
||||
path = "./src/lib.rs"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0 # Use slightly better optimizations.
|
||||
@ -32,6 +32,9 @@ futures = "^0.1.26"
|
||||
comrak = "*"
|
||||
wee_alloc = "*"
|
||||
|
||||
lazy_static = "*"
|
||||
syntect = { version = "*", default-features = false, features = ["default-fancy"] }
|
||||
|
||||
[dependencies.wasm-bindgen]
|
||||
version = "0.2.66"
|
||||
features = ["enable-interning"]
|
||||
|
125
jirs-client/src/elements.rs
Normal file
125
jirs-client/src/elements.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use syntect::easy::HighlightLines;
|
||||
use syntect::highlighting::{FontStyle, Style};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(final, js_name = JirsCodeBuilder)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct JirsCodeBuilder {}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl JirsCodeBuilder {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn hi(&mut self, lang: &str, line: &str) -> String {
|
||||
let syntax = match crate::hi::SYNTAX_SET.find_syntax_by_name(lang) {
|
||||
Some(s) => s,
|
||||
_ => {
|
||||
return line.to_string();
|
||||
}
|
||||
};
|
||||
let mut h = HighlightLines::new(syntax, &crate::hi::THEME_SET.themes["base16-ocean-dark"]); // inspired-github
|
||||
let tokens = h.highlight(line, &crate::hi::SYNTAX_SET);
|
||||
|
||||
let parts: Vec<String> = tokens
|
||||
.into_iter()
|
||||
.map(|(style, token)| {
|
||||
let Style {
|
||||
foreground: f,
|
||||
background: b,
|
||||
font_style,
|
||||
} = style;
|
||||
let fs = if font_style == FontStyle::BOLD {
|
||||
"font-weight: bold"
|
||||
} else if font_style == FontStyle::ITALIC {
|
||||
"font-style: italic"
|
||||
} else {
|
||||
"font-decoration: underline"
|
||||
};
|
||||
let f = format!("rgba({}, {}, {}, {})", f.r, f.g, f.b, f.a);
|
||||
let b = format!("rgba({}, {}, {}, {})", b.r, b.g, b.b, b.a);
|
||||
format!(
|
||||
r#"<span style="color: {f};background:{b}; {fs}">{t}</span>"#,
|
||||
t = if token.is_empty() { " " } else { token },
|
||||
f = f,
|
||||
b = b,
|
||||
fs = fs
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
parts.join("")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define() {
|
||||
create_custom_element(
|
||||
"jirs-code-view",
|
||||
"JirsCodeView",
|
||||
r#"
|
||||
<style>
|
||||
:host { display: block; border: 1px solid black; background: rgba(43, 48, 59, 255); padding: 1rem; }
|
||||
:host { margin-left: 400px; }
|
||||
#view span { white-space: pre; }
|
||||
</style>
|
||||
<div id='view'></div>
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
fn create_custom_element(tag: &str, name: &str, html: &str) {
|
||||
let source = format!(
|
||||
r#"
|
||||
class {name} extends HTMLElement {{
|
||||
static RUNTIME = Symbol();
|
||||
static SHADOW = Symbol();
|
||||
|
||||
static get observedAttributes() {{ return ['lang']; }}
|
||||
|
||||
constructor() {{
|
||||
super();
|
||||
this[ {name} . SHADOW] = this.attachShadow({{ 'mode': 'closed' }});
|
||||
this[ {name} . SHADOW].innerHTML = `{html}`;
|
||||
}}
|
||||
|
||||
connectedCallback() {{
|
||||
this[ {name} . RUNTIME] = new JirsCodeBuilder();
|
||||
const view = this[ {name} . SHADOW].querySelector('#view');
|
||||
view.innerHTML = '';
|
||||
const lang = this.getAttribute('lang') || '';
|
||||
|
||||
setTimeout(() => {{
|
||||
const hi = () => {{
|
||||
const line = code.shift();
|
||||
if (line === undefined) return;
|
||||
const s = this[ {name} . RUNTIME].hi(lang, line);
|
||||
view.innerHTML += `${{s}}<br />`;
|
||||
setTimeout(() => hi(), 10);
|
||||
}};
|
||||
hi();
|
||||
}}, 10);
|
||||
}}
|
||||
|
||||
disconnectedCallback() {{
|
||||
this[ {name} . RUNTIME].free();
|
||||
}}
|
||||
|
||||
attributeChangedCallback(name, oldV, newV) {{
|
||||
}}
|
||||
}}
|
||||
customElements.define( '{tag}', {name});
|
||||
"#,
|
||||
name = name,
|
||||
tag = tag,
|
||||
html = html,
|
||||
);
|
||||
{
|
||||
use seed::*;
|
||||
match js_sys::eval(source.as_str()) {
|
||||
Ok(_v) => (),
|
||||
Err(e) => error!(e),
|
||||
};
|
||||
};
|
||||
}
|
BIN
jirs-client/src/hi/all.themedump
Normal file
BIN
jirs-client/src/hi/all.themedump
Normal file
Binary file not shown.
9
jirs-client/src/hi/mod.rs
Normal file
9
jirs-client/src/hi/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use lazy_static::lazy_static;
|
||||
use syntect::dumps::from_binary;
|
||||
use syntect::highlighting::ThemeSet;
|
||||
use syntect::parsing::SyntaxSet;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SYNTAX_SET: SyntaxSet = from_binary(include_bytes!("./newlines.packdump"));
|
||||
pub static ref THEME_SET: ThemeSet = from_binary(include_bytes!("./all.themedump"));
|
||||
}
|
BIN
jirs-client/src/hi/newlines.packdump
Normal file
BIN
jirs-client/src/hi/newlines.packdump
Normal file
Binary file not shown.
@ -15,7 +15,9 @@ use crate::shared::{go_to_board, go_to_login, styled_tooltip};
|
||||
use crate::ws::{flush_queue, open_socket, read_incoming, send_ws_msg};
|
||||
|
||||
mod changes;
|
||||
pub mod elements;
|
||||
mod fields;
|
||||
pub mod hi;
|
||||
mod invite;
|
||||
mod modal;
|
||||
mod model;
|
||||
@ -261,6 +263,7 @@ pub static mut WS_URL: String = String::new();
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn render(host_url: String, ws_url: String) {
|
||||
elements::define();
|
||||
unsafe {
|
||||
HOST_URL = host_url;
|
||||
WS_URL = ws_url;
|
||||
|
@ -70,12 +70,17 @@ pub enum RteMsg {
|
||||
RemoveFormat,
|
||||
Subscript,
|
||||
Superscript,
|
||||
|
||||
// table
|
||||
TableSetVisibility(bool),
|
||||
TableSetRows(u16),
|
||||
TableSetColumns(u16),
|
||||
TableSetVisibility(bool),
|
||||
InsertTable { rows: u16, cols: u16 },
|
||||
ChangeIndent(RteIndentMsg),
|
||||
|
||||
// code
|
||||
InsertCode(bool),
|
||||
|
||||
RequestFocus(uuid::Uuid),
|
||||
}
|
||||
|
||||
@ -139,6 +144,8 @@ impl RteMsg {
|
||||
RteMsg::Subscript => Some(ExecCommand::new("subscript")),
|
||||
RteMsg::Superscript => Some(ExecCommand::new("superscript")),
|
||||
RteMsg::InsertTable { .. } => None,
|
||||
// code
|
||||
RteMsg::InsertCode(_) => None,
|
||||
|
||||
// indent
|
||||
RteMsg::ChangeIndent(RteIndentMsg::Increase) => Some(ExecCommand::new("indent")),
|
||||
@ -171,11 +178,18 @@ pub struct StyledRteTableState {
|
||||
pub cols: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StyledRteCodeState {
|
||||
pub visible: bool,
|
||||
pub lang: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledRteState {
|
||||
pub value: String,
|
||||
pub field_id: FieldId,
|
||||
pub table_tooltip: StyledRteTableState,
|
||||
pub code_tooltip: StyledRteCodeState,
|
||||
range: Option<web_sys::Range>,
|
||||
identifier: uuid::Uuid,
|
||||
}
|
||||
@ -190,6 +204,10 @@ impl StyledRteState {
|
||||
rows: 3,
|
||||
cols: 3,
|
||||
},
|
||||
code_tooltip: StyledRteCodeState {
|
||||
visible: false,
|
||||
lang: "".to_string(),
|
||||
},
|
||||
range: None,
|
||||
identifier: uuid::Uuid::new_v4(),
|
||||
}
|
||||
@ -217,6 +235,12 @@ impl StyledRteState {
|
||||
self.schedule_focus(orders);
|
||||
}
|
||||
_ => match m {
|
||||
RteMsg::InsertCode(b) => {
|
||||
if *b {
|
||||
self.store_range();
|
||||
}
|
||||
self.code_tooltip.visible = *b;
|
||||
}
|
||||
RteMsg::TableSetRows(n) => {
|
||||
self.table_tooltip.rows = *n;
|
||||
}
|
||||
@ -772,41 +796,48 @@ fn second_row(values: &StyledRte) -> Node<Msg> {
|
||||
None as Option<Msg>
|
||||
}),
|
||||
);*/
|
||||
let field_id = values.field_id.clone();
|
||||
let mut table_button = styled_rte_button(
|
||||
"Table",
|
||||
Icon::Table,
|
||||
mouse_ev(Ev::Click, move |ev| {
|
||||
ev.prevent_default();
|
||||
Some(Msg::Rte(RteMsg::TableSetVisibility(true), field_id))
|
||||
}),
|
||||
);
|
||||
|
||||
let mut table_button = {
|
||||
let field_id = values.field_id.clone();
|
||||
styled_rte_button(
|
||||
"Table",
|
||||
Icon::Table,
|
||||
mouse_ev(Ev::Click, move |ev| {
|
||||
ev.prevent_default();
|
||||
Some(Msg::Rte(RteMsg::TableSetVisibility(true), field_id))
|
||||
}),
|
||||
)
|
||||
};
|
||||
table_button.add_child(table_tooltip);
|
||||
|
||||
let field_id = values.field_id.clone();
|
||||
let paragraph_button = styled_rte_button(
|
||||
"Paragraph",
|
||||
Icon::Paragraph,
|
||||
mouse_ev(Ev::Click, move |ev| {
|
||||
ev.prevent_default();
|
||||
Some(Msg::Rte(RteMsg::InsertParagraph, field_id))
|
||||
}),
|
||||
);
|
||||
// let field_id = values.field_id.clone();
|
||||
// let code_alt_button = styled_rte_button(
|
||||
// "Insert code",
|
||||
// Icon::CodeAlt,
|
||||
// mouse_ev(Ev::Click, move |ev| {
|
||||
// ev.prevent_default();
|
||||
// None as Option<Msg>
|
||||
// }),
|
||||
// );
|
||||
let paragraph_button = {
|
||||
let field_id = values.field_id.clone();
|
||||
styled_rte_button(
|
||||
"Paragraph",
|
||||
Icon::Paragraph,
|
||||
mouse_ev(Ev::Click, move |ev| {
|
||||
ev.prevent_default();
|
||||
Some(Msg::Rte(RteMsg::InsertParagraph, field_id))
|
||||
}),
|
||||
)
|
||||
};
|
||||
let code_alt_button = {
|
||||
let field_id = values.field_id.clone();
|
||||
styled_rte_button(
|
||||
"Insert code",
|
||||
Icon::CodeAlt,
|
||||
mouse_ev(Ev::Click, move |ev| {
|
||||
ev.prevent_default();
|
||||
Some(Msg::Rte(RteMsg::InsertCode(true), field_id))
|
||||
}),
|
||||
)
|
||||
};
|
||||
|
||||
div![
|
||||
class!["group insert"],
|
||||
paragraph_button,
|
||||
table_button,
|
||||
// code_alt_button,
|
||||
code_alt_button,
|
||||
listing_dots,
|
||||
listing_number,
|
||||
// sub_listing_button,
|
||||
@ -931,3 +962,22 @@ fn styled_rte_button(title: &str, icon: Icon, handler: EventHandler<Msg>) -> Nod
|
||||
button
|
||||
]
|
||||
}
|
||||
|
||||
fn insert_code() -> Node<Msg> {
|
||||
let mut languages: Vec<&str> = crate::hi::SYNTAX_SET
|
||||
.syntaxes()
|
||||
.iter()
|
||||
.map(|s| s.name.as_str())
|
||||
.collect();
|
||||
languages.sort();
|
||||
let options: Vec<Node<Msg>> = languages
|
||||
.into_iter()
|
||||
.map(|name| option![attrs![At::Value => name], name])
|
||||
.collect();
|
||||
|
||||
seed::select![options]
|
||||
}
|
||||
|
||||
pub fn code_to_tag(code: &str) -> Node<Msg> {
|
||||
custom!["jirs-code-view", code]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user