Merge pull request #332 from tree-sitter/web-command
Add a `web-ui` command for interactively debugging parsers in the web browser
This commit is contained in:
commit
ca2033984c
11 changed files with 525 additions and 80 deletions
26
.travis.yml
26
.travis.yml
|
|
@ -5,30 +5,38 @@ rust:
|
|||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
env: USE_EMSCRIPTEN=1
|
||||
- os: linux
|
||||
services: docker
|
||||
env: TEST_WASM=1
|
||||
|
||||
before_install:
|
||||
# Install node
|
||||
- if [ -n "$TEST_WASM" ]; then nvm install 10 && nvm use 10; fi
|
||||
- nvm install 10
|
||||
- nvm use 10
|
||||
|
||||
# Download emscripten and create a shorthand for adding it to the PATH.
|
||||
# Don't add it to the path globally because it overrides the default
|
||||
# clang and node.
|
||||
- if [ -n "$USE_EMSCRIPTEN" ]; then export WASM_ENV="$(script/fetch-emscripten)"; fi
|
||||
|
||||
script:
|
||||
# Build the WASM binding
|
||||
- (eval "$WASM_ENV" && script/build-wasm)
|
||||
|
||||
# Build the CLI
|
||||
- cargo build --release
|
||||
|
||||
# Fetch and regenerate the fixture parsers
|
||||
- script/fetch-fixtures
|
||||
- cargo build --release
|
||||
- script/generate-fixtures
|
||||
- (eval "$WASM_ENV" && script/generate-fixtures-wasm)
|
||||
|
||||
# Run the tests
|
||||
- export TREE_SITTER_STATIC_ANALYSIS=1
|
||||
- script/test
|
||||
- script/test-wasm
|
||||
- script/benchmark
|
||||
|
||||
# Build and test the WASM binding
|
||||
- if [ -n "$TEST_WASM" ]; then script/build-wasm; fi
|
||||
- if [ -n "$TEST_WASM" ]; then script/generate-fixtures-wasm; fi
|
||||
- if [ -n "$TEST_WASM" ]; then script/test-wasm; fi
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
|
@ -56,4 +64,6 @@ deploy:
|
|||
cache:
|
||||
cargo: true
|
||||
directories:
|
||||
- target/emsdk
|
||||
- test/fixtures/grammars
|
||||
- /home/travis/.emscripten_cache
|
||||
|
|
|
|||
117
Cargo.lock
generated
117
Cargo.lock
generated
|
|
@ -33,6 +33,11 @@ dependencies = [
|
|||
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.11"
|
||||
|
|
@ -98,6 +103,21 @@ name = "cfg-if"
|
|||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chunked_transfer"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
|
|
@ -183,6 +203,16 @@ dependencies = [
|
|||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.0.2"
|
||||
|
|
@ -228,6 +258,11 @@ dependencies = [
|
|||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.1"
|
||||
|
|
@ -302,6 +337,11 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.24"
|
||||
|
|
@ -627,6 +667,28 @@ dependencies = [
|
|||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny_http"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ascii 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.3.9"
|
||||
|
|
@ -662,8 +724,10 @@ dependencies = [
|
|||
"smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tiny_http 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tree-sitter 0.3.9",
|
||||
"tree-sitter-highlight 0.1.5",
|
||||
"webbrowser 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -682,6 +746,22 @@ name = "ucd-util"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.5"
|
||||
|
|
@ -700,6 +780,16 @@ dependencies = [
|
|||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.2"
|
||||
|
|
@ -720,6 +810,20 @@ name = "void"
|
|||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "webbrowser"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
|
|
@ -744,6 +848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
|
||||
"checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc"
|
||||
"checksum ascii 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "97be891acc47ca214468e09425d02cef3af2c94d0d82081cd02061f996802f14"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727"
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
|
|
@ -753,6 +858,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "498d20a7aaf62625b9bf26e637cf7736417cde1d0c99f1d04d1170229a85cf87"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||
|
|
@ -763,6 +870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "64b7d419d0622ae02fe5da6b9a5e1964b610a65bb37923b976aeebb6dbb8f86e"
|
||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
|
|
@ -770,6 +878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
|
||||
|
|
@ -779,6 +888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37"
|
||||
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
||||
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
|
|
@ -818,14 +928,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum tiny_http 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1661fa0a44c95d01604bd05c66732a446c657efb62b5164a7a083a3b552b4951"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum webbrowser 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c01efd7cb6939b7f34983f1edff0550e5b21b49e2db4495656295922df8939ac"
|
||||
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ serde_derive = "1.0"
|
|||
regex-syntax = "0.6.4"
|
||||
regex = "1"
|
||||
rsass = "^0.9.8"
|
||||
tiny_http = "0.6"
|
||||
webbrowser = "0.5.1"
|
||||
|
||||
[dependencies.tree-sitter]
|
||||
version = ">= 0.3.7"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ pub mod properties;
|
|||
pub mod test;
|
||||
pub mod util;
|
||||
pub mod wasm;
|
||||
pub mod web_ui;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::path::Path;
|
|||
use std::process::exit;
|
||||
use std::{u64, usize};
|
||||
use tree_sitter_cli::{
|
||||
config, error, generate, highlight, loader, logger, parse, properties, test, wasm,
|
||||
config, error, generate, highlight, loader, logger, parse, properties, test, wasm, web_ui,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
|
|
@ -93,8 +93,16 @@ fn run() -> error::Result<()> {
|
|||
.subcommand(
|
||||
SubCommand::with_name("build-wasm")
|
||||
.about("Compile a parser to WASM")
|
||||
.arg(
|
||||
Arg::with_name("docker")
|
||||
.long("docker")
|
||||
.help("Run emscripten via docker even if it is installed locally"),
|
||||
)
|
||||
.arg(Arg::with_name("path").index(1).multiple(true)),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("web-ui").about("Test a parser interactively in the browser"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let home_dir = dirs::home_dir().expect("Failed to read home directory");
|
||||
|
|
@ -244,7 +252,9 @@ fn run() -> error::Result<()> {
|
|||
}
|
||||
} else if let Some(matches) = matches.subcommand_matches("build-wasm") {
|
||||
let grammar_path = current_dir.join(matches.value_of("path").unwrap_or(""));
|
||||
wasm::compile_language_to_wasm(&grammar_path)?;
|
||||
wasm::compile_language_to_wasm(&grammar_path, matches.is_present("docker"))?;
|
||||
} else if matches.subcommand_matches("web-ui").is_some() {
|
||||
web_ui::serve(¤t_dir);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@ use std::fs;
|
|||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn compile_language_to_wasm(language_dir: &Path) -> Result<()> {
|
||||
let src_dir = language_dir.join("src");
|
||||
|
||||
// Parse the grammar.json to find out the language name.
|
||||
pub fn get_grammar_name(src_dir: &Path) -> Result<String> {
|
||||
let grammar_json_path = src_dir.join("grammar.json");
|
||||
let grammar_json = fs::read_to_string(&grammar_json_path).map_err(|e| {
|
||||
format!(
|
||||
|
|
@ -22,28 +19,42 @@ pub fn compile_language_to_wasm(language_dir: &Path) -> Result<()> {
|
|||
grammar_json_path, e
|
||||
)
|
||||
})?;
|
||||
let output_filename = format!("tree-sitter-{}.wasm", grammar.name);
|
||||
Ok(grammar.name)
|
||||
}
|
||||
|
||||
// Get the current user id so that files created in the docker container will have
|
||||
// the same owner.
|
||||
let user_id_output = Command::new("id")
|
||||
.arg("-u")
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to get get current user id {}", e))?;
|
||||
let user_id = String::from_utf8_lossy(&user_id_output.stdout);
|
||||
let user_id = user_id.trim();
|
||||
pub fn compile_language_to_wasm(language_dir: &Path, force_docker: bool) -> Result<()> {
|
||||
let src_dir = language_dir.join("src");
|
||||
let grammar_name = get_grammar_name(&src_dir)?;
|
||||
let output_filename = format!("tree-sitter-{}.wasm", grammar_name);
|
||||
|
||||
// Use `emscripten-slim` docker image with the parser directory mounted as a volume.
|
||||
let mut command = Command::new("docker");
|
||||
let mut volume_string = OsString::from(language_dir);
|
||||
volume_string.push(":/src");
|
||||
command.args(&["run", "--rm"]);
|
||||
command.args(&[OsStr::new("--volume"), &volume_string]);
|
||||
command.args(&["--user", user_id, "trzeci/emscripten-slim"]);
|
||||
let mut command;
|
||||
if !force_docker && Command::new("emcc").output().is_ok() {
|
||||
command = Command::new("emcc");
|
||||
command.current_dir(&language_dir);
|
||||
} else {
|
||||
command = Command::new("docker");
|
||||
command.args(&["run", "--rm"]);
|
||||
|
||||
// Mount the parser directory as a volume
|
||||
let mut volume_string = OsString::from(language_dir);
|
||||
volume_string.push(":/src");
|
||||
command.args(&[OsStr::new("--volume"), &volume_string]);
|
||||
|
||||
// Get the current user id so that files created in the docker container will have
|
||||
// the same owner.
|
||||
let user_id_output = Command::new("id")
|
||||
.arg("-u")
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to get get current user id {}", e))?;
|
||||
let user_id = String::from_utf8_lossy(&user_id_output.stdout);
|
||||
let user_id = user_id.trim();
|
||||
command.args(&["--user", user_id]);
|
||||
|
||||
// Run `emcc` in a container using the `emscripten-slim` image
|
||||
command.args(&["trzeci/emscripten-slim", "emcc"]);
|
||||
}
|
||||
|
||||
// Run emscripten in the container
|
||||
command.args(&[
|
||||
"emcc",
|
||||
"-o",
|
||||
&output_filename,
|
||||
"-Os",
|
||||
|
|
@ -54,7 +65,7 @@ pub fn compile_language_to_wasm(language_dir: &Path) -> Result<()> {
|
|||
"-s",
|
||||
"TOTAL_MEMORY=33554432",
|
||||
"-s",
|
||||
&format!("EXPORTED_FUNCTIONS=[\"_tree_sitter_{}\"]", grammar.name),
|
||||
&format!("EXPORTED_FUNCTIONS=[\"_tree_sitter_{}\"]", grammar_name),
|
||||
"-fno-exceptions",
|
||||
"-I",
|
||||
"src",
|
||||
|
|
@ -86,7 +97,7 @@ pub fn compile_language_to_wasm(language_dir: &Path) -> Result<()> {
|
|||
|
||||
let output = command
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to run docker emcc command - {}", e))?;
|
||||
.map_err(|e| format!("Failed to run emcc command - {}", e))?;
|
||||
if !output.status.success() {
|
||||
return Err(Error::from(format!(
|
||||
"emcc command failed - {}",
|
||||
|
|
|
|||
128
cli/src/web_ui.html
Normal file
128
cli/src/web_ui.html
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
<head>
|
||||
<title>tree-sitter THE_LANGUAGE_NAME</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.45.0/codemirror.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/clusterize.js/0.18.0/clusterize.min.css">
|
||||
<link rel="icon" type="image/png" href="http://tree-sitter.github.io/tree-sitter/assets/images/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="http://tree-sitter.github.io/tree-sitter/assets/images/favicon-16x16.png" sizes="16x16" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="playground-container">
|
||||
<header>
|
||||
<div class=header-item>
|
||||
<bold>THE_LANGUAGE_NAME</bold>
|
||||
</div>
|
||||
|
||||
<div class=header-item>
|
||||
<label for="logging-checkbox">log</label>
|
||||
<input id="logging-checkbox" type="checkbox"></input>
|
||||
</div>
|
||||
|
||||
<div class=header-item>
|
||||
<label for="update-time">parse time: </label>
|
||||
<span id="update-time"></span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<select id="language-select" style="display: none;">
|
||||
<option value="parser">Parser</option>
|
||||
</select>
|
||||
|
||||
<textarea id="code-input"></textarea>
|
||||
|
||||
<div id="output-container-scroll">
|
||||
<pre id="output-container" class="highlight"></pre>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.3.1.min.js"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.45.0/codemirror.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/clusterize.js/0.18.0/clusterize.min.js"></script>
|
||||
|
||||
<script>LANGUAGE_BASE_URL = "";</script>
|
||||
<script src=tree-sitter.js></script>
|
||||
<script src=playground.js></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font: Sans Serif;
|
||||
}
|
||||
|
||||
#playground-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
padding: 20px;
|
||||
height: 60px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.header-item {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
border-right: 1px solid #aaa;
|
||||
}
|
||||
|
||||
#output-container-scroll {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#output-container {
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#logging-checkbox {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
border-left: 3px solid red;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #040404;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.highlighted {
|
||||
background-color: #d9d9d9;
|
||||
color: red;
|
||||
border-radius: 3px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
93
cli/src/web_ui.rs
Normal file
93
cli/src/web_ui.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use super::wasm;
|
||||
use std::fs;
|
||||
use std::net::TcpListener;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use tiny_http::{Header, Response, Server};
|
||||
use webbrowser;
|
||||
|
||||
const HTML: &'static str = include_str!("./web_ui.html");
|
||||
const PLAYGROUND_JS: &'static [u8] = include_bytes!("../../docs/assets/js/playground.js");
|
||||
|
||||
#[cfg(unix)]
|
||||
const LIB_JS: &'static [u8] = include_bytes!("../../lib/binding_web/tree-sitter.js");
|
||||
#[cfg(unix)]
|
||||
const LIB_WASM: &'static [u8] = include_bytes!("../../lib/binding_web/tree-sitter.wasm");
|
||||
|
||||
#[cfg(windows)]
|
||||
const LIB_JS: &'static [u8] = &[];
|
||||
#[cfg(windows)]
|
||||
const LIB_WASM: &'static [u8] = &[];
|
||||
|
||||
pub fn serve(grammar_path: &Path) {
|
||||
let port = get_available_port().expect("Couldn't find an available port");
|
||||
let url = format!("127.0.0.1:{}", port);
|
||||
let server = Server::http(&url).expect("Failed to start web server");
|
||||
let grammar_name = wasm::get_grammar_name(&grammar_path.join("src"))
|
||||
.map_err(|e| format!("Failed to get wasm filename: {:?}", e))
|
||||
.unwrap();
|
||||
let wasm_filename = format!("tree-sitter-{}.wasm", grammar_name);
|
||||
let language_wasm = fs::read(grammar_path.join(&wasm_filename))
|
||||
.map_err(|_| {
|
||||
format!(
|
||||
"Failed to read '{}'. Run `tree-sitter build-wasm` first.",
|
||||
wasm_filename
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
webbrowser::open(&format!("http://127.0.0.1:{}", port))
|
||||
.map_err(|e| format!("Failed to open '{}' in a web browser. Error: {}", url, e))
|
||||
.unwrap();
|
||||
|
||||
let html = HTML
|
||||
.replace("THE_LANGUAGE_NAME", &grammar_name)
|
||||
.into_bytes();
|
||||
let html_header = Header::from_str("Content-type: text/html").unwrap();
|
||||
let js_header = Header::from_str("Content-type: application/javascript").unwrap();
|
||||
let wasm_header = Header::from_str("Content-type: application/wasm").unwrap();
|
||||
|
||||
for request in server.incoming_requests() {
|
||||
let res = match request.url() {
|
||||
"/" => response(&html, &html_header),
|
||||
"/playground.js" => response(PLAYGROUND_JS, &js_header),
|
||||
"/tree-sitter-parser.wasm" => response(&language_wasm, &wasm_header),
|
||||
"/tree-sitter.js" => {
|
||||
if cfg!(windows) {
|
||||
redirect("https://tree-sitter.github.io/tree-sitter.js")
|
||||
} else {
|
||||
response(LIB_JS, &js_header)
|
||||
}
|
||||
}
|
||||
"/tree-sitter.wasm" => {
|
||||
if cfg!(windows) {
|
||||
redirect("https://tree-sitter.github.io/tree-sitter.wasm")
|
||||
} else {
|
||||
response(LIB_WASM, &js_header)
|
||||
}
|
||||
}
|
||||
_ => response(b"Not found", &html_header).with_status_code(404),
|
||||
};
|
||||
request.respond(res).expect("Failed to write HTTP response");
|
||||
}
|
||||
}
|
||||
|
||||
fn redirect<'a>(url: &'a str) -> Response<&'a [u8]> {
|
||||
Response::empty(302)
|
||||
.with_data("".as_bytes(), Some(0))
|
||||
.with_header(Header::from_bytes("Location", url.as_bytes()).unwrap())
|
||||
}
|
||||
|
||||
fn response<'a>(data: &'a [u8], header: &Header) -> Response<&'a [u8]> {
|
||||
Response::empty(200)
|
||||
.with_data(data, Some(data.len()))
|
||||
.with_header(header.clone())
|
||||
}
|
||||
|
||||
fn get_available_port() -> Option<u16> {
|
||||
(8000..12000).find(port_is_available)
|
||||
}
|
||||
|
||||
fn port_is_available(port: &u16) -> bool {
|
||||
TcpListener::bind(("127.0.0.1", *port)).is_ok()
|
||||
}
|
||||
|
|
@ -11,10 +11,7 @@ let tree;
|
|||
const demoContainer = document.getElementById('playground-container');
|
||||
const languagesByName = {};
|
||||
|
||||
await Promise.all([
|
||||
codeInput.value = await fetch(scriptURL).then(r => r.text()),
|
||||
TreeSitter.init()
|
||||
]);
|
||||
await TreeSitter.init();
|
||||
|
||||
const parser = new TreeSitter();
|
||||
const codeEditor = CodeMirror.fromTextArea(codeInput, {
|
||||
|
|
@ -182,11 +179,13 @@ let tree;
|
|||
const node = tree.rootNode.namedDescendantForPosition(start, end);
|
||||
if (treeRows) {
|
||||
if (treeRowHighlightedIndex !== -1) {
|
||||
treeRows[treeRowHighlightedIndex] = treeRows[treeRowHighlightedIndex].replace('highlighted', 'plain');
|
||||
const row = treeRows[treeRowHighlightedIndex];
|
||||
if (row) treeRows[treeRowHighlightedIndex] = row.replace('highlighted', 'plain');
|
||||
}
|
||||
treeRowHighlightedIndex = treeRows.findIndex(row => row.includes(`data-id=${node.id}`));
|
||||
if (treeRowHighlightedIndex !== -1) {
|
||||
treeRows[treeRowHighlightedIndex] = treeRows[treeRowHighlightedIndex].replace('plain', 'highlighted');
|
||||
const row = treeRows[treeRowHighlightedIndex];
|
||||
if (row) treeRows[treeRowHighlightedIndex] = row.replace('plain', 'highlighted');
|
||||
}
|
||||
cluster.update(treeRows);
|
||||
const lineHeight = cluster.options.item_height;
|
||||
|
|
@ -220,7 +219,13 @@ let tree;
|
|||
|
||||
function handleLoggingChange() {
|
||||
if (loggingCheckbox.checked) {
|
||||
parser.setLogger(console.log);
|
||||
parser.setLogger((message, lexing) => {
|
||||
if (lexing) {
|
||||
console.log(" ", message)
|
||||
} else {
|
||||
console.log(message)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
parser.setLogger(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
usage() {
|
||||
cat <<EOF
|
||||
USAGE
|
||||
|
||||
$0 [--debug]
|
||||
$0 [--help] [--debug] [--docker]
|
||||
|
||||
SUMMARY
|
||||
|
||||
|
|
@ -15,57 +13,97 @@ SUMMARY
|
|||
|
||||
REQUIREMENTS
|
||||
|
||||
You must have the \`docker\` command on your PATH for this to work.
|
||||
You must have either the \`emcc\` command or the \`docker\` command
|
||||
on your PATH for this to work.
|
||||
|
||||
OPTIONS
|
||||
|
||||
--debug: Compile the library more quickly, with fewer optimizations and more runtime assertions.
|
||||
--help: Display this message.
|
||||
--debug: Compile the library more quickly, with fewer optimizations
|
||||
and more runtime assertions.
|
||||
--docker: Run emscripten using docker, even if \`emcc\` is installed.
|
||||
By default, \`emcc\` will be run directly when available.
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
web_dir=lib/binding_web
|
||||
exports=$(cat ${web_dir}/exports.json)
|
||||
args="-Os"
|
||||
minify=1
|
||||
emscripten_flags="-Os"
|
||||
minify_js=1
|
||||
force_docker=0
|
||||
|
||||
if [[ "$1" == "--debug" ]]; then
|
||||
minify=0
|
||||
args="-s ASSERTIONS=1 -s SAFE_HEAP=1 -Os"
|
||||
while [[ $# > 0 ]]; do
|
||||
case "$1" in
|
||||
--debug)
|
||||
minify_js=0
|
||||
emscripten_flags="-s ASSERTIONS=1 -s SAFE_HEAP=1 -Os"
|
||||
;;
|
||||
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--docker)
|
||||
force_docker=1
|
||||
;;
|
||||
|
||||
*)
|
||||
usage
|
||||
echo "Unrecognized argument '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
emcc=
|
||||
if which emcc > /dev/null && [[ "$force_docker" == "0" ]]; then
|
||||
export EMCC_FORCE_STDLIBS=libc++
|
||||
emcc=emcc
|
||||
elif which docker > /dev/null; then
|
||||
emcc="docker run \
|
||||
--rm \
|
||||
-v $(pwd):/src \
|
||||
-u $(id -u) \
|
||||
-e EMCC_FORCE_STDLIBS=libc++ \
|
||||
trzeci/emscripten-slim \
|
||||
emcc"
|
||||
else
|
||||
echo 'You must have either `docker` or `emcc` on your PATH to run this script'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p target/scratch
|
||||
|
||||
docker run \
|
||||
--rm \
|
||||
-v $(pwd):/src \
|
||||
-u $(id -u) \
|
||||
-e EMCC_FORCE_STDLIBS=libc++ \
|
||||
trzeci/emscripten-slim \
|
||||
\
|
||||
emcc \
|
||||
-s WASM=1 \
|
||||
-s TOTAL_MEMORY=33554432 \
|
||||
-s ALLOW_MEMORY_GROWTH \
|
||||
-s MAIN_MODULE=2 \
|
||||
-s NO_FILESYSTEM=1 \
|
||||
# Use emscripten to generate `tree-sitter.js` and `tree-sitter.wasm`
|
||||
# in the `target/scratch` directory
|
||||
$emcc \
|
||||
-s WASM=1 \
|
||||
-s TOTAL_MEMORY=33554432 \
|
||||
-s ALLOW_MEMORY_GROWTH \
|
||||
-s MAIN_MODULE=2 \
|
||||
-s NO_FILESYSTEM=1 \
|
||||
-s "EXPORTED_FUNCTIONS=${exports}" \
|
||||
$args \
|
||||
-std=c99 \
|
||||
-D 'fprintf(...)=' \
|
||||
-I lib/src \
|
||||
-I lib/include \
|
||||
-I lib/utf8proc \
|
||||
--js-library ${web_dir}/imports.js \
|
||||
--pre-js ${web_dir}/prefix.js \
|
||||
--post-js ${web_dir}/binding.js \
|
||||
lib/src/lib.c \
|
||||
${web_dir}/binding.c \
|
||||
$emscripten_flags \
|
||||
-std=c99 \
|
||||
-D 'fprintf(...)=' \
|
||||
-I lib/src \
|
||||
-I lib/include \
|
||||
-I lib/utf8proc \
|
||||
--js-library ${web_dir}/imports.js \
|
||||
--pre-js ${web_dir}/prefix.js \
|
||||
--post-js ${web_dir}/binding.js \
|
||||
lib/src/lib.c \
|
||||
${web_dir}/binding.c \
|
||||
-o target/scratch/tree-sitter.js
|
||||
|
||||
|
||||
if [[ "$minify" == "1" ]]; then
|
||||
# Use terser to write a minified version of `tree-sitter.js` into
|
||||
# the `lib/binding_web` directory.
|
||||
if [[ "$minify_js" == "1" ]]; then
|
||||
if [ ! -d ${web_dir}/node_modules/terser ]; then
|
||||
(
|
||||
cd ${web_dir}
|
||||
|
|
|
|||
30
script/fetch-emscripten
Executable file
30
script/fetch-emscripten
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p target
|
||||
EMSDK_DIR="./target/emsdk"
|
||||
|
||||
(
|
||||
if [ ! -f "$EMSDK_DIR/emsdk" ]; then
|
||||
echo 'Downloading emscripten SDK...'
|
||||
git clone https://github.com/emscripten-core/emsdk.git $EMSDK_DIR
|
||||
fi
|
||||
|
||||
cd $EMSDK_DIR
|
||||
|
||||
echo 'Updating emscripten SDK...'
|
||||
git pull
|
||||
./emsdk list
|
||||
|
||||
echo 'Installing latest emscripten...'
|
||||
./emsdk install latest
|
||||
|
||||
echo 'Activating latest emscripten...'
|
||||
./emsdk activate latest
|
||||
) >&2
|
||||
|
||||
(
|
||||
source "$EMSDK_DIR/emsdk_env.sh" > /dev/null
|
||||
declare -px
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue