Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8e4e227

Browse files
committed
inline initialSource
1 parent f5bed1d commit 8e4e227

File tree

3 files changed

+89
-114
lines changed

3 files changed

+89
-114
lines changed

docs/index.html

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,65 @@ <h1>Syntax Tree</h1>
1414
<a href="https://github.com/ruby-syntax-tree/syntax_tree">Source</a>
1515
<span><button type="button" id="format">Format</button></span>
1616
</nav>
17-
<textarea id="editor"></textarea>
17+
<textarea id="editor"># frozen_string_literal: true
18+
19+
require "json"
20+
require "pp"
21+
require "prettyprint"
22+
require "ripper"
23+
require "stringio"
24+
25+
require_relative "syntax_tree/formatter"
26+
require_relative "syntax_tree/node"
27+
require_relative "syntax_tree/parser"
28+
require_relative "syntax_tree/prettyprint"
29+
require_relative "syntax_tree/version"
30+
require_relative "syntax_tree/visitor"
31+
require_relative "syntax_tree/visitor/json_visitor"
32+
require_relative "syntax_tree/visitor/pretty_print_visitor"
33+
34+
module SyntaxTree
35+
# This holds references to objects that respond to both #parse and #format
36+
# so that we can use them in the CLI.
37+
HANDLERS = {}
38+
HANDLERS.default = SyntaxTree
39+
40+
# This is a hook provided so that plugins can register themselves as the
41+
# handler for a particular file type.
42+
def self.register_handler(extension, handler)
43+
HANDLERS[extension] = handler
44+
end
45+
46+
# Parses the given source and returns the syntax tree.
47+
def self.parse(source)
48+
parser = Parser.new(source)
49+
response = parser.parse
50+
response unless parser.error?
51+
end
52+
53+
# Parses the given source and returns the formatted source.
54+
def self.format(source)
55+
formatter = Formatter.new(source, [])
56+
parse(source).format(formatter)
57+
58+
formatter.flush
59+
formatter.output.join
60+
end
61+
62+
# Returns the source from the given filepath taking into account any potential
63+
# magic encoding comments.
64+
def self.read(filepath)
65+
encoding =
66+
File.open(filepath, "r") do |file|
67+
header = file.readline
68+
header += file.readline if header.start_with?("#!")
69+
Ripper.new(header).tap(&:parse).encoding
70+
end
71+
72+
File.read(filepath, encoding: encoding)
73+
end
74+
end
75+
</textarea>
1876
<textarea id="tree" disabled readonly>Loading...</textarea>
1977
</main>
2078
<script type="module" src="index.js"></script>

src/index.ts

Lines changed: 30 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
11
import "./index.css";
22

3-
import type { Editor } from "codemirror";
4-
import type { Ruby } from "./createRuby";
5-
import initialSource from "./initialSource";
3+
Promise.all([
4+
// We're going to load the editor asynchronously so that we can get to
5+
// first-paint faster. This works out nicely since we can use a textarea until
6+
// this chunk is loaded.
7+
import("./CodeMirror").then(({ default: CodeMirror }) => {
8+
const editor = document.getElementById("editor") as HTMLTextAreaElement;
9+
const newEditor = document.createElement("div");
10+
editor.replaceWith(newEditor);
11+
12+
return CodeMirror(newEditor, {
13+
lineNumbers: true,
14+
mode: "ruby",
15+
theme: "xq-light",
16+
value: editor.value
17+
});
18+
}),
19+
// We're going to load the Ruby VM chunk asynchronously because it is pretty
20+
// dang huge (> 40Mb). In the meantime the textarea that is holding the place
21+
// of the actual functional one is just going to display "Loading...".
22+
import("./createRuby").then(({ default: createRuby }) => createRuby())
23+
]).then(([editor, ruby]) => {
24+
// First, grab a reference to the tree element so that we can update it. Then,
25+
// set it initially to the tree represented by the source already there.
26+
const tree = document.getElementById("tree") as HTMLTextAreaElement;
27+
tree.value = ruby.prettyPrint(editor.getDoc().getValue());
28+
tree.disabled = false;
629

7-
let editorElement = document.getElementById("editor") as HTMLTextAreaElement;
8-
const formatElement = document.getElementById("format");
9-
const treeElement = document.getElementById("tree") as HTMLTextAreaElement;
10-
11-
// First, set the initial value of the editor element. It's just going to be a
12-
// textarea until we've loaded the editor chunk.
13-
editorElement.value = initialSource;
14-
15-
let editor: Editor = null;
16-
let ruby: Ruby = null;
17-
18-
type SourceChangedEvent = {
19-
source: string
20-
};;
21-
22-
// This function is called to set up the event handlers once both the editor and
23-
// the ruby chunk have been loaded.
24-
function synchronize() {
2530
// We're going to handle updates to the source through a custom event. This
2631
// turns out to be faster than handling the change event directly on the
2732
// editor since it blocks updates to the UI until the event handled returns.
28-
document.body.addEventListener("source-changed", (event: CustomEvent<SourceChangedEvent>) => {
33+
tree.addEventListener("source-changed", (event: CustomEvent<{ source: string }>) => {
2934
try {
30-
treeElement.value = ruby.prettyPrint(event.detail.source);
35+
tree.value = ruby.prettyPrint(event.detail.source);
3136
} catch (error) {
3237
// For now, just ignoring the error. Eventually I'd like to make this mark
3338
// an error state on the editor to give feedback to the user.
@@ -37,41 +42,14 @@ function synchronize() {
3742
// Attach to the editor and dispatch custom source-changed events whenever the
3843
// value is updated in the editor.
3944
editor.on("change", () => {
40-
document.body.dispatchEvent(new CustomEvent<SourceChangedEvent>("source-changed", {
45+
tree.dispatchEvent(new CustomEvent<{ source: string }>("source-changed", {
4146
detail: { source: editor.getDoc().getValue() }
4247
}));
4348
});
4449

4550
// Attach to the format button to update the source whenever the button is
4651
// clicked.
47-
formatElement.addEventListener("click", () => {
52+
document.getElementById("format").addEventListener("click", () => {
4853
editor.getDoc().setValue(ruby.format(editor.getValue()));
4954
});
50-
51-
// Finally, un-disable the tree element.
52-
treeElement.disabled = false;
53-
}
54-
55-
import("./CodeMirror").then(({ default: CodeMirror }) => {
56-
const newEditorElement = document.createElement("div");
57-
editorElement.replaceWith(newEditorElement);
58-
59-
editor = CodeMirror(newEditorElement, {
60-
lineNumbers: true,
61-
mode: "ruby",
62-
theme: "xq-light",
63-
value: editorElement.value
64-
});
65-
66-
if (ruby) {
67-
synchronize();
68-
}
69-
});
70-
71-
import("./createRuby").then(({ default: createRuby }) => createRuby()).then((created) => {
72-
ruby = created;
73-
74-
if (editor) {
75-
synchronize();
76-
}
7755
});

src/initialSource.ts

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)