mirror of
https://github.com/Dummi26/mers.git
synced 2025-12-24 15:36:33 +01:00
- changed the list type from [t] to [t ...]
- added more examples to the readme
This commit is contained in:
495
mers/Cargo.lock
generated
495
mers/Cargo.lock
generated
@@ -11,6 +11,197 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "edit"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c562aa71f7bc691fde4c6bf5f93ae5a5298b617c2eb44c76c87832299a17fbb4"
|
||||
dependencies = [
|
||||
"tempfile",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue-sys"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
@@ -21,7 +212,64 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
name = "mers"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"edit",
|
||||
"notify",
|
||||
"regex",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -40,3 +288,250 @@ name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
|
||||
dependencies = [
|
||||
"either",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
@@ -10,4 +10,7 @@ name = "mers"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
edit = "0.1.4"
|
||||
notify = "5.1.0"
|
||||
regex = "1.7.2"
|
||||
static_assertions = "1.1.0"
|
||||
|
||||
176
mers/src/main.rs
176
mers/src/main.rs
@@ -1,24 +1,172 @@
|
||||
use std::time::Instant;
|
||||
use std::{
|
||||
fs,
|
||||
sync::{Arc, Mutex},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use notify::Watcher as FsWatcher;
|
||||
|
||||
pub mod libs;
|
||||
pub mod parse;
|
||||
pub mod script;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
let path = std::env::args().nth(1).unwrap();
|
||||
let script = parse::parse::parse(&mut if path.trim() == "-e" {
|
||||
parse::file::File::new(
|
||||
std::env::args()
|
||||
.skip(2)
|
||||
.map(|mut v| {
|
||||
v.push('\n');
|
||||
v
|
||||
})
|
||||
.collect::<String>(),
|
||||
path.into(),
|
||||
)
|
||||
} else {
|
||||
parse::file::File::new(std::fs::read_to_string(&path).unwrap(), path.into())
|
||||
let script = parse::parse::parse(&mut match args.len() {
|
||||
0 => {
|
||||
println!("Please provide some arguments, such as the path to a file or \"-e <code>\".");
|
||||
std::process::exit(100);
|
||||
}
|
||||
_ => {
|
||||
if args[0].trim_start().starts_with("-") {
|
||||
let mut execute = false;
|
||||
let mut verbose = 0;
|
||||
let mut interactive = 0;
|
||||
let mut interactive_use_new_terminal = false;
|
||||
let mut prev_char = None;
|
||||
let mut advanced = false;
|
||||
for ch in args[0][1..].chars() {
|
||||
if !advanced {
|
||||
if ch == '+' {
|
||||
advanced = true;
|
||||
continue;
|
||||
}
|
||||
match ch {
|
||||
'e' => execute = true,
|
||||
'v' => verbose += 1,
|
||||
'i' => interactive += 1,
|
||||
ch => {
|
||||
eprintln!("Ignoring -{ch}. (unknown char)");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prev_char = Some(ch);
|
||||
} else {
|
||||
if let Some(prev_char) = prev_char {
|
||||
match prev_char {
|
||||
'i' => {
|
||||
match ch {
|
||||
't' => interactive_use_new_terminal = true,
|
||||
_ => eprintln!("Ignoring i+{ch}. (unknown adv char)"),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
eprintln!("Ignoring advanced args because there was no previous argument.");
|
||||
}
|
||||
advanced = false;
|
||||
}
|
||||
}
|
||||
if verbose != 0 {
|
||||
eprintln!("info: set verbosity level to {verbose}. this doesn't do anything yet. [TODO!]");
|
||||
}
|
||||
if interactive >= 0 {
|
||||
let (contents, path) = match interactive {
|
||||
1 => {
|
||||
// basic: open file and watch for fs changes
|
||||
let temp_file_edit = edit::Builder::new().suffix(".mers").tempfile().unwrap();
|
||||
let temp_file = temp_file_edit.path();
|
||||
eprintln!("Using temporary file at {temp_file:?}. Save the file to update the output here.");
|
||||
if let Ok(_) = std::fs::write(&temp_file, []) {
|
||||
if let Ok(mut watcher) = {
|
||||
let temp_file = temp_file.to_path_buf();
|
||||
// the file watcher
|
||||
notify::recommended_watcher(move |event: Result<notify::Event, notify::Error>| {
|
||||
if let Ok(event) = event {
|
||||
match &event.kind {
|
||||
notify::EventKind::Modify(notify::event::ModifyKind::Data(_)) => {
|
||||
if let Ok(file_contents) = fs::read_to_string(&temp_file) {
|
||||
let mut file = parse::file::File::new(file_contents, temp_file.clone());
|
||||
static_assertions::const_assert_eq!(parse::parse::PARSE_VERSION, 0);
|
||||
let mut ginfo = script::block::to_runnable::GInfo::default();
|
||||
let libs = parse::parse::parse_step_lib_paths(&mut file);
|
||||
match parse::parse::parse_step_interpret(&mut file) {
|
||||
Ok(func) => {
|
||||
let libs = parse::parse::parse_step_libs_load(libs, &mut ginfo);
|
||||
ginfo.libs = Arc::new(libs);
|
||||
match parse::parse::parse_step_compile(func, &mut ginfo) {
|
||||
Ok(func) => {
|
||||
println!();
|
||||
println!(" - - - - -");
|
||||
let output = func.run(vec![]);
|
||||
println!(" - - - - -");
|
||||
println!("{}", output);
|
||||
}
|
||||
Err(e) => eprintln!("Couldn't compile:\n{e:?}"),
|
||||
}
|
||||
}
|
||||
Err(e) =>eprintln!("Couldn't interpret:\n{e:?}"),
|
||||
}
|
||||
} else {
|
||||
println!("can't read file at {:?}!", temp_file);
|
||||
std::process::exit(105);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
})} {
|
||||
if let Ok(_) = watcher.watch(&temp_file, notify::RecursiveMode::NonRecursive) {
|
||||
if interactive_use_new_terminal {
|
||||
if let Ok(term) = std::env::var("TERM") {
|
||||
let editor = edit::get_editor().unwrap();
|
||||
eprintln!("launching \"{term} -e {editor:?} {temp_file:?}...");
|
||||
std::process::Command::new(term)
|
||||
.arg("-e")
|
||||
.arg(&editor)
|
||||
.arg(temp_file)
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait()
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
edit::edit_file(temp_file_edit.path()).unwrap();
|
||||
}
|
||||
temp_file_edit.close().unwrap();
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
println!("Cannot watch the file at \"{:?}\" for hot-reload.", temp_file);
|
||||
std::process::exit(104);
|
||||
}
|
||||
} else {
|
||||
println!("Cannot use filesystem watcher for hot-reload.");
|
||||
// TODO: don't exit here?
|
||||
std::process::exit(103);
|
||||
}
|
||||
} else {
|
||||
println!("could not write file \"{:?}\".", temp_file);
|
||||
std::process::exit(102);
|
||||
}
|
||||
}
|
||||
_ => (String::new(), String::new()),
|
||||
};
|
||||
parse::file::File::new(
|
||||
contents,
|
||||
path.into()
|
||||
)
|
||||
}
|
||||
else if execute {
|
||||
parse::file::File::new(
|
||||
args.iter().skip(1).fold(String::new(), |mut s, v| {
|
||||
if !s.is_empty() {
|
||||
s.push(' ');
|
||||
}
|
||||
s.push_str(v);
|
||||
s
|
||||
}),
|
||||
path.into(),
|
||||
)
|
||||
} else {
|
||||
println!("please provide either a file or -e and a script to run!");
|
||||
std::process::exit(101);
|
||||
}
|
||||
} else {
|
||||
parse::file::File::new(std::fs::read_to_string(&args[0]).unwrap(), path.into())
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
println!(" - - - - -");
|
||||
|
||||
@@ -33,9 +33,31 @@ impl From<ToRunnableError> for ScriptError {
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {}
|
||||
|
||||
pub const PARSE_VERSION: u64 = 0;
|
||||
|
||||
/// executes the 4 parse_steps in order: lib_paths => interpret => libs_load => compile
|
||||
pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||
let mut ginfo = GInfo::default();
|
||||
let libs = parse_step_lib_paths(file);
|
||||
let func = parse_step_interpret(file)?;
|
||||
ginfo.libs = Arc::new(parse_step_libs_load(libs, &mut ginfo));
|
||||
|
||||
eprintln!();
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func}");
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func:#?}");
|
||||
|
||||
let run = parse_step_compile(func, &mut ginfo)?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Runnable: {run:#?}");
|
||||
|
||||
Ok(run)
|
||||
}
|
||||
|
||||
pub fn parse_step_lib_paths(file: &mut File) -> Vec<Command> {
|
||||
let mut libs = vec![];
|
||||
let mut enum_variants = GInfo::default_enum_variants();
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
let pos = file.get_pos().clone();
|
||||
@@ -49,37 +71,43 @@ pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||
if let Some(parent) = path_to_executable.parent() {
|
||||
cmd.current_dir(parent.clone());
|
||||
}
|
||||
match libs::Lib::launch(cmd, &mut enum_variants) {
|
||||
Ok(lib) => {
|
||||
libs.push(lib);
|
||||
eprintln!("Loaded library!");
|
||||
}
|
||||
Err(e) => panic!(
|
||||
"Unable to load library at {}: {e:?}",
|
||||
path_to_executable.to_string_lossy().as_ref(),
|
||||
),
|
||||
}
|
||||
libs.push(cmd);
|
||||
} else {
|
||||
file.set_pos(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let func = SFunction::new(
|
||||
libs
|
||||
}
|
||||
|
||||
pub fn parse_step_interpret(file: &mut File) -> Result<SFunction, ParseError> {
|
||||
Ok(SFunction::new(
|
||||
vec![(
|
||||
"args".to_string(),
|
||||
VSingleType::List(VSingleType::String.into()).into(),
|
||||
)],
|
||||
parse_block_advanced(file, Some(false), true, true, false)?,
|
||||
);
|
||||
eprintln!();
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func}");
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func:#?}");
|
||||
let run = to_runnable::to_runnable(func, GInfo::new(Arc::new(libs), enum_variants))?;
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Runnable: {run:#?}");
|
||||
Ok(run)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_step_libs_load(lib_cmds: Vec<Command>, ginfo: &mut GInfo) -> Vec<libs::Lib> {
|
||||
let mut libs = vec![];
|
||||
for cmd in lib_cmds {
|
||||
match libs::Lib::launch(cmd, &mut ginfo.enum_variants) {
|
||||
Ok(lib) => {
|
||||
libs.push(lib);
|
||||
}
|
||||
Err(e) => eprintln!("!! Unable to load library: {e:?} !!",),
|
||||
}
|
||||
}
|
||||
libs
|
||||
}
|
||||
|
||||
pub fn parse_step_compile(
|
||||
main_func: SFunction,
|
||||
ginfo: &mut GInfo,
|
||||
) -> Result<RScript, ToRunnableError> {
|
||||
to_runnable::to_runnable(main_func, ginfo)
|
||||
}
|
||||
|
||||
fn parse_block(file: &mut File) -> Result<SBlock, ParseError> {
|
||||
@@ -503,8 +531,17 @@ fn parse_single_type_adv(
|
||||
// Tuple or Array
|
||||
Some('[') => {
|
||||
let mut types = vec![];
|
||||
let mut list = false;
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
if file[file.get_char_index()..].starts_with("...]") {
|
||||
list = true;
|
||||
file.next();
|
||||
file.next();
|
||||
file.next();
|
||||
file.next();
|
||||
break;
|
||||
}
|
||||
match file.peek() {
|
||||
Some(']') => {
|
||||
file.next();
|
||||
@@ -521,7 +558,7 @@ fn parse_single_type_adv(
|
||||
file.next();
|
||||
}
|
||||
}
|
||||
if types.len() == 1 {
|
||||
if list {
|
||||
VSingleType::List(types.pop().unwrap())
|
||||
} else {
|
||||
VSingleType::Tuple(types)
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::{
|
||||
|
||||
use crate::libs;
|
||||
|
||||
use self::to_runnable::{ToRunnableError, GInfo};
|
||||
use self::to_runnable::{GInfo, ToRunnableError};
|
||||
|
||||
use super::{
|
||||
builtins::BuiltinFunction,
|
||||
@@ -94,10 +94,14 @@ pub mod to_runnable {
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{script::{
|
||||
val_data::VDataEnum,
|
||||
val_type::{VSingleType, VType}, builtins,
|
||||
}, libs};
|
||||
use crate::{
|
||||
libs,
|
||||
script::{
|
||||
builtins,
|
||||
val_data::VDataEnum,
|
||||
val_type::{VSingleType, VType},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
BuiltinFunction, RBlock, RFunction, RScript, RStatement, RStatementEnum, SBlock, SFunction,
|
||||
@@ -150,13 +154,27 @@ pub mod to_runnable {
|
||||
// Global, shared between all
|
||||
pub struct GInfo {
|
||||
vars: usize,
|
||||
libs: Arc<Vec<libs::Lib>>,
|
||||
lib_fns: HashMap<String, (usize, usize)>,
|
||||
enum_variants: HashMap<String, usize>,
|
||||
pub libs: Arc<Vec<libs::Lib>>,
|
||||
pub lib_fns: HashMap<String, (usize, usize)>,
|
||||
pub enum_variants: HashMap<String, usize>,
|
||||
}
|
||||
impl Default for GInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
vars: 0,
|
||||
libs: Arc::new(vec![]),
|
||||
lib_fns: HashMap::new(),
|
||||
enum_variants: Self::default_enum_variants(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl GInfo {
|
||||
pub fn default_enum_variants() -> HashMap<String, usize> {
|
||||
builtins::EVS.iter().enumerate().map(|(i, v)| (v.to_string(), i)).collect()
|
||||
builtins::EVS
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| (v.to_string(), i))
|
||||
.collect()
|
||||
}
|
||||
pub fn new(libs: Arc<Vec<libs::Lib>>, enum_variants: HashMap<String, usize>) -> Self {
|
||||
let mut lib_fns = HashMap::new();
|
||||
@@ -165,7 +183,12 @@ pub mod to_runnable {
|
||||
lib_fns.insert(name.to_string(), (libid, fnid));
|
||||
}
|
||||
}
|
||||
Self { vars: 0, libs, lib_fns, enum_variants }
|
||||
Self {
|
||||
vars: 0,
|
||||
libs,
|
||||
lib_fns,
|
||||
enum_variants,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Local, used to keep local variables separated
|
||||
@@ -175,24 +198,27 @@ pub mod to_runnable {
|
||||
fns: HashMap<String, Arc<RFunction>>,
|
||||
}
|
||||
|
||||
pub fn to_runnable(s: SFunction, mut ginfo: GInfo) -> Result<RScript, ToRunnableError> {
|
||||
pub fn to_runnable(s: SFunction, ginfo: &mut GInfo) -> Result<RScript, ToRunnableError> {
|
||||
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
|
||||
return Err(ToRunnableError::MainWrongInput);
|
||||
}
|
||||
assert_eq!(s.inputs[0].1,VType {
|
||||
types: vec![VSingleType::List(VType {
|
||||
types: vec![VSingleType::String],
|
||||
})],
|
||||
});
|
||||
assert_eq!(
|
||||
s.inputs[0].1,
|
||||
VType {
|
||||
types: vec![VSingleType::List(VType {
|
||||
types: vec![VSingleType::String],
|
||||
})],
|
||||
}
|
||||
);
|
||||
let func = function(
|
||||
&s,
|
||||
&mut ginfo,
|
||||
ginfo,
|
||||
LInfo {
|
||||
vars: HashMap::new(),
|
||||
fns: HashMap::new(),
|
||||
},
|
||||
)?;
|
||||
Ok(RScript::new(func, ginfo.vars, ginfo.libs)?)
|
||||
Ok(RScript::new(func, ginfo.vars, ginfo.libs.clone())?)
|
||||
}
|
||||
|
||||
// go over every possible known-type input for the given function, returning all possible RFunctions.
|
||||
@@ -276,21 +302,24 @@ pub mod to_runnable {
|
||||
for t in v {
|
||||
stypes(t, ginfo);
|
||||
}
|
||||
},
|
||||
VSingleType::EnumVariantS(e, v) => *t = VSingleType::EnumVariant({
|
||||
if let Some(v) = ginfo.enum_variants.get(e) {
|
||||
*v
|
||||
} else {
|
||||
let v = ginfo.enum_variants.len();
|
||||
ginfo.enum_variants.insert(e.clone(), v);
|
||||
v
|
||||
}
|
||||
},
|
||||
{
|
||||
stypes(v, ginfo);
|
||||
v.clone()
|
||||
}
|
||||
),
|
||||
VSingleType::EnumVariantS(e, v) => {
|
||||
*t = VSingleType::EnumVariant(
|
||||
{
|
||||
if let Some(v) = ginfo.enum_variants.get(e) {
|
||||
*v
|
||||
} else {
|
||||
let v = ginfo.enum_variants.len();
|
||||
ginfo.enum_variants.insert(e.clone(), v);
|
||||
v
|
||||
}
|
||||
},
|
||||
{
|
||||
stypes(v, ginfo);
|
||||
v.clone()
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -533,7 +562,6 @@ pub mod to_runnable {
|
||||
} else {
|
||||
eprintln!("WARN: Match condition with return type {} never returns a match and will be ignored entirely. Note: this also skips type-checking for the action part of this match arm because the success type is not known.", case_condition_out);
|
||||
}
|
||||
|
||||
}
|
||||
linfo.vars.get_mut(match_on).unwrap().1 = og_type;
|
||||
|
||||
@@ -721,7 +749,7 @@ pub enum RStatementEnum {
|
||||
Switch(RStatement, Vec<(VType, RStatement)>),
|
||||
Match(usize, Vec<(RStatement, RStatement)>),
|
||||
IndexFixed(RStatement, usize),
|
||||
EnumVariant(usize, RStatement)
|
||||
EnumVariant(usize, RStatement),
|
||||
}
|
||||
impl RStatementEnum {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||
@@ -758,7 +786,9 @@ impl RStatementEnum {
|
||||
func.run(vars, libs)
|
||||
}
|
||||
Self::BuiltinFunction(v, args) => v.run(args, vars, libs),
|
||||
Self::LibFunction(libid, fnid, args, _) => libs[*libid].run_fn(*fnid, &args.iter().map(|arg| arg.run(vars, libs)).collect()),
|
||||
Self::LibFunction(libid, fnid, args, _) => {
|
||||
libs[*libid].run_fn(*fnid, &args.iter().map(|arg| arg.run(vars, libs)).collect())
|
||||
}
|
||||
Self::Block(b) => b.run(vars, libs),
|
||||
Self::If(c, t, e) => {
|
||||
if let VDataEnum::Bool(v) = c.run(vars, libs).data {
|
||||
@@ -802,7 +832,10 @@ impl RStatementEnum {
|
||||
}
|
||||
VDataEnum::String(v) => {
|
||||
for ch in v.chars() {
|
||||
if let Some(v) = in_loop(VDataEnum::String(ch.to_string()).to()).data.matches() {
|
||||
if let Some(v) = in_loop(VDataEnum::String(ch.to_string()).to())
|
||||
.data
|
||||
.matches()
|
||||
{
|
||||
oval = v;
|
||||
break;
|
||||
}
|
||||
@@ -836,9 +869,7 @@ impl RStatementEnum {
|
||||
for (case_condition, case_action) in cases {
|
||||
// [t] => Some(t), t => Some(t), [] | false => None
|
||||
if let Some(v) = case_condition.run(vars, libs).data.matches() {
|
||||
let og = {
|
||||
std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v)
|
||||
};
|
||||
let og = { std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v) };
|
||||
let res = case_action.run(vars, libs);
|
||||
*vars[*match_on].lock().unwrap() = og;
|
||||
break 'm res;
|
||||
@@ -847,9 +878,7 @@ impl RStatementEnum {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
Self::IndexFixed(st, i) => st.run(vars, libs).get(*i).unwrap(),
|
||||
Self::EnumVariant(e, v) => {
|
||||
VDataEnum::EnumVariant(*e, Box::new(v.run(vars, libs))).to()
|
||||
}
|
||||
Self::EnumVariant(e, v) => VDataEnum::EnumVariant(*e, Box::new(v.run(vars, libs))).to(),
|
||||
}
|
||||
}
|
||||
pub fn out(&self) -> VType {
|
||||
@@ -887,12 +916,8 @@ impl RStatementEnum {
|
||||
a.out() | VSingleType::Tuple(vec![]).to()
|
||||
}
|
||||
}
|
||||
Self::While(c) => {
|
||||
c.out().matches().1
|
||||
}
|
||||
Self::For(_, _, b) => {
|
||||
VSingleType::Tuple(vec![]).to() | b.out().matches().1
|
||||
}
|
||||
Self::While(c) => c.out().matches().1,
|
||||
Self::For(_, _, b) => VSingleType::Tuple(vec![]).to() | b.out().matches().1,
|
||||
Self::BuiltinFunction(f, args) => f.returns(args.iter().map(|rs| rs.out()).collect()),
|
||||
Self::Switch(switch_on, cases) => {
|
||||
let switch_on = switch_on.out().types;
|
||||
@@ -941,7 +966,11 @@ pub struct RScript {
|
||||
libs: Arc<Vec<libs::Lib>>,
|
||||
}
|
||||
impl RScript {
|
||||
fn new(main: RFunction, vars: usize, libs: Arc<Vec<libs::Lib>>) -> Result<Self, ToRunnableError> {
|
||||
fn new(
|
||||
main: RFunction,
|
||||
vars: usize,
|
||||
libs: Arc<Vec<libs::Lib>>,
|
||||
) -> Result<Self, ToRunnableError> {
|
||||
if main.inputs.len() != 1 {
|
||||
return Err(ToRunnableError::MainWrongInput);
|
||||
}
|
||||
@@ -1016,7 +1045,7 @@ impl Display for VSingleType {
|
||||
write!(f, "]")?;
|
||||
Ok(())
|
||||
}
|
||||
Self::List(t) => write!(f, "[{t}]"),
|
||||
Self::List(t) => write!(f, "[{t} ...]"),
|
||||
Self::Function(_) => write!(f, "FUNCTION"),
|
||||
Self::Thread(_) => write!(f, "THREAD"),
|
||||
Self::Reference(r) => write!(f, "&{r}"),
|
||||
|
||||
@@ -354,7 +354,16 @@ impl BuiltinFunction {
|
||||
}
|
||||
}
|
||||
// TODO! finish this
|
||||
_ => true,
|
||||
Self::Pop | Self::Remove | Self::Get | Self::Len | Self::Substring => true,
|
||||
Self::Contains | Self::StartsWith | Self::EndsWith | Self::Regex => {
|
||||
input.len() == 2
|
||||
&& input
|
||||
.iter()
|
||||
.all(|v| v.fits_in(&VSingleType::String.to()).is_empty())
|
||||
}
|
||||
Self::Trim => {
|
||||
input.len() == 1 && input[0].fits_in(&VSingleType::String.to()).is_empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// for invalid inputs, may panic
|
||||
|
||||
Reference in New Issue
Block a user