init
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# ---> Zig
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
54
build.zig
Normal file
54
build.zig
Normal file
@@ -0,0 +1,54 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const mod = b.addModule("pandas_markdown", .{
|
||||
.root_source_file = b.path("src/root.zig"),
|
||||
.test_runner = .{ .path = b.path("tests/test_runner.zig"), .mode = .simple },
|
||||
.target = target,
|
||||
});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "pandas_markdown",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.test_runner = .{ .path = b.path("tests/test_runner.zig"), .mode = .simple },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.imports = &.{
|
||||
.{ .name = "pandas_markdown", .module = mod },
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const mod_tests = b.addTest(.{
|
||||
.root_module = mod,
|
||||
});
|
||||
|
||||
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||
|
||||
const exe_tests = b.addTest(.{
|
||||
.root_module = exe.root_module,
|
||||
});
|
||||
|
||||
const run_exe_tests = b.addRunArtifact(exe_tests);
|
||||
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&run_mod_tests.step);
|
||||
test_step.dependOn(&run_exe_tests.step);
|
||||
}
|
||||
81
build.zig.zon
Normal file
81
build.zig.zon
Normal file
@@ -0,0 +1,81 @@
|
||||
.{
|
||||
// This is the default name used by packages depending on this one. For
|
||||
// example, when a user runs `zig fetch --save <url>`, this field is used
|
||||
// as the key in the `dependencies` table. Although the user can choose a
|
||||
// different name, most users will stick with this provided value.
|
||||
//
|
||||
// It is redundant to include "zig" in this name because it is already
|
||||
// within the Zig package namespace.
|
||||
.name = .pandas_markdown,
|
||||
// This is a [Semantic Version](https://semver.org/).
|
||||
// In a future version of Zig it will be used for package deduplication.
|
||||
.version = "0.0.0",
|
||||
// Together with name, this represents a globally unique package
|
||||
// identifier. This field is generated by the Zig toolchain when the
|
||||
// package is first created, and then *never changes*. This allows
|
||||
// unambiguous detection of one package being an updated version of
|
||||
// another.
|
||||
//
|
||||
// When forking a Zig project, this id should be regenerated (delete the
|
||||
// field and run `zig build`) if the upstream project is still maintained.
|
||||
// Otherwise, the fork is *hostile*, attempting to take control over the
|
||||
// original project's identity. Thus it is recommended to leave the comment
|
||||
// on the following line intact, so that it shows up in code reviews that
|
||||
// modify the field.
|
||||
.fingerprint = 0xcd4f98c3fd56819e, // Changing this has security and trust implications.
|
||||
// Tracks the earliest Zig version that the package considers to be a
|
||||
// supported use case.
|
||||
.minimum_zig_version = "0.15.1",
|
||||
// This field is optional.
|
||||
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||
// Once all dependencies are fetched, `zig build` no longer requires
|
||||
// internet connectivity.
|
||||
.dependencies = .{
|
||||
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
|
||||
//.example = .{
|
||||
// // When updating this field to a new URL, be sure to delete the corresponding
|
||||
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
||||
// // the new URL. If the contents of a URL change this will result in a hash mismatch
|
||||
// // which will prevent zig from using it.
|
||||
// .url = "https://example.com/foo.tar.gz",
|
||||
//
|
||||
// // This is computed from the file contents of the directory of files that is
|
||||
// // obtained after fetching `url` and applying the inclusion rules given by
|
||||
// // `paths`.
|
||||
// //
|
||||
// // This field is the source of truth; packages do not come from a `url`; they
|
||||
// // come from a `hash`. `url` is just one of many possible mirrors for how to
|
||||
// // obtain a package matching this `hash`.
|
||||
// //
|
||||
// // Uses the [multihash](https://multiformats.io/multihash/) format.
|
||||
// .hash = "...",
|
||||
//
|
||||
// // When this is provided, the package is found in a directory relative to the
|
||||
// // build root. In this case the package's hash is irrelevant and therefore not
|
||||
// // computed. This field and `url` are mutually exclusive.
|
||||
// .path = "foo",
|
||||
//
|
||||
// // When this is set to `true`, a package is declared to be lazily
|
||||
// // fetched. This makes the dependency only get fetched if it is
|
||||
// // actually used.
|
||||
// .lazy = false,
|
||||
//},
|
||||
},
|
||||
// Specifies the set of files and directories that are included in this package.
|
||||
// Only files and directories listed here are included in the `hash` that
|
||||
// is computed for this package. Only files listed here will remain on disk
|
||||
// when using the zig package manager. As a rule of thumb, one should list
|
||||
// files required for compilation plus any license(s).
|
||||
// Paths are relative to the build root. Use the empty string (`""`) to refer to
|
||||
// the build root itself.
|
||||
// A directory listed here means that all files within, recursively, are included.
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
// For example...
|
||||
//"LICENSE",
|
||||
//"README.md",
|
||||
},
|
||||
}
|
||||
69
create_tests.py
Normal file
69
create_tests.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# test "parses-comment" {
|
||||
# const input = "// this is a comment\n";
|
||||
# const parsed = [_]Token{
|
||||
# Token{
|
||||
# .type = .comment,
|
||||
# .data = comment_id,
|
||||
# },
|
||||
# Token{
|
||||
# .type = .raw_text,
|
||||
# .data = "this is a comment",
|
||||
# },
|
||||
# Token{ .type = .newline, .data = "\n" },
|
||||
# };
|
||||
|
||||
# var parsing = try tokenize(input, std.testing.allocator);
|
||||
|
||||
# for (parsed, parsing.items[0..parsed.len]) |expected_token, actual_token| {
|
||||
# try expect(expected_token.type == actual_token.type);
|
||||
# try expect(std.mem.eql(u8, expected_token.data, actual_token.data));
|
||||
# }
|
||||
|
||||
# parsing.deinit(std.testing.allocator);
|
||||
# }
|
||||
|
||||
import json
|
||||
from pprint import pprint
|
||||
|
||||
with open("tests/test.json", "r") as txt:
|
||||
tests : dict = json.loads(txt.read())
|
||||
for test_name, test_value in tests["basic_unit_tests"].items():
|
||||
|
||||
tokens = ""
|
||||
|
||||
for token in test_value["parsed"]:
|
||||
token_type = list(token.keys())[0]
|
||||
|
||||
tokens += f"""
|
||||
Token{{
|
||||
.type = .{token_type},
|
||||
.data = "{token[token_type].encode("unicode_escape").decode("utf-8")}",
|
||||
}},"""
|
||||
|
||||
print(f"""
|
||||
test "{test_name}" {{
|
||||
const input = "{test_value["input"].encode("unicode_escape").decode("utf-8")}";
|
||||
const parsed = [_]Token{{{tokens}
|
||||
}};
|
||||
|
||||
var parsing = try tokenize(input, std.testing.allocator);
|
||||
try expect(parsing.items.len >= parsed.len);
|
||||
|
||||
for (parsed, parsing.items[0..parsed.len]) |expected_token, actual_token| {{
|
||||
try expect(expected_token.type == actual_token.type);
|
||||
try expect(std.mem.eql(u8, expected_token.data, actual_token.data));
|
||||
}}
|
||||
|
||||
parsing.deinit(std.testing.allocator);
|
||||
}}
|
||||
""")
|
||||
# pprint(test_value["parsed"])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
15
find_all_tokens.py
Normal file
15
find_all_tokens.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import json
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
tokens = set()
|
||||
|
||||
with open("tests/test.json", "r") as txt:
|
||||
tests : dict = json.loads(txt.read())
|
||||
for test_name, test_value in tests["basic_unit_tests"].items():
|
||||
for token in test_value["parsed"]:
|
||||
tokens.add(list(token.keys())[0])
|
||||
|
||||
pprint(tokens)
|
||||
|
||||
|
||||
365
grammer.md
Normal file
365
grammer.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# meta data
|
||||
|
||||
|
||||
yaml can be defined at the start of a file to define meta data
|
||||
```md
|
||||
---
|
||||
# yaml
|
||||
---
|
||||
```
|
||||
|
||||
# headings
|
||||
these are standard markdown headings
|
||||
|
||||
```md
|
||||
# heading 1
|
||||
## heading 2
|
||||
### heading 3
|
||||
#### heading 4
|
||||
##### heading 5
|
||||
###### heading 6
|
||||
```
|
||||
|
||||
# text and inline styles
|
||||
|
||||
## text
|
||||
|
||||
just some text man dont know what to tell you
|
||||
```
|
||||
plain test
|
||||
```
|
||||
|
||||
## inline styles
|
||||
all inline styles must start with a space and end with a space
|
||||
however these are just the defualt ones and can be changed within the meta data as well as the ablity to add custom ones
|
||||
|
||||
### code
|
||||
```md
|
||||
`plain test`
|
||||
```
|
||||
|
||||
### bold
|
||||
```md
|
||||
!plain test!
|
||||
```
|
||||
|
||||
### italic
|
||||
```md
|
||||
*plain test*
|
||||
```
|
||||
|
||||
### underline
|
||||
```md
|
||||
_plain test_
|
||||
```
|
||||
|
||||
### strikethrough
|
||||
```md
|
||||
~plain test~
|
||||
```
|
||||
|
||||
### highlighted
|
||||
```md
|
||||
|plain test|
|
||||
```
|
||||
|
||||
all style chars:
|
||||
```
|
||||
named : `!*_~|
|
||||
unamed : &%$#-+=
|
||||
```
|
||||
|
||||
### super script
|
||||
```md
|
||||
sometext^{}
|
||||
```
|
||||
### sub script
|
||||
```md
|
||||
sometext_2
|
||||
```
|
||||
|
||||
# lists
|
||||
|
||||
|
||||
## ordered
|
||||
```md
|
||||
1. ordered list
|
||||
2. ordered list
|
||||
3. ordered list
|
||||
```
|
||||
|
||||
```md
|
||||
i. ordered list
|
||||
ii. ordered list
|
||||
iii. ordered list
|
||||
```
|
||||
|
||||
```md
|
||||
a. ordered list
|
||||
b. ordered list
|
||||
c. ordered list
|
||||
```
|
||||
|
||||
## unordered
|
||||
|
||||
```md
|
||||
- unordered list
|
||||
- unordered list
|
||||
- unordered list
|
||||
```
|
||||
|
||||
```md
|
||||
= unordered list
|
||||
= unordered list
|
||||
= unordered list
|
||||
```
|
||||
|
||||
```md
|
||||
+ unordered list
|
||||
+ unordered list
|
||||
+ unordered list
|
||||
```
|
||||
|
||||
```md
|
||||
* unordered list
|
||||
* unordered list
|
||||
* unordered list
|
||||
```
|
||||
|
||||
# embeds
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
```md
|
||||
#[table text](relitive path to tabulated data)
|
||||
```
|
||||
|
||||
```md
|
||||
$[file text](path to file#starting_line:ending_line)
|
||||
```
|
||||
|
||||
embed file chars:
|
||||
```
|
||||
named : !#$
|
||||
unamed : *_~|&%-+=
|
||||
```
|
||||
|
||||
```md
|
||||
/[file text](link to something)
|
||||
```
|
||||
|
||||
# tables
|
||||
|
||||
```
|
||||
| col | col | col |
|
||||
| --- | --- | --- |
|
||||
| row | row | row |
|
||||
| row | row | row |
|
||||
| row | row | row |
|
||||
| row | row | row |
|
||||
| --- | --- | --- |
|
||||
| col | col | col |
|
||||
| --- | --- | --- |
|
||||
| row | row | row |
|
||||
| row | row | row |
|
||||
| row | row | row |
|
||||
| row | row | row |
|
||||
```
|
||||
|
||||
# quote blocks
|
||||
|
||||
```md
|
||||
> quote
|
||||
> quote
|
||||
> quote
|
||||
```
|
||||
|
||||
```md
|
||||
| quote
|
||||
| quote
|
||||
| quote
|
||||
```
|
||||
|
||||
# text/code blocks
|
||||
|
||||
```
|
||||
\```
|
||||
some text or code
|
||||
\```
|
||||
```
|
||||
|
||||
```
|
||||
\```lang_name
|
||||
some text or code
|
||||
\```
|
||||
```
|
||||
|
||||
the passthough lang name will just place what is in the box within the output
|
||||
```
|
||||
\```passthough
|
||||
some text or code
|
||||
\```
|
||||
```
|
||||
|
||||
# comments
|
||||
|
||||
everything after the commnet identifier is a comment until the next line
|
||||
```md
|
||||
// this is a comment
|
||||
```
|
||||
|
||||
# tick box
|
||||
```md
|
||||
- [ ] something to check off
|
||||
- [x] something checked off
|
||||
- [/] something ticked off
|
||||
- [~] something dashed off
|
||||
```
|
||||
|
||||
# horrazontal rules
|
||||
```md
|
||||
--- // straight line
|
||||
=== // double straight line
|
||||
*** // big dotted straight line
|
||||
... // small dotted line
|
||||
&&& // squiggly line
|
||||
^^^ // jagged line
|
||||
```
|
||||
|
||||
# footnote
|
||||
|
||||
```md
|
||||
sometext [^1]
|
||||
|
||||
[^1]: footnote
|
||||
```
|
||||
|
||||
# advanced features
|
||||
|
||||
## custom styles
|
||||
any of the above features can have style overrides
|
||||
it beings with a . to differnate it from other functions
|
||||
```md
|
||||
@.styles()
|
||||
# heading 7
|
||||
```
|
||||
|
||||
## citations
|
||||
|
||||
```md
|
||||
---
|
||||
refs: refs.bib
|
||||
---
|
||||
|
||||
@cite(panda)
|
||||
|
||||
@bib()
|
||||
```
|
||||
|
||||
## replacements
|
||||
|
||||
```md
|
||||
---
|
||||
replacement:
|
||||
toads: "frogs"
|
||||
---
|
||||
|
||||
@toads
|
||||
```
|
||||
-->
|
||||
```
|
||||
frogs
|
||||
```
|
||||
|
||||
## replacement macros
|
||||
```md
|
||||
---
|
||||
macros:
|
||||
hello:
|
||||
args:
|
||||
name : "str"
|
||||
age : "number"
|
||||
code:
|
||||
"hello my name is {name} and i am {age} years old"
|
||||
---
|
||||
|
||||
|
||||
@hello("panda", 240)
|
||||
```
|
||||
-->
|
||||
```
|
||||
hello my name is panda and i am 240 years old
|
||||
```
|
||||
|
||||
## numerical macros
|
||||
|
||||
```
|
||||
---
|
||||
macros:
|
||||
add:
|
||||
args:
|
||||
num1 : "number"
|
||||
num2 : "number"
|
||||
eq:
|
||||
num1 + num2
|
||||
---
|
||||
|
||||
@add(1, 2)
|
||||
```
|
||||
-->
|
||||
```
|
||||
3
|
||||
```
|
||||
|
||||
## cli macros
|
||||
|
||||
```
|
||||
---
|
||||
macros:
|
||||
generate_figure:
|
||||
args:
|
||||
filename : "str"
|
||||
cmd:
|
||||
python generate_figure.py {filename}
|
||||
post_process:
|
||||
""
|
||||
---
|
||||
|
||||
@generate_figure("data/run2.csv")
|
||||
```
|
||||
-->
|
||||
```
|
||||

|
||||
```
|
||||
|
||||
|
||||
## heading id override
|
||||
|
||||
```md
|
||||
@.id(heading-1-overide)
|
||||
@.style()
|
||||
# heading 1
|
||||
|
||||
@.id(heading-2-overide)
|
||||
@.style()
|
||||
## heading 2
|
||||
|
||||
@.id(heading-3-overide)
|
||||
@.style()
|
||||
### heading 3
|
||||
|
||||
@.id(heading-4-overide)
|
||||
@.style()
|
||||
#### heading 4
|
||||
|
||||
@.id(heading-5-overide)
|
||||
@.style()
|
||||
##### heading 5
|
||||
|
||||
@.id(heading-6-overide)
|
||||
@.style()
|
||||
###### heading 6
|
||||
|
||||
```
|
||||
23
how_it_works.md
Normal file
23
how_it_works.md
Normal file
@@ -0,0 +1,23 @@
|
||||
1. first comments are stripped out of the line
|
||||
well they are actually still there if you want to add them in to your output
|
||||
|
||||
2. multiline elements are processed
|
||||
|
||||
3. any tags that begining a line are stripped and added to the token list
|
||||
|
||||
4. the inline text elements are then run
|
||||
|
||||
1. soemthing else
|
||||
|
||||
this is to make sure the child elements are correct
|
||||
|
||||
# you can have heading in here
|
||||
|
||||
2. more shit
|
||||
1. something
|
||||
|
||||
|
||||
|
||||
sometext
|
||||
someother text
|
||||
even more text
|
||||
20
readme.md
Normal file
20
readme.md
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
|
||||
|
||||
how to run the tests in a cleaner manner
|
||||
``` bash
|
||||
zig test --test-runner tests/test_runner.zig src/document.zig
|
||||
```
|
||||
|
||||
|
||||
|
||||
# todo
|
||||
|
||||
- [ ] possible ENBF grammer
|
||||
- [ ] add multistyle tests
|
||||
- [ ] add the style chars inbetween the style char markers test
|
||||
- [ ] add comment tests on all
|
||||
- [ ] add multilevel nested list test
|
||||
- [ ] add bulk everything in one test
|
||||
- [ ] styles within tables test
|
||||
3069
src/document.zig
Normal file
3069
src/document.zig
Normal file
File diff suppressed because it is too large
Load Diff
27
src/main.zig
Normal file
27
src/main.zig
Normal file
@@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
const pandas_markdown = @import("pandas_markdown");
|
||||
|
||||
pub fn main() !void {
|
||||
// Prints to stderr, ignoring potential errors.
|
||||
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
||||
try pandas_markdown.bufferedPrint();
|
||||
}
|
||||
|
||||
test "simple test" {
|
||||
const gpa = std.testing.allocator;
|
||||
var list: std.ArrayList(i32) = .empty;
|
||||
defer list.deinit(gpa); // Try commenting this out and see if zig detects the memory leak!
|
||||
try list.append(gpa, 42);
|
||||
try std.testing.expectEqual(@as(i32, 42), list.pop());
|
||||
}
|
||||
|
||||
test "fuzz example" {
|
||||
const Context = struct {
|
||||
fn testOne(context: @This(), input: []const u8) anyerror!void {
|
||||
_ = context;
|
||||
// Try passing `--fuzz` to `zig build test` and see if it manages to fail this test case!
|
||||
try std.testing.expect(!std.mem.eql(u8, "canyoufindme", input));
|
||||
}
|
||||
};
|
||||
try std.testing.fuzz(Context{}, Context.testOne, .{});
|
||||
}
|
||||
0
src/tests.zig
Normal file
0
src/tests.zig
Normal file
727
tests/test.json
Normal file
727
tests/test.json
Normal file
@@ -0,0 +1,727 @@
|
||||
|
||||
{
|
||||
"idenifier_chars" : {
|
||||
"headings" : "#",
|
||||
"inline_styles" : "`!*_~|&%$#-+=",
|
||||
"sup" : "^",
|
||||
"sub" : "_",
|
||||
"ordered" : [
|
||||
"[number].",
|
||||
"[letter].",
|
||||
"[i]."
|
||||
],
|
||||
"unordered" : "-=+*",
|
||||
"embed" : "!#$*_~|&%-+=",
|
||||
"link" : "/"
|
||||
},
|
||||
"basic_unit_tests" : {
|
||||
"heading_1" : {
|
||||
"input" : "# hello this is a heading\n",
|
||||
"parsed" : [
|
||||
{"heading" : "#"},
|
||||
{"text" : "hello this is a heading"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"heading_2" : {
|
||||
"input" : "## hello this is a heading\n",
|
||||
"parsed" : [
|
||||
{"heading" : "##"},
|
||||
{"text" : "hello this is a heading"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"heading_3" : {
|
||||
"input" : "### hello this is a heading\n",
|
||||
"parsed" : [
|
||||
{"heading" : "###"},
|
||||
{"text" : "hello this is a heading"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"heading_4" : {
|
||||
"input" : "#### hello this is a heading\n",
|
||||
"parsed" : [
|
||||
{"heading" : "####"},
|
||||
{"text" : "hello this is a heading"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"heading_5" : {
|
||||
"input" : "##### hello this is a heading\n",
|
||||
"parsed" : [
|
||||
{"heading" : "#####"},
|
||||
{"text" : "hello this is a heading"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"heading_6" : {
|
||||
"input" : "###### hello this is a heading\n",
|
||||
"parsed" : [
|
||||
{"heading" : "######"},
|
||||
{"text" : "hello this is a heading"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"header_no_text" : {
|
||||
"input" : "######\n",
|
||||
"parsed" : [
|
||||
{"heading" : "######"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text" : {
|
||||
"input" : "plain test\n",
|
||||
"parsed" : [
|
||||
{"text" : "plain test"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_code" : {
|
||||
"input" : "`plain test`\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "`"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "`"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_bold" : {
|
||||
"input" : "!plain test!\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "!"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "!"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_italic" : {
|
||||
"input" : "*plain test*\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "*"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "*"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_underline" : {
|
||||
"input" : "_plain test_\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "_"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "_"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_strikethrough" : {
|
||||
"input" : "~plain test~\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "~"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "~"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_highlighted" : {
|
||||
"input" : "|plain test|\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "|"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "|"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_&" : {
|
||||
"input" : "&plain test&\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "&"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "&"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_%" : {
|
||||
"input" : "%plain test%\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "%"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "%"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_$" : {
|
||||
"input" : "$plain test$\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "$"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "$"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_#" : {
|
||||
"input" : "#plain test#\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "#"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "#"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_-" : {
|
||||
"input" : "-plain test-\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "-"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "-"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_+" : {
|
||||
"input" : "+plain test+\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "+"},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "+"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_=" : {
|
||||
"input" : "=plain test=\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "="},
|
||||
{"text" : "plain test"},
|
||||
{"inline_style" : "="},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_espaced" : {
|
||||
"input" : "\\`plain test`\n",
|
||||
"parsed" : [
|
||||
{"text" : "`plain test`"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_with_style_char_in_string" : {
|
||||
"input" : "+plain something + something else test+\n",
|
||||
"parsed" : [
|
||||
{"inline_style" : "+"},
|
||||
{"text" : "plain something + something else test"},
|
||||
{"inline_style" : "+"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_with_space right after" : {
|
||||
"input" : "+ plain something + something else test+\n",
|
||||
"parsed" : [
|
||||
{"text" : "+ plain something + something else test+"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_style_super_script" : {
|
||||
"input" : "sometext^2\n",
|
||||
"parsed" : [
|
||||
{"text" : "sometext"},
|
||||
{"sup" : "^"},
|
||||
{"text" : "2"}
|
||||
]
|
||||
},
|
||||
"text_style_sub_script" : {
|
||||
"input" : "sometext_2\n",
|
||||
"parsed" : [
|
||||
{"text" : "sometext"},
|
||||
{"sub" : "_"},
|
||||
{"text" : "2"}
|
||||
]
|
||||
},
|
||||
"list_ordered_number":{
|
||||
"input" : "1. ordered list\n2. ordered list\n3. ordered list\n",
|
||||
"parsed" : [
|
||||
{"ordered_list" : "1."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"ordered_list" : "2."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"ordered_list" : "3."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"list_ordered_i":{
|
||||
"input" : "i. ordered list\nii. ordered list\niii. ordered list\n",
|
||||
"parsed" : [
|
||||
{"ordered_list" : "i."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"ordered_list" : "ii."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"ordered_list" : "iii."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"list_ordered_letter":{
|
||||
"input" : "a. ordered list\nb. ordered list\nc. ordered list\n",
|
||||
"parsed" : [
|
||||
{"ordered_list" : "a."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"ordered_list" : "b."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"ordered_list" : "c."},
|
||||
{"text" : "ordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"list_unordered_dashed":{
|
||||
"input" : "- unordered list\n- unordered list\n- unordered list\n",
|
||||
"parsed" : [
|
||||
{"unordered_list" : "-"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "-"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "-"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"list_unordered_eq":{
|
||||
"input" : "= unordered list\n= unordered list\n= unordered list\n",
|
||||
"parsed" : [
|
||||
{"unordered_list" : "="},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "="},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "="},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"list_unordered_plus":{
|
||||
"input" : "+ unordered list\n+ unordered list\n+ unordered list\n",
|
||||
"parsed" : [
|
||||
{"unordered_list" : "+"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "+"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "+"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"list_unordered_dot":{
|
||||
"input" : "* unordered list\n* unordered list\n* unordered list\n",
|
||||
"parsed" : [
|
||||
{"unordered_list" : "*"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "*"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"},
|
||||
{"unordered_list" : "*"},
|
||||
{"text" : "unordered list"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_image": {
|
||||
"input" : "\n",
|
||||
"parsed" : [
|
||||
{"embed" : "!"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "figure text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "relitive path to image"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_table": {
|
||||
"input" : "#[table text](relitive path to tabulated data)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "#"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "table text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "relitive path to tabulated data"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_file": {
|
||||
"input" : "$[file text](path to file#starting_line:ending_line)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "$"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "path to file#starting_line:ending_line"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_*": {
|
||||
"input" : "*[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "*"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed__": {
|
||||
"input" : "_[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "_"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_~": {
|
||||
"input" : "~[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "~"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_|": {
|
||||
"input" : "|[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "|"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_&": {
|
||||
"input" : "&[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "&"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_%": {
|
||||
"input" : "%[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "%"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_-": {
|
||||
"input" : "-[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "-"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_+": {
|
||||
"input" : "+[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "+"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_=": {
|
||||
"input" : "=[file text](file_path)\n",
|
||||
"parsed" : [
|
||||
{"embed" : "="},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "file_path"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"embed_link": {
|
||||
"input" : "/[file text](link to something)\n",
|
||||
"parsed" : [
|
||||
{"link" : "/"},
|
||||
{"bracket_open" : "["},
|
||||
{"text" : "file text"},
|
||||
{"bracket_close" : "]"},
|
||||
{"bracket_open" : "("},
|
||||
{"raw_text" : "link to something"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"table" : {
|
||||
"input" : "| col | col | col |\n| --- | --- | --- |\n| row | row | row |\n| row | row | row |\n| row | row | row |\n| row | row | row |\n",
|
||||
"parsed" : [
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " col "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " col "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " col "},
|
||||
{"table_sep" : "|"},
|
||||
{"newline" : "\n"},
|
||||
{"table_sep" : "|"},
|
||||
{"table_row_sep" : " --- "},
|
||||
{"table_sep" : "|"},
|
||||
{"table_row_sep" : " --- "},
|
||||
{"table_sep" : "|"},
|
||||
{"table_row_sep" : " --- "},
|
||||
{"table_sep" : "|"},
|
||||
{"newline" : "\n"},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"newline" : "\n"},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"newline" : "\n"},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"newline" : "\n"},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"text" : " row "},
|
||||
{"table_sep" : "|"},
|
||||
{"newline" : "\n"}
|
||||
|
||||
]
|
||||
},
|
||||
"quote_arrow" : {
|
||||
"input" : "> quote\n> quote\n> quote\n",
|
||||
"parsed" : [
|
||||
{"quote" : ">"},
|
||||
{"text" : "quote"},
|
||||
{"newline" : "\n"},
|
||||
{"quote" : ">"},
|
||||
{"text" : "quote"},
|
||||
{"newline" : "\n"},
|
||||
{"quote" : ">"},
|
||||
{"text" : "quote"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"quote_bar" : {
|
||||
"input" : "| quote\n| quote\n| quote\n",
|
||||
"parsed" : [
|
||||
{"quote" : "|"},
|
||||
{"text" : "quote"},
|
||||
{"newline" : "\n"},
|
||||
{"quote" : "|"},
|
||||
{"text" : "quote"},
|
||||
{"newline" : "\n"},
|
||||
{"quote" : "|"},
|
||||
{"text" : "quote"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"text_block" : {
|
||||
"input" : "```\nsome text or code\n```\n",
|
||||
"parsed" : [
|
||||
{"code_block" : "```"},
|
||||
{"newline" : "\n"},
|
||||
{"raw_text" : "some text or code"},
|
||||
{"newline" : "\n"},
|
||||
{"code_block" : "```"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"code_block" : {
|
||||
"input" : "```lang_name\nsome text or code\n```\n",
|
||||
"parsed" : [
|
||||
{"code_block" : "```"},
|
||||
{"raw_text" : "lang_name"},
|
||||
{"newline" : "\n"},
|
||||
{"raw_text" : "some text or code"},
|
||||
{"newline" : "\n"},
|
||||
{"code_block" : "```"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"passthrough_block" : {
|
||||
"input" : "```passthrough\nsome text or code\n```\n",
|
||||
"parsed" : [
|
||||
{"code_block" : "```"},
|
||||
{"raw_text" : "passthrough"},
|
||||
{"newline" : "\n"},
|
||||
{"raw_text" : "some text or code"},
|
||||
{"newline" : "\n"},
|
||||
{"code_block" : "```"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"comment" : {
|
||||
"input" : "// this is a comment\n",
|
||||
"parsed" : [
|
||||
{"comment" : "// "},
|
||||
{"raw_text" : "this is a comment"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"tick_box_empty" : {
|
||||
"input" : "- [ ] something to check off\n",
|
||||
"parsed" : [
|
||||
{"tickbox" : "- [ ]"},
|
||||
{"text" : "something to check off"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"tick_box_checked" : {
|
||||
"input" : "- [x] something checked off\n",
|
||||
"parsed" : [
|
||||
{"tickbox" : "- [x]"},
|
||||
{"text" : "something checked off"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"tick_box_ticked" : {
|
||||
"input" : "- [/] something ticked off\n",
|
||||
"parsed" : [
|
||||
{"tickbox" : "- [/]"},
|
||||
{"text" : "something ticked off"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"tick_box_dashed" : {
|
||||
"input" : "- [~] something dashed off\n",
|
||||
"parsed" : [
|
||||
{"tickbox" : "- [~]"},
|
||||
{"text" : "something dashed off"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"horizontal_rule_straight_line" : {
|
||||
"input" : "---\n",
|
||||
"parsed" : [
|
||||
{"rule" : "---"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"horizontal_rule_double_straight_line" : {
|
||||
"input" : "===\n",
|
||||
"parsed" : [
|
||||
{"rule" : "==="},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"horizontal_rule_big_dotted_straight_line" : {
|
||||
"input" : "***\n",
|
||||
"parsed" : [
|
||||
{"rule" : "***"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"horizontal_rule_small_dotted_line" : {
|
||||
"input" : "...\n",
|
||||
"parsed" : [
|
||||
{"rule" : "..."},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"horizontal_rule_squiggly_line" : {
|
||||
"input" : "&&&\n",
|
||||
"parsed" : [
|
||||
{"rule" : "&&&"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"horizontal_rule_jagged_line" : {
|
||||
"input" : "^^^\n",
|
||||
"parsed" : [
|
||||
{"rule" : "^^^"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"footnote" : {
|
||||
"input" : "sometext [^1]\n\n[^1]: footnote\n",
|
||||
"parsed" : [
|
||||
{"text" : "sometext "},
|
||||
{"footnote" : "[^1]"},
|
||||
{"newline" : "\n"},
|
||||
{"newline" : "\n"},
|
||||
{"footnote_def" : "[^1]:"},
|
||||
{"text" : "footnote"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
},
|
||||
"inbulit" : {
|
||||
"input" : "@.macro(arg, arg2)\n",
|
||||
"parsed" : [
|
||||
{"inbulit" : "macro"},
|
||||
{"bracket_open" : "("},
|
||||
{"macro_arg" : "arg"},
|
||||
{"arg_sep" : ","},
|
||||
{"macro_arg" : "arg2"},
|
||||
{"bracket_close" : ")"},
|
||||
{"newline" : "\n"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
16
tests/test_runner.zig
Normal file
16
tests/test_runner.zig
Normal file
@@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn main() !void {
|
||||
var stdout_buffer: [1024]u8 = undefined;
|
||||
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
||||
const stdout = &stdout_writer.interface;
|
||||
for (builtin.test_functions) |t| {
|
||||
t.func() catch |err| {
|
||||
try stdout.print("{s} fail: {}\n", .{ t.name, err });
|
||||
continue;
|
||||
};
|
||||
try stdout.print("{s} passed\n", .{t.name});
|
||||
}
|
||||
try stdout.flush(); // Don't forget to flush!
|
||||
}
|
||||
Reference in New Issue
Block a user