mirror of
https://github.com/pdemian/human2regex.git
synced 2025-05-16 12:30:09 -07:00
Added codemirror editor
This commit is contained in:
parent
a23efd3904
commit
92fc7445d5
5
docs/bundle.min.css
vendored
5
docs/bundle.min.css
vendored
File diff suppressed because one or more lines are too long
18
docs/bundle.min.js
vendored
18
docs/bundle.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html><html lang="en" dir="ltr"><head><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content="Create regular expressions with natural, human language"><meta name="keywords" content="Human2Regex, Human, Regex, Natural, Language, Natural Language"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Human2Regex</title><link href="bundle.min.css" rel="stylesheet" type="text/css"><meta name="theme-color" content="#212529"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="default"><link rel="icon" type="image/x-icon" href="favicon.ico"></head><body><a class="skip skip-top" href="#maincontent">Skip to main content</a><div class="wrapper"><nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav"><div class="container"><a class="navbar-brand" href="index.html"><img src="favicon.png" width="30" height="30" class="d-inline-block align-top" alt="logo"> Human2Regex</a></div></nav><div class="container" id="maincontent" role="main"><div class="row"><div class="col-lg-8"><div class="form-group row zero-margin-bottom"><p class="col-sm-4">Regex dialect:</p><span class="col-sm-8"><select class="form-control" id="dialect"><option value="js" selected="selected">Javascript</option><option value="dotnet">.NET</option><option value="java">Java</option><option value="perl">Perl</option></select></span></div><h4>Your Regular Expression:</h4><input readonly="readonly" class="form-control" id="regex"><h4>Human Speak:</h4><textarea class="form-control" id="human" rows="25" onkeydown='if(9===event.keyCode){var v=this.value,s=this.selectionStart,e=this.selectionEnd;return this.value=v.substring(0,s)+"\t"+v.substring(e),this.selectionStart=this.selectionEnd=s+1,!1}'>
|
<!DOCTYPE html><html lang="en" dir="ltr"><head><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content="Create regular expressions with natural, human language"><meta name="keywords" content="Human2Regex, Human, Regex, Natural, Language, Natural Language"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Human2Regex</title><link href="bundle.min.css" rel="stylesheet" type="text/css"><meta name="theme-color" content="#212529"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="default"><link rel="icon" type="image/x-icon" href="favicon.ico"></head><body><a class="skip skip-top" href="#maincontent">Skip to main content</a><div class="wrapper"><nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav"><div class="container"><a class="navbar-brand" href="index.html"><img src="favicon.png" width="30" height="30" class="d-inline-block align-top" alt="logo"> Human2Regex</a></div></nav><div class="container" id="maincontent" role="main"><div class="row"><div class="col-lg-8 tenpx-margin-bottom"><div class="form-group row zero-margin-bottom"><label for="dialect" class="col-sm-4 col-form-label">Regex dialect:</label><div class="col-sm-8"><select class="form-control" id="dialect"><option value="js" selected="selected">Javascript</option><option value="dotnet">.NET</option><option value="java">Java</option><option value="perl">Perl</option></select></div></div><h4>Your Regular Expression:</h4><div class="row"><div class="col-xl-11"><input readonly="readonly" class="form-control" id="regex"></div><div class="col-xl-1"><button type="button" class="btn btn-secondary" id="clip">Copy</button></div></div><h4>Human Speak:</h4><textarea class="form-control" id="human" rows="25">
|
||||||
// H2R supports // # and /**/ as comments
|
// H2R supports // # and /**/ as comments
|
||||||
// A group is only captured if given a name.
|
// A group is only captured if given a name.
|
||||||
// You can use "and", "or", "not" to specify "[]" regex
|
// You can use "and", "or", "not" to specify "[]" regex
|
||||||
@ -37,4 +37,4 @@ create an optional group
|
|||||||
# fragment, again, we don't care, so ignore everything afterwards
|
# fragment, again, we don't care, so ignore everything afterwards
|
||||||
match "#"
|
match "#"
|
||||||
match 0+ any thing
|
match 0+ any thing
|
||||||
</textarea></div><br><div class="col-lg-4 margin-when-small"><div class="cheatsheet"><h2>Cheat Sheet:</h2><p>Full documentation available <a href="tutorial.html">here</a></p><p class="font-weight-bold">Matching</p><p><code>match "hello world"</code> matches "hello world" exactly</p><p></p><p><code>match "hello" then optionally " world"</code> matches "hello" or "hello world"</p><p><code>match "hello" or "world"</code> matches "hello" or "world</p><p><code>match a word</code> matches any word</p><p class="font-weight-bold">Repetition</p><p><code>match 0+ "hello"</code> matches 0 or more "hello"s</p><p><code>match 3 "hello"</code> matches exactly "hellohellohello"</p><p><code>match 1 to 5 "hello"</code> matches between 1 to 5 "hello"s</p><p><code>repeat 0 or more</code> repeats the intended text 0 or more times (default)</p><p><code>optionally repeat between 3 to 5</code> optionally repeats the indented text 3 to 5 times</p><p class="font-weight-bold">Grouping</p><p><code>create a group called "mygroup"</code> creates a group called "mygroup"</p><p><code>create an optional group</code> creates an unnamed optional group</p></div></div></div></div><footer><div class="container"><div class="row"><div class="col-lg-8 col-md-10 mx-auto"><p class="copyright">Copyright © 2020 Patrick Demian. This page's source code is available at <a rel="noopener noreferrer" href="https://github.com/pdemian/">github.com/pdemian/</a></p></div></div></div></footer></div><script defer="defer" src="bundle.min.js"></script></body></html>
|
</textarea><h4>Errors:</h4><textarea readonly="readonly" class="form-control" id="errors" rows="5"></textarea></div><br><div class="col-lg-4 tenpx-margin-bottom"><div class="cheatsheet"><h2>Cheat Sheet:</h2><p>Full documentation available <a href="tutorial.html">here</a></p><p class="font-weight-bold">Matching</p><p><code>match "hello world"</code> matches "hello world" exactly</p><p></p><p><code>match "hello" then optionally " world"</code> matches "hello" or "hello world"</p><p><code>match "hello" or "world"</code> matches "hello" or "world</p><p><code>match a word</code> matches any word</p><p class="font-weight-bold">Repetition</p><p><code>match 0+ "hello"</code> matches 0 or more "hello"s</p><p><code>match 3 "hello"</code> matches exactly "hellohellohello"</p><p><code>match 1 to 5 "hello"</code> matches between 1 to 5 "hello"s</p><p><code>repeat 0 or more</code> repeats the intended text 0 or more times (default)</p><p><code>optionally repeat between 3 to 5</code> optionally repeats the indented text 3 to 5 times</p><p class="font-weight-bold">Grouping</p><p><code>create a group called "mygroup"</code> creates a group called "mygroup"</p><p><code>create an optional group</code> creates an unnamed optional group</p></div></div></div></div><footer><div class="container"><div class="row"><div class="col-lg-8 col-md-10 mx-auto"><p class="copyright">Copyright © 2020 Patrick Demian. This page's source code is available at <a rel="noopener noreferrer" href="https://github.com/pdemian/">github.com/pdemian/</a></p></div></div></div></footer></div><script defer="defer" src="bundle.min.js"></script></body></html>
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -2400,6 +2400,11 @@
|
|||||||
"q": "^1.1.2"
|
"q": "^1.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"codemirror": {
|
||||||
|
"version": "5.58.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.58.2.tgz",
|
||||||
|
"integrity": "sha512-K/hOh24cCwRutd1Mk3uLtjWzNISOkm4fvXiMO7LucCrqbh6aJDdtqUziim3MZUI6wOY0rvY1SlL1Ork01uMy6w=="
|
||||||
|
},
|
||||||
"collect-v8-coverage": {
|
"collect-v8-coverage": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chevrotain": "^7.0.2",
|
"chevrotain": "^7.0.2",
|
||||||
|
"codemirror": "^5.58.2",
|
||||||
"jquery": "^3.5.1"
|
"jquery": "^3.5.1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -4,29 +4,33 @@
|
|||||||
import { Human2RegexLexer, Human2RegexLexerOptions } from "./lexer";
|
import { Human2RegexLexer, Human2RegexLexerOptions } from "./lexer";
|
||||||
import { Human2RegexParser, Human2RegexParserOptions } from "./parser";
|
import { Human2RegexParser, Human2RegexParserOptions } from "./parser";
|
||||||
import { RobotLanguage } from "./generator";
|
import { RobotLanguage } from "./generator";
|
||||||
import { lexErrorToCommonError, parseErrorToCommonError, semanticErrorToCommonError, ICommonError } from "./utilities";
|
import { CommonError } from "./utilities";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
import CodeMirror from "codemirror/lib/codemirror";
|
||||||
|
require("codemirror/mode/javascript/javascript");
|
||||||
|
|
||||||
import "./webpage/bootstrap.css";
|
import "./webpage/bootstrap.css";
|
||||||
import "./webpage/cleanblog.css";
|
import "./webpage/cleanblog.css";
|
||||||
|
import "codemirror/lib/codemirror.css";
|
||||||
import "./webpage/style.css";
|
import "./webpage/style.css";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
const total_errors: ICommonError[] = [];
|
const total_errors: CommonError[] = [];
|
||||||
const lexer = new Human2RegexLexer(new Human2RegexLexerOptions(true));
|
const lexer = new Human2RegexLexer(new Human2RegexLexerOptions(true));
|
||||||
const parser = new Human2RegexParser(new Human2RegexParserOptions(true));
|
const parser = new Human2RegexParser(new Human2RegexParserOptions(true));
|
||||||
const result = lexer.tokenize($("#human").text());
|
const result = lexer.tokenize($("#human").text());
|
||||||
|
|
||||||
result.errors.map(lexErrorToCommonError).forEach((x) => total_errors.push(x));
|
result.errors.map(CommonError.fromLexError).forEach((x) => total_errors.push(x));
|
||||||
|
|
||||||
|
let regex_result = "";
|
||||||
|
|
||||||
if (total_errors.length === 0) {
|
if (total_errors.length === 0) {
|
||||||
parser.input = result.tokens;
|
parser.input = result.tokens;
|
||||||
|
|
||||||
const regex = parser.parse();
|
const regex = parser.parse();
|
||||||
|
|
||||||
parser.errors.map(parseErrorToCommonError).forEach((x) => total_errors.push(x));
|
parser.errors.map(CommonError.fromParseError).forEach((x) => total_errors.push(x));
|
||||||
|
|
||||||
let lang: RobotLanguage = RobotLanguage.JS;
|
let lang: RobotLanguage = RobotLanguage.JS;
|
||||||
switch ($("#dialect option:selected").val()) {
|
switch ($("#dialect option:selected").val()) {
|
||||||
@ -46,15 +50,21 @@ $(function() {
|
|||||||
|
|
||||||
const valid = regex.validate(lang);
|
const valid = regex.validate(lang);
|
||||||
|
|
||||||
valid.map(semanticErrorToCommonError).forEach((x) => total_errors.push(x));
|
valid.map(CommonError.fromSemanticError).forEach((x) => total_errors.push(x));
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
if (total_errors.length === 0) {
|
if (total_errors.length === 0) {
|
||||||
const r = regex.toRegex(lang);
|
regex_result = regex.toRegex(lang);
|
||||||
$("#regex").attr("value", r);
|
$("#regex").attr("value", regex_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$("#errors").empty();
|
||||||
|
|
||||||
|
for (const error of total_errors) {
|
||||||
|
$("#errors").append(`${error.toString()}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Errors = " + total_errors);
|
console.log("Errors = " + total_errors);
|
||||||
|
|
||||||
$("#dialect").on("selectionchanged", () => {
|
$("#dialect").on("selectionchanged", () => {
|
||||||
@ -64,6 +74,31 @@ $(function() {
|
|||||||
$("#human").on("input", () => {
|
$("#human").on("input", () => {
|
||||||
//do something
|
//do something
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#clip").on("click", () => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
if (window.isSecureContext && navigator?.clipboard?.writeText) {
|
||||||
|
navigator.clipboard.writeText(regex_result);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const text = document.getElementById("regex") as any;
|
||||||
|
text.select();
|
||||||
|
text.setSelectionRange(0, 10*10*10*10);
|
||||||
|
document.execCommand("copy");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = CodeMirror.fromTextArea(document.getElementById("human"), {
|
||||||
|
mode: {name: "javascript"},
|
||||||
|
lineNumbers: false,
|
||||||
|
indentUnit: 4,
|
||||||
|
viewportMargin: Infinity
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.on("change", (instance: unknown, change_obj: unknown) => {
|
||||||
|
/* not empty */
|
||||||
|
console.log(editor.getValue());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,35 +54,24 @@ export function regexEscape(input: string) : string {
|
|||||||
return input.replace("\\", "\\\\").replace(/([=:\-\.\[\]\^\|\(\)\*\+\?\{\}\$\/])/g, "\\$1");
|
return input.replace("\\", "\\\\").replace(/([=:\-\.\[\]\^\|\(\)\*\+\?\{\}\$\/])/g, "\\$1");
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICommonError {
|
export class CommonError {
|
||||||
type: string,
|
constructor(public type: string, public start_line: number, public start_column: number, public length: number, public message: string) {
|
||||||
startLine: number,
|
/* empty */
|
||||||
startColumn: number,
|
}
|
||||||
length: number,
|
|
||||||
message: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function lexErrorToCommonError(error: ILexingError): ICommonError {
|
public static fromLexError(error: ILexingError): CommonError {
|
||||||
return {
|
return new CommonError("Lexer Error", error.line, error.column, error.length, error.message);
|
||||||
type: "Lexer Error",
|
}
|
||||||
startLine: error.line,
|
|
||||||
startColumn: error.column,
|
|
||||||
length: error.length,
|
|
||||||
message: error.message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseErrorToCommonError(error: IRecognitionException): ICommonError {
|
public static fromParseError(error: IRecognitionException): CommonError {
|
||||||
return {
|
return new CommonError("Parser Error", error.token.startLine ?? NaN, error.token.startColumn ?? NaN, error.token.endOffset ?? NaN - error.token.startOffset, error.name + ": " + error.message);
|
||||||
type: "Parser Error",
|
}
|
||||||
startLine: error.token.startLine ?? NaN,
|
|
||||||
startColumn: error.token.startColumn ?? NaN,
|
|
||||||
length: error.token.endOffset ?? NaN - error.token.startOffset,
|
|
||||||
message: error.name + ": " + error.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function semanticErrorToCommonError(error: ISemanticError): ICommonError {
|
public static fromSemanticError(error: ISemanticError): CommonError {
|
||||||
(error as ICommonError).type = "Semantic Error";
|
return new CommonError("Semantic Error", error.startLine, error.startColumn, error.length, error.message);
|
||||||
return error as ICommonError;
|
}
|
||||||
|
|
||||||
|
public toString(): string {
|
||||||
|
return `${this.type} @ ${this.start_line} ${this.start_column}: ${this.message}`;
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,21 +2,30 @@
|
|||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="container" id="maincontent" role="main">
|
<div class="container" id="maincontent" role="main">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8 tenpx-margin-bottom">
|
||||||
<div class="form-group row zero-margin-bottom">
|
<div class="form-group row zero-margin-bottom">
|
||||||
<p class="col-sm-4">Regex dialect:</p>
|
<label for="dialect" class="col-sm-4 col-form-label">Regex dialect:</label>
|
||||||
<span class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<select class="form-control" id="dialect">
|
<select class="form-control" id="dialect">
|
||||||
<option value="js" selected>Javascript</option>
|
<option value="js" selected>Javascript</option>
|
||||||
<option value="dotnet">.NET</option>
|
<option value="dotnet">.NET</option>
|
||||||
<option value="java">Java</option>
|
<option value="java">Java</option>
|
||||||
<option value="perl">Perl</option>
|
<option value="perl">Perl</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h4>Your Regular Expression:</h4>
|
<h4>Your Regular Expression:</h4>
|
||||||
<input readonly type="text" class="form-control" id="regex"></input>
|
<div class="row">
|
||||||
|
<div class="col-xl-11">
|
||||||
|
<input readonly type="text" class="form-control" id="regex"></input>
|
||||||
|
</div>
|
||||||
|
<div class="col-xl-1">
|
||||||
|
<button type="button" class="btn btn-secondary" id="clip">Copy</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h4>Human Speak:</h4>
|
<h4>Human Speak:</h4>
|
||||||
<textarea class="form-control" id="human" rows="25" onkeydown="if(event.keyCode===9){var v=this.value,s=this.selectionStart,e=this.selectionEnd;this.value=v.substring(0, s)+'\t'+v.substring(e);this.selectionStart=this.selectionEnd=s+1;return false;}">
|
<textarea class="form-control" id="human" rows="25">
|
||||||
// H2R supports // # and /**/ as comments
|
// H2R supports // # and /**/ as comments
|
||||||
// A group is only captured if given a name.
|
// A group is only captured if given a name.
|
||||||
// You can use "and", "or", "not" to specify "[]" regex
|
// You can use "and", "or", "not" to specify "[]" regex
|
||||||
@ -56,9 +65,11 @@ create an optional group
|
|||||||
match "#"
|
match "#"
|
||||||
match 0+ any thing
|
match 0+ any thing
|
||||||
</textarea>
|
</textarea>
|
||||||
|
<h4>Errors:</h4>
|
||||||
|
<textarea readonly class="form-control " id="errors" rows="5"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="col-lg-4 margin-when-small">
|
<div class="col-lg-4 tenpx-margin-bottom">
|
||||||
<div class="cheatsheet">
|
<div class="cheatsheet">
|
||||||
<h2>Cheat Sheet:</h2>
|
<h2>Cheat Sheet:</h2>
|
||||||
<p>Full documentation available <a href="tutorial.html">here</a></p>
|
<p>Full documentation available <a href="tutorial.html">here</a></p>
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
/*! Copyright (c) 2020 Patrick Demian; Licensed under MIT */
|
/*! Copyright (c) 2020 Patrick Demian; Licensed under MIT */
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
.tenpx-margin-bottom {
|
||||||
.margin-when-small {
|
margin-bottom: 10px;
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
@ -81,4 +78,48 @@ a:hover {
|
|||||||
|
|
||||||
.navbar-light .navbar-nav .nav-link {
|
.navbar-light .navbar-nav .nav-link {
|
||||||
color: rgba(0, 0, 0, 0.54);
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#errors {
|
||||||
|
resize: none;
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
/* Bootstrap Settings */
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
font: inherit;
|
||||||
|
overflow: auto;
|
||||||
|
font-family: inherit;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 6px 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #555;
|
||||||
|
background-color: #fff;
|
||||||
|
background-image: none;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
|
||||||
|
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||||
|
/* Code Mirror Settings */
|
||||||
|
font-family: monospace;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
resize: vertical;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-focused {
|
||||||
|
/* Bootstrap Settings */
|
||||||
|
border-color: #80bdff;
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: 0 0 0.2rem rgba(102, 175, 233, .6);
|
||||||
|
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user