Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

VS Code like Editor in Playground and Customized Terminal #265

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This configuration file was automatically generated by Gitpod.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we delete this file? It might cause problem with the setup.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is the config file that Gitpod uses when you open the project in Gitpod and as as far as I have tested, doesn't meddle with the source files. Could you please elaborate on what files conflict with this one and which setup is being affected by this file? We could resolve the issue better that way.

The content of this file basically tells Gitpod to build the bundle (which is not pushed to Github, i.e. ignored) and also start the dev server so that we can preview the docs website. If you open the project on your machine locally by checking out the PR, this file is ignored and the project should open as it does normally.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familiar with the gitpod so thought it might conflict. Anyways nice addition to the playground. Let's wait for the authorized users to react to this.

# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
# and commit this file to your remote git repository to share the goodness with others.

tasks:
- init: npm install && npm run build
command: npm run dev


2 changes: 0 additions & 2 deletions apps/docs/components/Code/CodeEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,3 @@ type Props = {
code: string;
};
export default React.memo(CodeEditor);


55 changes: 55 additions & 0 deletions apps/docs/components/Code/CodeEditor/monaco/MonacoCodeEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from "react";
import { OnChange } from "@monaco-editor/react";
import monacoOptions from "./options";
import Editor from "@monaco-editor/react";
import { bhailangConfig, bhailangSyntax } from "./monacoBhailang";
import { useMonaco } from "@monaco-editor/react";
import {
reservedValueCompletions,
keywordCompletions,
snippetCompletions,
} from "./completions";
import { theme } from "./theme";

interface Props {
handleChange: OnChange;
code: string;
}

const MonacoCodeEditor = (props: Props) => {
const monaco = useMonaco();
React.useEffect(() => {
if (monaco) {
monaco.languages.register({ id: "bhailang" });
monaco.languages.setMonarchTokensProvider("bhailang", bhailangSyntax);
monaco.languages.setLanguageConfiguration("bhailang", bhailangConfig);
monaco.languages.registerCompletionItemProvider("bhailang", {
provideCompletionItems: () => {
var suggestions = [
...keywordCompletions(monaco),
...snippetCompletions(monaco),
...reservedValueCompletions(monaco),
];
return { suggestions: suggestions };
},
});
monaco.editor.defineTheme("my-theme", theme);
monaco.editor.setTheme("my-theme");
}
}, [monaco]);

return (
<div className="shadow-md">
<Editor
height="50vh"
language="bhailang"
onChange={props.handleChange}
value={props.code}
options={monacoOptions}
theme="vs-dark"
/>
</div>
);
};

export default React.memo(MonacoCodeEditor);
72 changes: 72 additions & 0 deletions apps/docs/components/Code/CodeEditor/monaco/completions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { bhailangKeywords } from "./monacoBhailang";
import M from "monaco-editor";

export const keywordCompletions = (monaco: typeof M) =>
bhailangKeywords.map((keyword) => ({
label: keyword,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: keyword,
}));

export const snippetCompletions = (monaco: typeof M) => [
{
label: "byh",
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: "bhai ye hai ${1:varname} = ${0:value};",
insertTextRules:
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: "Variable banata hai bhai",
},
{
label: "bb",
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: 'bol bhai ${1:"Kuch to bol bhai"};',
insertTextRules:
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: "Bolega bhai",
},
{
label: "agb",
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: ["agar bhai (${1:condition}) {", "\t$0", "}"].join("\n"),
insertTextRules:
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: "If statement",
},
{
label: "ntb",
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: ["nahi to bhai (${1:condition}) {", "\t$0", "}"].join("\n"),
insertTextRules:
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: "Elseif block",
},
{
label: "wb",
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: ["warna bhai {", "\t$0", "}"].join("\n"),
insertTextRules:
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: "Else block",
},
{
label: "jtb",
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: [
"jab tak bhai (${1:condition}) {",
"\t${0:// kuch kar bhai}",
"}",
].join("\n"),
insertTextRules:
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: "If-Else Statement",
},
];

export const reservedValueCompletions = (monaco: typeof M) => [
...["sahi", "galat", "nalla"].map((b) => ({
label: b,
kind: monaco.languages.CompletionItemKind.Value,
insertText: b,
})),
];
230 changes: 230 additions & 0 deletions apps/docs/components/Code/CodeEditor/monaco/monacoBhailang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import monaco from "monaco-editor";

export const bhailangKeywords =
"hi|bye|bol|bhai|agar|nahi|to|warna|jab|tak|bas|kar|hai|agla|dekh|ye".split(
"|"
);

export const bhailangSyntax: monaco.languages.IMonarchLanguage = {
// Set defaultToken to invalid to see what you do not tokenize yet
defaultToken: "invalid",
tokenPostfix: ".bhai",

keywords: bhailangKeywords,

typeKeywords: ["any", "boolean", "number", "object", "string", "nalla"],

operators: [
"<=",
">=",
"==",
"!=",
"===",
"!==",
"=>",
"+",
"-",
"**",
"*",
"/",
"%",
"++",
"--",
"<<",
"</",
">>",
">>>",
"&",
"|",
"^",
"!",
"~",
"&&",
"||",
"?",
":",
"=",
"+=",
"-=",
"*=",
"**=",
"/=",
"%=",
"<<=",
">>=",
">>>=",
"&=",
"|=",
"^=",
"@",
],

// we include these common regular expressions
symbols: /[=><!~?:&|+\-*\/\^%]+/,
escapes:
/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
digits: /\d+(_+\d+)*/,
octaldigits: /[0-7]+(_+[0-7]+)*/,
binarydigits: /[0-1]+(_+[0-1]+)*/,
hexdigits: /[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,

regexpctl: /[(){}\[\]\$\^|\-*+?\.]/,
regexpesc:
/\\(?:[bBdDfnrstvwWn0\\\/]|@regexpctl|c[A-Z]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})/,

// The main tokenizer for our languages
tokenizer: {
root: [[/[{}]/, "delimiter.bracket"], { include: "common" }],

common: [
// identifiers and keywords
[
/[a-z_$][\w$]*/,
{
cases: {
"@typeKeywords": "keyword",
"@keywords": "keyword",
"@default": "identifier",
},
},
],
[/[A-Z][\w\$]*/, "type.identifier"], // to show class names nicely
// [/[A-Z][\w\$]*/, 'identifier'],

// whitespace
{ include: "@whitespace" },

// regular expression: ensure it is terminated before beginning (otherwise it is an opeator)
[
/\/(?=([^\\\/]|\\.)+\/([gimsuy]*)(\s*)(\.|;|\/|,|\)|\]|\}|$))/,
{ token: "regexp", bracket: "@open", next: "@regexp" },
],

// delimiters and operators
[/[()\[\]]/, "@brackets"],
[/[<>](?!@symbols)/, "@brackets"],
[
/@symbols/,
{
cases: {
"@operators": "delimiter",
"@default": "",
},
},
],

// numbers
[/(@digits)[eE]([\-+]?(@digits))?/, "number.float"],
[/(@digits)\.(@digits)([eE][\-+]?(@digits))?/, "number.float"],
[/0[xX](@hexdigits)/, "number.hex"],
[/0[oO]?(@octaldigits)/, "number.octal"],
[/0[bB](@binarydigits)/, "number.binary"],
[/(@digits)/, "number"],

// delimiter: after number because of .\d floats
[/[;,.]/, "delimiter"],

// strings
[/"([^"\\]|\\.)*$/, "string.invalid"], // non-teminated string
[/'([^'\\]|\\.)*$/, "string.invalid"], // non-teminated string
[/"/, "string", "@string_double"],
[/'/, "string", "@string_single"],
[/`/, "string", "@string_backtick"],
],

whitespace: [
[/[ \t\r\n]+/, ""],
[/\/\*\*(?!\/)/, "comment.doc", "@jsdoc"],
[/\/\*/, "comment", "@comment"],
[/\/\/.*$/, "comment"],
],

comment: [
// [/[^\/*]+/, "comment"],
[/((\n*.*)*)(.*)hi bhai/, "comment"],
[/\*\//, "comment", "@pop"],
[/[\/*]/, "comment"],
],

jsdoc: [
[/[^\/*]+/, "comment.doc"],
[/\*\//, "comment.doc", "@pop"],
[/[\/*]/, "comment.doc"],
],

// We match regular expression quite precisely
regexp: [
[
/(\{)(\d+(?:,\d*)?)(\})/,
[
"regexp.escape.control",
"regexp.escape.control",
"regexp.escape.control",
],
],
[/(\()(\?:|\?=|\?!)/, ["regexp.escape.control", "regexp.escape.control"]],
[/[()]/, "regexp.escape.control"],
[/@regexpctl/, "regexp.escape.control"],
[/[^\\\/]/, "regexp"],
[/@regexpesc/, "regexp.escape"],
[/\\\./, "regexp.invalid"],
],

regexrange: [
[/-/, "regexp.escape.control"],
[/\^/, "regexp.invalid"],
[/@regexpesc/, "regexp.escape"],
[/[^\]]/, "regexp"],
[
/\]/,
{ token: "regexp.escape.control", next: "@pop", bracket: "@close" },
],
],

string_double: [
[/[^\\"]+/, "string"],
[/@escapes/, "string.escape"],
[/\\./, "string.escape.invalid"],
[/"/, "string", "@pop"],
],

string_single: [
[/[^\\']+/, "string"],
[/@escapes/, "string.escape"],
[/\\./, "string.escape.invalid"],
[/'/, "string", "@pop"],
],

string_backtick: [
[/\$\{/, { token: "delimiter.bracket", next: "@bracketCounting" }],
[/[^\\`$]+/, "string"],
[/@escapes/, "string.escape"],
[/\\./, "string.escape.invalid"],
[/`/, "string", "@pop"],
],

bracketCounting: [
[/\{/, "delimiter.bracket", "@bracketCounting"],
[/\}/, "delimiter.bracket", "@pop"],
{ include: "common" },
],
},
};

export const bhailangConfig: monaco.languages.LanguageConfiguration = {
surroundingPairs: [
{ open: "{", close: "}" },
{ open: "[", close: "]" },
{ open: "(", close: ")" },
{ open: "<", close: ">" },
{ open: "'", close: "'" },
{ open: '"', close: '"' },
],
autoClosingPairs: [
{ open: "{", close: "}" },
{ open: "[", close: "]" },
{ open: "(", close: ")" },
{ open: "'", close: "'", notIn: ["string", "comment"] },
{ open: '"', close: '"', notIn: ["string", "comment"] },
],
};
18 changes: 18 additions & 0 deletions apps/docs/components/Code/CodeEditor/monaco/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { editor } from "monaco-editor";

const options: editor.IStandaloneEditorConstructionOptions = {
automaticLayout: true,
padding: { top: 16, bottom: 16 },
tabSize: 2,
autoClosingQuotes: "always",
fontFamily: "Jetbrains Mono",
fontLigatures: true,
fontSize: 14,
lineHeight: 32,
suggestLineHeight: 32,
cursorSmoothCaretAnimation: true,
scrollBeyondLastLine: false,
smoothScrolling: true,
};

export default options;