mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 08:09:27 +00:00
fix: Updated QueryEditor component to support languages (#3988)
fix #4292 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new custom `QueryEditor` component for a more customizable and consistent editing experience across various forms and editors. - Added support for a new programming language, VRL, including syntax highlighting and theming. - **Enhancements** - Updated multiple components (`AddTemplate.vue`, `AddFunction.vue`, `EditRole.vue`) to utilize the `QueryEditor` component, improving editing functionality and user interface. - Enhanced the `SearchBar.vue` component for better formatting and language handling. - **Bug Fixes** - Adjusted the language attribute in the `SearchBar.vue` component from "ruby" to "vrl" to ensure correct syntax highlighting. - **Tests** - Improved stability of the alerts test suite by adding a timeout after user input actions. - Added a timeout in the sanity test cases to enhance the reliability of template submission. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -214,6 +214,7 @@ test.describe("Alerts testcases", () => {
|
||||
'[data-test="add-template-name-input"]').fill("test");
|
||||
await page.click(".view-line")
|
||||
await page.keyboard.type('test');
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator(
|
||||
'[data-test="add-template-submit-btn"]').click({ force: true }); await expect(page.locator(
|
||||
".q-notification__message").getByText(/Please enter valid JSON/).first()).toBeVisible();
|
||||
|
||||
@@ -427,6 +427,7 @@ test.describe("Sanity testcases", () => {
|
||||
const jsonString = '{"text": "{alert_name} is active"}';
|
||||
await page.click(".view-line");
|
||||
await page.keyboard.type(jsonString);
|
||||
await page.waitForTimeout(500);
|
||||
await page
|
||||
.locator('[data-test="add-template-submit-btn"]')
|
||||
.click({ force: true });
|
||||
|
||||
@@ -37,9 +37,8 @@ import {
|
||||
} from "vue";
|
||||
|
||||
import "monaco-editor/esm/vs/editor/editor.all.js";
|
||||
import "monaco-editor/esm/vs/basic-languages/sql/sql.contribution.js";
|
||||
import "monaco-editor/esm/vs/basic-languages/sql/sql.js";
|
||||
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||
import { vrlLanguageDefinition } from "@/utils/query/vrlLanguageDefinition";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { debounce } from "quasar";
|
||||
@@ -125,7 +124,7 @@ export default defineComponent({
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
const setupEditor = () => {
|
||||
monaco.editor.defineTheme("myCustomTheme", {
|
||||
base: "vs", // can also be vs-dark or hc-black
|
||||
inherit: true, // can also be false to completely replace the builtin rules
|
||||
@@ -210,6 +209,52 @@ export default defineComponent({
|
||||
window.addEventListener("click", () => {
|
||||
editorObj.layout();
|
||||
});
|
||||
|
||||
window.addEventListener("resize", async () => {
|
||||
await nextTick();
|
||||
editorObj.layout();
|
||||
// queryEditorRef.value.resetEditorLayout();
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
provider.value?.dispose();
|
||||
|
||||
if (props.language === "vrl") {
|
||||
monaco.languages.register({ id: "vrl" });
|
||||
|
||||
// Register a tokens provider for the language
|
||||
monaco.languages.setMonarchTokensProvider(
|
||||
"vrl",
|
||||
vrlLanguageDefinition as any
|
||||
);
|
||||
}
|
||||
|
||||
if (props.language === "sql") {
|
||||
await import(
|
||||
"monaco-editor/esm/vs/basic-languages/sql/sql.contribution.js"
|
||||
);
|
||||
}
|
||||
|
||||
if (props.language === "json") {
|
||||
await import(
|
||||
"monaco-editor/esm/vs/language/json/monaco.contribution.js"
|
||||
);
|
||||
}
|
||||
|
||||
if (props.language === "html") {
|
||||
await import(
|
||||
"monaco-editor/esm/vs/language/html/monaco.contribution.js"
|
||||
);
|
||||
}
|
||||
|
||||
if (props.language === "markdown") {
|
||||
await import(
|
||||
"monaco-editor/esm/vs/basic-languages/markdown/markdown.contribution.js"
|
||||
);
|
||||
}
|
||||
|
||||
setupEditor();
|
||||
});
|
||||
|
||||
onActivated(async () => {
|
||||
@@ -329,6 +374,10 @@ export default defineComponent({
|
||||
editorRef.value.dispatchEvent(escEvent);
|
||||
};
|
||||
|
||||
const formatDocument = () => {
|
||||
editorObj.getAction("editor.action.formatDocument").run();
|
||||
};
|
||||
|
||||
const getCursorIndex = () => {
|
||||
const currentPosition = editorObj.getPosition();
|
||||
const cursorIndex = editorObj.getModel().getOffsetAt(currentPosition) - 1;
|
||||
@@ -344,6 +393,7 @@ export default defineComponent({
|
||||
triggerAutoComplete,
|
||||
getCursorIndex,
|
||||
searchObj,
|
||||
formatDocument,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -81,15 +81,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
>
|
||||
{{ t("alert_templates.body") + " *" }}
|
||||
</div>
|
||||
<div
|
||||
data-test="add-template-body-input"
|
||||
<query-editor
|
||||
editor-id="add-template-editor"
|
||||
class="monaco-editor q-mt-sm"
|
||||
language="json"
|
||||
ref="editorRef"
|
||||
id="editor"
|
||||
v-model:query="formData.body"
|
||||
data-test="add-template-body-input"
|
||||
:label="t('alerts.sql')"
|
||||
stack-label
|
||||
style="border: 1px solid #dbdbdb; border-radius: 5px"
|
||||
class="showLabelOnTop"
|
||||
resize
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
/>
|
||||
</div>
|
||||
@@ -169,29 +168,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</q-page>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
defineProps,
|
||||
onBeforeMount,
|
||||
onActivated,
|
||||
defineEmits,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { ref, defineProps, onBeforeMount, onActivated, defineEmits } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
import "monaco-editor/esm/vs/editor/editor.all.js";
|
||||
import "monaco-editor/esm/vs/language/json/monaco.contribution.js";
|
||||
import "monaco-editor/esm/vs/language/json/jsonMode.js";
|
||||
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||
|
||||
import templateService from "@/services/alert_templates";
|
||||
import { useStore } from "vuex";
|
||||
import { copyToClipboard, useQuasar } from "quasar";
|
||||
import type { TemplateData, Template } from "@/ts/interfaces/index";
|
||||
import { useRouter } from "vue-router";
|
||||
import { isValidResourceName } from "@/utils/zincutils";
|
||||
import QueryEditor from "@/components/QueryEditor.vue";
|
||||
|
||||
const props = defineProps<{ template: TemplateData | null }>();
|
||||
const emit = defineEmits(["get:templates", "cancel:hideform"]);
|
||||
@@ -204,8 +191,6 @@ const formData: Ref<Template> = ref({
|
||||
const store = useStore();
|
||||
const q = useQuasar();
|
||||
const editorRef: any = ref(null);
|
||||
let editorobj: any = null;
|
||||
const editorData = ref("");
|
||||
const isUpdatingTemplate = ref(false);
|
||||
const sampleTemplates = [
|
||||
{
|
||||
@@ -238,51 +223,6 @@ onActivated(() => setupTemplateData());
|
||||
onBeforeMount(() => {
|
||||
setupTemplateData();
|
||||
});
|
||||
onMounted(async () => {
|
||||
monaco.editor.defineTheme("myCustomTheme", {
|
||||
base: "vs", // can also be vs-dark or hc-black
|
||||
inherit: true, // can also be false to completely replace the builtin rules
|
||||
rules: [
|
||||
{
|
||||
token: "comment",
|
||||
foreground: "ffa500",
|
||||
background: "FFFFFF",
|
||||
fontStyle: "italic underline",
|
||||
},
|
||||
{
|
||||
token: "comment.js",
|
||||
foreground: "008800",
|
||||
fontStyle: "bold",
|
||||
background: "FFFFFF",
|
||||
},
|
||||
{ token: "comment.css", foreground: "0000ff", background: "FFFFFF" }, // will inherit fontStyle from `comment` above
|
||||
],
|
||||
colors: {
|
||||
"editor.foreground": "#000000",
|
||||
"editor.background": "#FFFFFF",
|
||||
"editorCursor.foreground": "#000000",
|
||||
"editor.lineHighlightBackground": "#FFFFFF",
|
||||
"editorLineNumber.foreground": "#000000",
|
||||
"editor.border": "#FFFFFF",
|
||||
},
|
||||
});
|
||||
editorobj = monaco.editor.create(editorRef.value, {
|
||||
value: ``,
|
||||
language: "json",
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
theme: store.state.theme == "dark" ? "vs-dark" : "myCustomTheme",
|
||||
automaticLayout: true,
|
||||
suggestOnTriggerCharacters: false,
|
||||
wordWrap: "on",
|
||||
});
|
||||
editorobj.onKeyUp((e: any) => {
|
||||
editorData.value = editorobj.getValue();
|
||||
formData.value.body = editorobj.getValue();
|
||||
});
|
||||
editorobj.setValue(formData.value.body);
|
||||
});
|
||||
const setupTemplateData = () => {
|
||||
if (props.template) {
|
||||
isUpdatingTemplate.value = true;
|
||||
@@ -291,15 +231,6 @@ const setupTemplateData = () => {
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => store.state.theme,
|
||||
() => {
|
||||
monaco.editor.setTheme(
|
||||
store.state.theme == "dark" ? "vs-dark" : "myCustomTheme",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const isTemplateBodyValid = () => {
|
||||
try {
|
||||
JSON.parse(formData.value.body);
|
||||
@@ -406,13 +337,10 @@ const copyTemplateBody = (text: any) => {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
#editor {
|
||||
.monaco-editor {
|
||||
width: 100%;
|
||||
min-height: 310px;
|
||||
// padding-bottom: 14px;
|
||||
resize: vertical;
|
||||
overflow: auto;
|
||||
max-height: 350px;
|
||||
min-height: 310px !important;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.example-template-body {
|
||||
|
||||
@@ -90,16 +90,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/>
|
||||
|
||||
<div class="q-py-md showLabelOnTop text-bold text-h7">Function:</div>
|
||||
<div
|
||||
<query-editor
|
||||
data-test="logs-vrl-function-editor"
|
||||
ref="editorRef"
|
||||
id="editor"
|
||||
:label="t('function.jsfunction')"
|
||||
stack-label
|
||||
style="border: 1px solid #dbdbdb; border-radius: 5px"
|
||||
@keyup="editorUpdate"
|
||||
class="showLabelOnTop"
|
||||
resize
|
||||
></div>
|
||||
editor-id="add-function-editor"
|
||||
class="monaco-editor"
|
||||
v-model:query="formData.function"
|
||||
language="vrl"
|
||||
/>
|
||||
|
||||
<!-- <q-input v-if="formData.ingest" v-model="formData.order" :label="t('function.order')" color="input-border"
|
||||
bg-color="input-bg" class="q-py-md showLabelOnTop" stack-label outlined filled dense type="number" min="1" /> -->
|
||||
@@ -132,14 +130,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, onMounted, computed, watch } from "vue";
|
||||
import "monaco-editor/esm/vs/editor/editor.all.js";
|
||||
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||
|
||||
import jsTransformService from "../../services/jstransform";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useStore } from "vuex";
|
||||
import { useQuasar } from "quasar";
|
||||
import segment from "../../services/segment_analytics";
|
||||
import QueryEditor from "@/components/QueryEditor.vue";
|
||||
|
||||
const defaultValue: any = () => {
|
||||
return {
|
||||
@@ -164,6 +161,9 @@ export default defineComponent({
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
QueryEditor,
|
||||
},
|
||||
emits: ["update:list", "cancel:hideform"],
|
||||
setup(props, { emit }) {
|
||||
const store: any = useStore();
|
||||
@@ -188,55 +188,9 @@ export default defineComponent({
|
||||
const editorUpdate = (e: any) => {
|
||||
formData.value.function = e.target.value;
|
||||
};
|
||||
const editorData = ref("");
|
||||
const prefixCode = ref("");
|
||||
const suffixCode = ref("");
|
||||
|
||||
onMounted(async () => {
|
||||
monaco.editor.defineTheme("myCustomTheme", {
|
||||
base: "vs", // can also be vs-dark or hc-black
|
||||
inherit: true, // can also be false to completely replace the builtin rules
|
||||
rules: [
|
||||
{
|
||||
token: "comment",
|
||||
foreground: "ffa500",
|
||||
fontStyle: "italic underline",
|
||||
},
|
||||
{ token: "comment.js", foreground: "008800", fontStyle: "bold" },
|
||||
{ token: "comment.css", foreground: "0000ff" }, // will inherit fontStyle from `comment` above
|
||||
],
|
||||
colors: {
|
||||
"editor.foreground": "#000000",
|
||||
},
|
||||
});
|
||||
editorobj = monaco.editor.create(editorRef.value, {
|
||||
value: ``,
|
||||
language: "vrl",
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
theme: store.state.theme == "dark" ? "vs-dark" : "myCustomTheme",
|
||||
});
|
||||
|
||||
editorobj.onKeyUp((e: any) => {
|
||||
if (editorobj.getValue() != "") {
|
||||
editorData.value = editorobj.getValue();
|
||||
formData.value.function = editorobj.getValue();
|
||||
}
|
||||
});
|
||||
|
||||
editorobj.setValue(formData.value.function);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => store.state.theme,
|
||||
() => {
|
||||
monaco.editor.setTheme(
|
||||
store.state.theme == "dark" ? "vs-dark" : "myCustomTheme"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const isValidParam = () => {
|
||||
const methodPattern = /^[A-Za-z0-9]+(?:,[A-Za-z0-9]+)*$/g;
|
||||
return methodPattern.test(formData.value.params) || "Invalid params.";
|
||||
@@ -256,11 +210,9 @@ end`;
|
||||
suffixCode.value = ``;
|
||||
}
|
||||
|
||||
const someCode = `${prefixCode.value}
|
||||
${editorData.value}
|
||||
formData.value.function = `${prefixCode.value}
|
||||
${formData.value.function}
|
||||
${suffixCode.value}`;
|
||||
editorobj.setValue(someCode);
|
||||
formData.value.function = editorobj.getValue();
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
@@ -270,7 +222,6 @@ end`;
|
||||
timeout: 2000,
|
||||
});
|
||||
|
||||
formData.value.function = editorobj.getValue();
|
||||
addJSTransformForm.value.validate().then((valid: any) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
@@ -349,7 +300,6 @@ end`;
|
||||
editorobj,
|
||||
prefixCode,
|
||||
suffixCode,
|
||||
editorData,
|
||||
editorUpdate,
|
||||
updateEditorContent,
|
||||
streamTypes,
|
||||
@@ -377,11 +327,10 @@ end`;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#editor {
|
||||
.monaco-editor {
|
||||
width: 100%;
|
||||
min-height: 15rem;
|
||||
/* padding-bottom: 14px; */
|
||||
resize: both;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
|
||||
@@ -227,10 +227,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
: { width: '100%' }
|
||||
"
|
||||
>
|
||||
<PermissionsJSON
|
||||
<query-editor
|
||||
data-test="logs-vrl-function-editor"
|
||||
editor-id="add-function-editor"
|
||||
class="monaco-editor q-mt-sm"
|
||||
language="json"
|
||||
ref="permissionJsonEditorRef"
|
||||
v-model:query="permissionsJsonValue"
|
||||
class="q-mt-sm"
|
||||
style="height: calc(100vh - 328px)"
|
||||
/>
|
||||
</div>
|
||||
@@ -337,8 +340,8 @@ import AppTabs from "@/components/common/AppTabs.vue";
|
||||
import GroupUsers from "../groups/GroupUsers.vue";
|
||||
import { nextTick } from "vue";
|
||||
|
||||
const PermissionsJSON = defineAsyncComponent(
|
||||
() => import("@/components/iam/roles/PermissionsJSON.vue")
|
||||
const QueryEditor = defineAsyncComponent(
|
||||
() => import("@/components/QueryEditor.vue")
|
||||
);
|
||||
|
||||
onBeforeMount(() => {
|
||||
|
||||
@@ -1,382 +0,0 @@
|
||||
<!-- Copyright 2023 Zinc Labs Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div
|
||||
data-test="query-editor"
|
||||
class="logs-query-editor"
|
||||
ref="editorRef"
|
||||
:id="editorId"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
onMounted,
|
||||
nextTick,
|
||||
type Ref,
|
||||
onDeactivated,
|
||||
onUnmounted,
|
||||
onActivated,
|
||||
watch,
|
||||
} from "vue";
|
||||
|
||||
import "monaco-editor/esm/vs/editor/editor.all.js";
|
||||
import "monaco-editor/esm/vs/language/json/monaco.contribution.js";
|
||||
import "monaco-editor/esm/vs/language/json/jsonMode.js";
|
||||
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { debounce } from "quasar";
|
||||
import useLogs from "@/composables/useLogs";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
editorId: {
|
||||
type: String,
|
||||
default: "editor",
|
||||
},
|
||||
query: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
showAutoComplete: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
keywords: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
suggestions: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
debounceTime: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ["update-query", "run-query", "update:query"],
|
||||
setup(props, { emit }) {
|
||||
const store = useStore();
|
||||
const editorRef: any = ref();
|
||||
let editorObj: any = null;
|
||||
const { searchObj } = useLogs();
|
||||
|
||||
let provider: Ref<monaco.IDisposable | null> = ref(null);
|
||||
|
||||
const CompletionKind: any = {
|
||||
Keyword: monaco.languages.CompletionItemKind.Keyword,
|
||||
Operator: monaco.languages.CompletionItemKind.Operator,
|
||||
Text: monaco.languages.CompletionItemKind.Text,
|
||||
Value: monaco.languages.CompletionItemKind.Value,
|
||||
Method: monaco.languages.CompletionItemKind.Method,
|
||||
Function: monaco.languages.CompletionItemKind.Function,
|
||||
Constructor: monaco.languages.CompletionItemKind.Constructor,
|
||||
Field: monaco.languages.CompletionItemKind.Field,
|
||||
Variable: monaco.languages.CompletionItemKind.Variable,
|
||||
};
|
||||
const insertTextRules: any = {
|
||||
InsertAsSnippet:
|
||||
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||
KeepWhitespace:
|
||||
monaco.languages.CompletionItemInsertTextRule.KeepWhitespace,
|
||||
None: monaco.languages.CompletionItemInsertTextRule.None,
|
||||
};
|
||||
|
||||
const createDependencyProposals = (range: any) => {
|
||||
return props.keywords.map((keyword: any) => {
|
||||
const itemObj: any = {
|
||||
...keyword,
|
||||
label: keyword["label"],
|
||||
kind: CompletionKind[keyword["kind"]],
|
||||
insertText: keyword["insertText"],
|
||||
range: range,
|
||||
};
|
||||
if (insertTextRules[keyword["insertTextRule"]]) {
|
||||
itemObj["insertTextRules"] =
|
||||
insertTextRules[keyword["insertTextRule"]];
|
||||
}
|
||||
return itemObj;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
monaco.editor.defineTheme("myCustomTheme", {
|
||||
base: "vs", // can also be vs-dark or hc-black
|
||||
inherit: true, // can also be false to completely replace the builtin rules
|
||||
rules: [{ token: "comment", background: "FFFFFF" }],
|
||||
colors: {
|
||||
"editor.foreground": "#000000",
|
||||
"editor.background": "#fafafa",
|
||||
"editorCursor.foreground": "#000000",
|
||||
"editor.lineHighlightBackground": "#FFFFFF",
|
||||
"editorLineNumber.foreground": "#000000",
|
||||
"editor.border": "#000000",
|
||||
},
|
||||
});
|
||||
|
||||
registerAutoCompleteProvider();
|
||||
|
||||
const editorElement = document.getElementById(props.editorId);
|
||||
|
||||
if (!editorElement) {
|
||||
console.error("Query Editor element not found");
|
||||
return;
|
||||
}
|
||||
if (editorElement && editorElement?.hasChildNodes()) return;
|
||||
|
||||
editorObj = monaco.editor.create(editorElement as HTMLElement, {
|
||||
value: props.query,
|
||||
language: "json",
|
||||
theme: store.state.theme == "dark" ? "vs-dark" : "myCustomTheme",
|
||||
showFoldingControls: "never",
|
||||
formatOnPaste: true,
|
||||
formatOnType: true,
|
||||
tabSize: 2,
|
||||
wordWrap: "on",
|
||||
lineNumbers: "on",
|
||||
lineNumbersMinChars: 0,
|
||||
overviewRulerLanes: 0,
|
||||
fixedOverflowWidgets: false,
|
||||
overviewRulerBorder: false,
|
||||
lineDecorationsWidth: 3,
|
||||
hideCursorInOverviewRuler: true,
|
||||
renderLineHighlight: "none",
|
||||
glyphMargin: false,
|
||||
folding: false,
|
||||
scrollBeyondLastColumn: 0,
|
||||
scrollBeyondLastLine: false,
|
||||
smoothScrolling: true,
|
||||
mouseWheelScrollSensitivity: 1,
|
||||
fastScrollSensitivity: 1,
|
||||
scrollbar: { horizontal: "auto", vertical: "visible" },
|
||||
find: {
|
||||
addExtraSpaceOnTop: false,
|
||||
autoFindInSelection: "never",
|
||||
seedSearchStringFromSelection: "never",
|
||||
},
|
||||
minimap: { enabled: false },
|
||||
readOnly: props.readOnly,
|
||||
});
|
||||
|
||||
editorObj.onDidChangeModelContent(
|
||||
debounce((e: any) => {
|
||||
emit("update-query", e, editorObj.getValue());
|
||||
emit("update:query", editorObj.getValue());
|
||||
}, props.debounceTime)
|
||||
);
|
||||
|
||||
editorObj.createContextKey("ctrlenter", true);
|
||||
editorObj.addCommand(
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
|
||||
function () {
|
||||
setTimeout(() => {
|
||||
emit("run-query");
|
||||
}, 300);
|
||||
},
|
||||
"ctrlenter"
|
||||
);
|
||||
|
||||
editorObj.onDidFocusEditorWidget(() => {
|
||||
searchObj.meta.queryEditorPlaceholderFlag = false;
|
||||
});
|
||||
|
||||
editorObj.onDidBlurEditorWidget(() => {
|
||||
searchObj.meta.queryEditorPlaceholderFlag = true;
|
||||
});
|
||||
|
||||
window.addEventListener("click", () => {
|
||||
editorObj.layout();
|
||||
});
|
||||
});
|
||||
|
||||
watch(
|
||||
() => store.state.theme,
|
||||
() => {
|
||||
monaco.editor.setTheme(
|
||||
store.state.theme == "dark" ? "vs-dark" : "myCustomTheme"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
onActivated(async () => {
|
||||
provider.value?.dispose();
|
||||
registerAutoCompleteProvider();
|
||||
editorObj.layout();
|
||||
});
|
||||
|
||||
onDeactivated(() => {
|
||||
provider.value?.dispose();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
provider.value?.dispose();
|
||||
});
|
||||
|
||||
// update readonly when prop value changes
|
||||
watch(
|
||||
() => props.readOnly,
|
||||
() => {
|
||||
editorObj.updateOptions({ readOnly: props.readOnly });
|
||||
}
|
||||
);
|
||||
|
||||
// update readonly when prop value changes
|
||||
watch(
|
||||
() => props.query,
|
||||
() => {
|
||||
if (props.readOnly || !editorObj.hasWidgetFocus()) {
|
||||
editorObj.getModel().setValue(props.query);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const setValue = (value: string) => {
|
||||
if (editorObj?.setValue) {
|
||||
editorObj.setValue(value);
|
||||
editorObj.layout();
|
||||
}
|
||||
};
|
||||
|
||||
const registerAutoCompleteProvider = () => {
|
||||
if (!props.showAutoComplete) return;
|
||||
provider.value = monaco.languages.registerCompletionItemProvider(
|
||||
"javascript",
|
||||
{
|
||||
provideCompletionItems: function (model, position) {
|
||||
// find out if we are completing a property in the 'dependencies' object.
|
||||
var textUntilPosition = model.getValueInRange({
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: position.lineNumber,
|
||||
endColumn: position.column,
|
||||
});
|
||||
|
||||
var word = model.getWordUntilPosition(position);
|
||||
var range = {
|
||||
startLineNumber: position.lineNumber,
|
||||
endLineNumber: position.lineNumber,
|
||||
startColumn: word.startColumn,
|
||||
endColumn: word.endColumn,
|
||||
};
|
||||
|
||||
let arr = textUntilPosition.trim().split(" ");
|
||||
let filteredSuggestions = [];
|
||||
filteredSuggestions = createDependencyProposals(range);
|
||||
filteredSuggestions = filteredSuggestions.filter((item) => {
|
||||
return item.label.toLowerCase().includes(word.word.toLowerCase());
|
||||
});
|
||||
|
||||
// if (filteredSuggestions.length == 0) {
|
||||
const lastElement = arr.pop();
|
||||
props.suggestions.forEach((suggestion: any) => {
|
||||
filteredSuggestions.push({
|
||||
label: suggestion.label(lastElement),
|
||||
kind: monaco.languages.CompletionItemKind[
|
||||
suggestion.kind || "Text"
|
||||
],
|
||||
insertText: suggestion.insertText(lastElement),
|
||||
range: range,
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
suggestions: filteredSuggestions,
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const resetEditorLayout = () => {
|
||||
editorObj.layout();
|
||||
};
|
||||
|
||||
const formatDocument = () => {
|
||||
console.log(
|
||||
"formatDocument",
|
||||
editorObj.getAction("editor.action.formatDocument")
|
||||
);
|
||||
editorObj.getAction("editor.action.formatDocument").run();
|
||||
};
|
||||
|
||||
const triggerAutoComplete = async (value: string) => {
|
||||
disableSuggestionPopup();
|
||||
await nextTick();
|
||||
editorObj.trigger(value, "editor.action.triggerSuggest", {});
|
||||
};
|
||||
|
||||
const disableSuggestionPopup = () => {
|
||||
const escEvent = new KeyboardEvent("keydown", {
|
||||
keyCode: 27,
|
||||
code: "Escape",
|
||||
key: "Escape",
|
||||
bubbles: true,
|
||||
});
|
||||
editorRef.value.dispatchEvent(escEvent);
|
||||
};
|
||||
|
||||
const getCursorIndex = () => {
|
||||
const currentPosition = editorObj.getPosition();
|
||||
const cursorIndex = editorObj.getModel().getOffsetAt(currentPosition) - 1;
|
||||
return cursorIndex || null;
|
||||
};
|
||||
|
||||
return {
|
||||
editorRef,
|
||||
editorObj,
|
||||
setValue,
|
||||
resetEditorLayout,
|
||||
disableSuggestionPopup,
|
||||
triggerAutoComplete,
|
||||
getCursorIndex,
|
||||
searchObj,
|
||||
formatDocument,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#editor {
|
||||
width: 100%;
|
||||
height: 78%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.logs-query-editor {
|
||||
.monaco-editor,
|
||||
.monaco-editor .monaco-editor {
|
||||
padding: 0px 0px 0px 0px !important;
|
||||
|
||||
.editor-widget .suggest-widget {
|
||||
z-index: 9999;
|
||||
display: flex !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -180,7 +180,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@click.stop="
|
||||
handleFavoriteSavedView(
|
||||
props.row,
|
||||
favoriteViews.includes(props.row.view_id)
|
||||
favoriteViews.includes(props.row.view_id),
|
||||
)
|
||||
"
|
||||
>
|
||||
@@ -256,7 +256,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@click.stop="
|
||||
handleFavoriteSavedView(
|
||||
props.row,
|
||||
favoriteViews.includes(props.row.view_id)
|
||||
favoriteViews.includes(props.row.view_id),
|
||||
)
|
||||
"
|
||||
>
|
||||
@@ -555,8 +555,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
? 'empty-function'
|
||||
: ''
|
||||
"
|
||||
language="ruby"
|
||||
@keydown.ctrl.enter="handleRunQueryFn"
|
||||
language="vrl"
|
||||
@focus="searchObj.meta.functionEditorPlaceholderFlag = false"
|
||||
@blur="searchObj.meta.functionEditorPlaceholderFlag = true"
|
||||
/>
|
||||
@@ -936,7 +936,7 @@ export default defineComponent({
|
||||
components: {
|
||||
DateTime,
|
||||
QueryEditor: defineAsyncComponent(
|
||||
() => import("@/components/QueryEditor.vue")
|
||||
() => import("@/components/QueryEditor.vue"),
|
||||
),
|
||||
SyntaxGuide,
|
||||
AutoRefreshInterval,
|
||||
@@ -1008,7 +1008,7 @@ export default defineComponent({
|
||||
query: this.searchObj.data.customDownloadQueryObj,
|
||||
page_type: this.searchObj.data.stream.streamType,
|
||||
},
|
||||
"UI"
|
||||
"UI",
|
||||
)
|
||||
.then((res) => {
|
||||
this.customDownloadDialog = false;
|
||||
@@ -1070,7 +1070,6 @@ export default defineComponent({
|
||||
} = useLogs();
|
||||
const queryEditorRef = ref(null);
|
||||
|
||||
|
||||
const formData: any = ref(defaultValue());
|
||||
const functionOptions = ref(searchObj.data.transforms);
|
||||
|
||||
@@ -1134,7 +1133,7 @@ export default defineComponent({
|
||||
(fields) => {
|
||||
if (fields != undefined && fields.length) updateFieldKeywords(fields);
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
@@ -1142,7 +1141,7 @@ export default defineComponent({
|
||||
(funs) => {
|
||||
if (funs.length) updateFunctionKeywords(funs);
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
@@ -1265,13 +1264,13 @@ export default defineComponent({
|
||||
if (searchObj.data.parsedQuery?.from?.length > 0) {
|
||||
if (
|
||||
!searchObj.data.stream.selectedStream.includes(
|
||||
searchObj.data.parsedQuery.from[0].table
|
||||
searchObj.data.parsedQuery.from[0].table,
|
||||
) &&
|
||||
searchObj.data.parsedQuery.from[0].table !== streamName
|
||||
) {
|
||||
let streamFound = false;
|
||||
searchObj.data.stream.selectedStream = [];
|
||||
|
||||
|
||||
streamName = searchObj.data.parsedQuery.from[0].table;
|
||||
searchObj.data.streamResults.list.forEach((stream) => {
|
||||
if (stream.name == searchObj.data.parsedQuery.from[0].table) {
|
||||
@@ -1294,7 +1293,7 @@ export default defineComponent({
|
||||
// true
|
||||
// )
|
||||
// searchObj.data.stream.selectedStreamFields = data.schema
|
||||
|
||||
|
||||
// }
|
||||
}
|
||||
});
|
||||
@@ -1313,7 +1312,7 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e,"Logs: Error while updating query value");
|
||||
console.log(e, "Logs: Error while updating query value");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1341,12 +1340,12 @@ export default defineComponent({
|
||||
value.selectedDate.from = timestampToTimezoneDate(
|
||||
value.startTime / 1000,
|
||||
store.state.timezone,
|
||||
"yyyy/MM/DD"
|
||||
"yyyy/MM/DD",
|
||||
);
|
||||
value.selectedTime.startTime = timestampToTimezoneDate(
|
||||
value.startTime / 1000,
|
||||
store.state.timezone,
|
||||
"HH:mm"
|
||||
"HH:mm",
|
||||
);
|
||||
|
||||
dateTimeRef.value.setAbsoluteTime(value.startTime, value.endTime);
|
||||
@@ -1532,7 +1531,7 @@ export default defineComponent({
|
||||
if (isSavedFunctionAction.value == "create") {
|
||||
callTransform = jsTransformService.create(
|
||||
store.state.selectedOrganization.identifier,
|
||||
formData.value
|
||||
formData.value,
|
||||
);
|
||||
|
||||
callTransform
|
||||
@@ -1574,7 +1573,7 @@ export default defineComponent({
|
||||
saveFunctionLoader.value = true;
|
||||
callTransform = jsTransformService.update(
|
||||
store.state.selectedOrganization.identifier,
|
||||
formData.value
|
||||
formData.value,
|
||||
);
|
||||
|
||||
callTransform
|
||||
@@ -1585,7 +1584,7 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const transformIndex = searchObj.data.transforms.findIndex(
|
||||
(obj) => obj.name === formData.value.name
|
||||
(obj) => obj.name === formData.value.name,
|
||||
);
|
||||
if (transformIndex !== -1) {
|
||||
searchObj.data.transforms[transformIndex].name =
|
||||
@@ -1694,7 +1693,7 @@ export default defineComponent({
|
||||
} else {
|
||||
const needle = val.toLowerCase();
|
||||
functionOptions.value = searchObj.data.transforms.filter(
|
||||
(v) => v.name?.toLowerCase().indexOf(needle) > -1
|
||||
(v) => v.name?.toLowerCase().indexOf(needle) > -1,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1726,7 +1725,7 @@ export default defineComponent({
|
||||
savedviewsService
|
||||
.getViewDetail(
|
||||
store.state.selectedOrganization.identifier,
|
||||
item.view_id
|
||||
item.view_id,
|
||||
)
|
||||
.then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
@@ -1757,32 +1756,32 @@ export default defineComponent({
|
||||
// ----- Here we are explicitly handling stream change for multistream -----
|
||||
let selectedStreams = [];
|
||||
const streamValues = searchObj.data.stream.streamLists.map(
|
||||
(item) => item.value
|
||||
(item) => item.value,
|
||||
);
|
||||
if (typeof extractedObj.data.stream.selectedStream == "object") {
|
||||
if (
|
||||
extractedObj.data.stream.selectedStream.hasOwnProperty(
|
||||
"value"
|
||||
"value",
|
||||
)
|
||||
) {
|
||||
selectedStreams.push(
|
||||
extractedObj.data.stream.selectedStream.value
|
||||
extractedObj.data.stream.selectedStream.value,
|
||||
);
|
||||
} else {
|
||||
selectedStreams.push(
|
||||
...extractedObj.data.stream.selectedStream
|
||||
...extractedObj.data.stream.selectedStream,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selectedStreams.push(extractedObj.data.stream.selectedStream);
|
||||
}
|
||||
const streamNotExist = selectedStreams.filter(
|
||||
(stream_str) => !streamValues.includes(stream_str)
|
||||
(stream_str) => !streamValues.includes(stream_str),
|
||||
);
|
||||
if (streamNotExist.length > 0) {
|
||||
let errMsg = t("search.streamNotExist").replace(
|
||||
"[STREAM_NAME]",
|
||||
streamNotExist
|
||||
streamNotExist,
|
||||
);
|
||||
throw new Error(errMsg);
|
||||
return;
|
||||
@@ -1821,7 +1820,7 @@ export default defineComponent({
|
||||
name: "",
|
||||
function: searchObj.data.tempFunctionContent,
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
searchObj.data.tempFunctionContent =
|
||||
extractedObj.data.tempFunctionContent;
|
||||
@@ -1832,7 +1831,7 @@ export default defineComponent({
|
||||
name: "",
|
||||
function: "",
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
searchObj.data.tempFunctionContent = "";
|
||||
searchObj.meta.functionEditorPlaceholderFlag = true;
|
||||
@@ -1867,15 +1866,15 @@ export default defineComponent({
|
||||
if (typeof extractedObj.data.stream.selectedStream == "object") {
|
||||
if (
|
||||
extractedObj.data.stream.selectedStream.hasOwnProperty(
|
||||
"value"
|
||||
"value",
|
||||
)
|
||||
) {
|
||||
selectedStreams.push(
|
||||
extractedObj.data.stream.selectedStream.value
|
||||
extractedObj.data.stream.selectedStream.value,
|
||||
);
|
||||
} else {
|
||||
selectedStreams.push(
|
||||
...extractedObj.data.stream.selectedStream
|
||||
...extractedObj.data.stream.selectedStream,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -1898,7 +1897,7 @@ export default defineComponent({
|
||||
|
||||
const streamData = await getStreams(
|
||||
searchObj.data.stream.streamType,
|
||||
true
|
||||
true,
|
||||
);
|
||||
searchObj.data.streamResults = streamData;
|
||||
await loadStreamLists();
|
||||
@@ -1906,15 +1905,15 @@ export default defineComponent({
|
||||
// searchObj.value = mergeDeep(searchObj, extractedObj);
|
||||
|
||||
const streamValues = searchObj.data.stream.streamLists.map(
|
||||
(item) => item.value
|
||||
(item) => item.value,
|
||||
);
|
||||
const streamNotExist = selectedStreams.filter(
|
||||
(stream_str) => !streamValues.includes(stream_str)
|
||||
(stream_str) => !streamValues.includes(stream_str),
|
||||
);
|
||||
if (streamNotExist.length > 0) {
|
||||
let errMsg = t("search.streamNotExist").replace(
|
||||
"[STREAM_NAME]",
|
||||
streamNotExist
|
||||
streamNotExist,
|
||||
);
|
||||
throw new Error(errMsg);
|
||||
return;
|
||||
@@ -1926,7 +1925,7 @@ export default defineComponent({
|
||||
name: "",
|
||||
function: searchObj.data.tempFunctionContent,
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
searchObj.data.tempFunctionContent =
|
||||
extractedObj.data.tempFunctionContent;
|
||||
@@ -1937,7 +1936,7 @@ export default defineComponent({
|
||||
name: "",
|
||||
function: "",
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
searchObj.data.tempFunctionContent = "";
|
||||
searchObj.meta.functionEditorPlaceholderFlag = true;
|
||||
@@ -2029,7 +2028,7 @@ export default defineComponent({
|
||||
saveViewLoader.value = true;
|
||||
updateSavedViews(
|
||||
savedViewSelectedName.value.view_id,
|
||||
savedViewSelectedName.value.view_name
|
||||
savedViewSelectedName.value.view_name,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
@@ -2048,7 +2047,7 @@ export default defineComponent({
|
||||
savedviewsService
|
||||
.delete(
|
||||
store.state.selectedOrganization.identifier,
|
||||
deleteViewID.value
|
||||
deleteViewID.value,
|
||||
)
|
||||
.then((res) => {
|
||||
if (res.status == 200) {
|
||||
@@ -2203,7 +2202,7 @@ export default defineComponent({
|
||||
searchObj.data.savedViews[index].payload = viewObj.data;
|
||||
searchObj.data.savedViews[index].view_name = viewName;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
$q.notify({
|
||||
@@ -2255,7 +2254,7 @@ export default defineComponent({
|
||||
const queryString = Object.entries(queryObj)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`,
|
||||
)
|
||||
.join("&");
|
||||
|
||||
@@ -2285,7 +2284,7 @@ export default defineComponent({
|
||||
const resetFilters = () => {
|
||||
if (searchObj.meta.sqlMode == true) {
|
||||
searchObj.data.query = `SELECT [FIELD_LIST] FROM "${searchObj.data.stream.selectedStream.join(
|
||||
","
|
||||
",",
|
||||
)}" ORDER BY ${store.state.zoConfig.timestamp_column} DESC`;
|
||||
if (
|
||||
searchObj.data.stream.interestingFieldList.length > 0 &&
|
||||
@@ -2293,12 +2292,12 @@ export default defineComponent({
|
||||
) {
|
||||
searchObj.data.query = searchObj.data.query.replace(
|
||||
"[FIELD_LIST]",
|
||||
searchObj.data.stream.interestingFieldList.join(",")
|
||||
searchObj.data.stream.interestingFieldList.join(","),
|
||||
);
|
||||
} else {
|
||||
searchObj.data.query = searchObj.data.query.replace(
|
||||
"[FIELD_LIST]",
|
||||
"*"
|
||||
"*",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -2343,7 +2342,7 @@ export default defineComponent({
|
||||
let favoriteViewsList = localSavedViews.value;
|
||||
if (favoriteViewsList.length > 0) {
|
||||
favoriteViewsList = favoriteViewsList.filter(
|
||||
(item) => item.view_id != row.view_id
|
||||
(item) => item.view_id != row.view_id,
|
||||
);
|
||||
// for (const [key, item] of favoriteViewsList.entries()) {
|
||||
// console.log(item, key);
|
||||
@@ -2620,7 +2619,7 @@ export default defineComponent({
|
||||
if (query.toLowerCase().includes("order by")) {
|
||||
const [beforeOrderBy, afterOrderBy] = queryIndexSplit(
|
||||
query,
|
||||
"order by"
|
||||
"order by",
|
||||
);
|
||||
query =
|
||||
beforeOrderBy.trim() +
|
||||
@@ -2631,7 +2630,7 @@ export default defineComponent({
|
||||
} else if (query.toLowerCase().includes("limit")) {
|
||||
const [beforeLimit, afterLimit] = queryIndexSplit(
|
||||
query,
|
||||
"limit"
|
||||
"limit",
|
||||
);
|
||||
query =
|
||||
beforeLimit.trim() + " AND " + filter + " limit" + afterLimit;
|
||||
@@ -2642,7 +2641,7 @@ export default defineComponent({
|
||||
if (query.toLowerCase().includes("order by")) {
|
||||
const [beforeOrderBy, afterOrderBy] = queryIndexSplit(
|
||||
query,
|
||||
"order by"
|
||||
"order by",
|
||||
);
|
||||
query =
|
||||
beforeOrderBy.trim() +
|
||||
@@ -2653,7 +2652,7 @@ export default defineComponent({
|
||||
} else if (query.toLowerCase().includes("limit")) {
|
||||
const [beforeLimit, afterLimit] = queryIndexSplit(
|
||||
query,
|
||||
"limit"
|
||||
"limit",
|
||||
);
|
||||
query =
|
||||
beforeLimit.trim() +
|
||||
|
||||
@@ -0,0 +1,660 @@
|
||||
// VRL Language Definition
|
||||
export const vrlLanguageDefinition = {
|
||||
defaultToken: "invalid",
|
||||
ignoreCase: true,
|
||||
tokenPostfix: ".vrl",
|
||||
|
||||
brackets: [
|
||||
{ open: "{", close: "}", token: "delimiter.curly" },
|
||||
{ open: "[", close: "]", token: "delimiter.square" },
|
||||
{ open: "(", close: ")", token: "delimiter.parenthesis" },
|
||||
],
|
||||
|
||||
regEx: /\/(?!\/\/)(?:[^\/\\]|\\.)*\/[igm]*/,
|
||||
|
||||
keywords: [
|
||||
"abort",
|
||||
"as",
|
||||
"break",
|
||||
"continue",
|
||||
"else",
|
||||
"false",
|
||||
"for",
|
||||
"if",
|
||||
"impl",
|
||||
"in",
|
||||
"let",
|
||||
"loop",
|
||||
"null",
|
||||
"return",
|
||||
"self",
|
||||
"std",
|
||||
"then",
|
||||
"this",
|
||||
"true",
|
||||
"type",
|
||||
"until",
|
||||
"use",
|
||||
"while",
|
||||
],
|
||||
|
||||
// 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})/,
|
||||
|
||||
// The main tokenizer for our languages
|
||||
tokenizer: {
|
||||
root: [
|
||||
// function invokes fallible
|
||||
[
|
||||
/([a-zA-Z_!]+)(\!)(\()/,
|
||||
{
|
||||
cases: {
|
||||
$3: ["keyword", "keyword", ""],
|
||||
},
|
||||
// log: 'in function invoke::found::\n\n$0'
|
||||
},
|
||||
],
|
||||
// function invokes
|
||||
[
|
||||
/([a-zA-Z_!]+)(\()/,
|
||||
{
|
||||
cases: {
|
||||
$2: ["keyword", ""],
|
||||
},
|
||||
// log: 'in function invoke::found::\n\n$0'
|
||||
},
|
||||
],
|
||||
|
||||
// rstrings
|
||||
[/r'[^']+'/, { token: "regexp" /*log: 'root_r_string::\n\n$0'*/ }],
|
||||
|
||||
// timestamps
|
||||
[
|
||||
/t'[^']+'/,
|
||||
{ token: "regexp" /*log: 'function_arg_r_string::\n\n$0'*/ },
|
||||
],
|
||||
|
||||
// field access, eg: .foo
|
||||
[
|
||||
/(\.[^\ \=]+)([\ |\=])/,
|
||||
{
|
||||
cases: {
|
||||
$2: ["entity", ""],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// sstrings
|
||||
[/s'[^']+'/, { token: "string" /*log: 'root_s_string::\n\n$0'*/ }],
|
||||
|
||||
// identifiers and keywords
|
||||
[/\@[a-zA-Z_]\w*/, "variable.predefined"],
|
||||
|
||||
[
|
||||
/[a-zA-Z_]\w*/,
|
||||
{
|
||||
cases: {
|
||||
this: "variable.predefined",
|
||||
"@keywords": { token: "keyword.$0" },
|
||||
|
||||
"@default": "",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// whitespace
|
||||
[/[ \t\r\n]+/, ""],
|
||||
|
||||
// Comments
|
||||
[/###/, "comment", "@comment"],
|
||||
[/#.*$/, "comment"],
|
||||
|
||||
// Function invokes
|
||||
|
||||
// regular expressions
|
||||
["///", { token: "regexp", next: "@hereregexp" }],
|
||||
|
||||
[/^(\s*)(@regEx)/, ["", "regexp"]],
|
||||
[/(\()(\s*)(@regEx)/, ["@brackets", "", "regexp"]],
|
||||
[/(\,)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\=)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\:)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\[)(\s*)(@regEx)/, ["@brackets", "", "regexp"]],
|
||||
[/(\!)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\&)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\|)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\?)(\s*)(@regEx)/, ["delimiter", "", "regexp"]],
|
||||
[/(\{)(\s*)(@regEx)/, ["@brackets", "", "regexp"]],
|
||||
[/(\;)(\s*)(@regEx)/, ["", "", "regexp"]],
|
||||
|
||||
// delimiters
|
||||
[
|
||||
/}/,
|
||||
{
|
||||
cases: {
|
||||
"$S2==interpolatedstring": {
|
||||
token: "string",
|
||||
next: "@pop",
|
||||
},
|
||||
"@default": "@brackets",
|
||||
},
|
||||
},
|
||||
],
|
||||
[/[{}()\[\]]/, "@brackets"],
|
||||
[/@symbols/, "delimiter"],
|
||||
|
||||
// numbers
|
||||
[/\d+[eE]([\-+]?\d+)?/, "number.float"],
|
||||
[/\d+\.\d+([eE][\-+]?\d+)?/, "number.float"],
|
||||
[/0[xX][0-9a-fA-F]+/, "number.hex"],
|
||||
[/0[0-7]+(?!\d)/, "number.octal"],
|
||||
[/\d+/, "number"],
|
||||
|
||||
// delimiter: after number because of .\d floats
|
||||
[/[,.]/, "delimiter"],
|
||||
|
||||
// strings:
|
||||
[/"""/, "string", '@herestring."""'],
|
||||
[/'''/, "string", "@herestring.'''"],
|
||||
[
|
||||
/"/,
|
||||
{
|
||||
cases: {
|
||||
"@eos": "string",
|
||||
"@default": { token: "string", next: '@string."' },
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
/'/,
|
||||
{
|
||||
cases: {
|
||||
"@eos": "string",
|
||||
"@default": { token: "string", next: "@string.'" },
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
string: [
|
||||
[/[^"'\#\\]+/, "string"],
|
||||
[/@escapes/, "string.escape"],
|
||||
[/\./, "string.escape.invalid"],
|
||||
[/\./, "string.escape.invalid"],
|
||||
|
||||
[
|
||||
/#{/,
|
||||
{
|
||||
cases: {
|
||||
'$S2=="': {
|
||||
token: "string",
|
||||
next: "root.interpolatedstring",
|
||||
},
|
||||
"@default": "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
/["']/,
|
||||
{
|
||||
cases: {
|
||||
"$#==$S2": { token: "string", next: "@pop" },
|
||||
"@default": "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
[/#/, "string"],
|
||||
],
|
||||
|
||||
herestring: [
|
||||
[
|
||||
/("""|''')/,
|
||||
{
|
||||
cases: {
|
||||
"$1==$S2": { token: "string", next: "@pop" },
|
||||
"@default": "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
[/[^#\\'"]+/, "string"],
|
||||
[/['"]+/, "string"],
|
||||
[/@escapes/, "string.escape"],
|
||||
[/\./, "string.escape.invalid"],
|
||||
|
||||
[/#{/, { token: "string.quote", next: "root.interpolatedstring" }],
|
||||
[/#/, "string"],
|
||||
],
|
||||
|
||||
comment: [
|
||||
[/[^#]+/, "comment"],
|
||||
[/###/, "comment", "@pop"],
|
||||
[/#/, "comment"],
|
||||
],
|
||||
|
||||
hereregexp: [
|
||||
[/[^\\\/#]+/, "regexp"],
|
||||
[/\\./, "regexp"],
|
||||
[/#.*$/, "comment"],
|
||||
["///[igm]*", { token: "regexp", next: "@pop" }],
|
||||
[/\//, "regexp"],
|
||||
],
|
||||
|
||||
function_arg: [
|
||||
[
|
||||
/([a-zA-Z_!]+)\(/,
|
||||
{
|
||||
cases: {
|
||||
$S1: {
|
||||
token: "keyword",
|
||||
next: "@push",
|
||||
log: "function_arg_nested::\n\n$0",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
// we copy the string highlighters from root and apply them to function arguments as well
|
||||
[/"""/, "string", '@herestring."""'],
|
||||
[/'''/, "string", "@herestring.'''"],
|
||||
[
|
||||
/"/,
|
||||
{
|
||||
cases: {
|
||||
"@eos": "string",
|
||||
"@default": { token: "string", next: '@string."' },
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
/'/,
|
||||
{
|
||||
cases: {
|
||||
"@eos": "string",
|
||||
"@default": { token: "string", next: "@string.'" },
|
||||
},
|
||||
},
|
||||
],
|
||||
// TODO: field access inside function parameters sometimes fails, eg: in a
|
||||
// newline func(.foo)
|
||||
// [/(\.)/, { token: "entity" }],
|
||||
// r strings
|
||||
[
|
||||
/r'[^']+'/,
|
||||
{ token: "regexp" /*log: 'function_arg_r_string::\n\n$0'*/ },
|
||||
],
|
||||
[
|
||||
/t'[^']+'/,
|
||||
{ token: "regexp" /*log: 'function_arg_r_string::\n\n$0'*/ },
|
||||
],
|
||||
// s strings
|
||||
[/s'[^']+'/, { token: "string" /*log: 'root_s_string::\n\n$0'*/ }],
|
||||
[
|
||||
/\)/,
|
||||
{ token: "", /*log: 'end_off_function_arg::\n\n$0',*/ next: "@pop" },
|
||||
],
|
||||
[
|
||||
/[\.\[\]\,\\\"\%\{\}\$\:\^\w]+/,
|
||||
{ token: "" /*log: 'function_arg_anything_else::\n\n$0'*/ },
|
||||
],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const vrlThemeDefinition = {
|
||||
base: "vs",
|
||||
inherit: true,
|
||||
rules: [
|
||||
{
|
||||
background: "ffffff",
|
||||
token: "",
|
||||
},
|
||||
{
|
||||
foreground: "d73a49",
|
||||
token: "vrl-function-invokes",
|
||||
},
|
||||
{
|
||||
foreground: "d73a49",
|
||||
token: "vrl-function-invokes-fallible",
|
||||
},
|
||||
{
|
||||
foreground: "6a737d",
|
||||
token: "comment",
|
||||
},
|
||||
{
|
||||
foreground: "6a737d",
|
||||
token: "punctuation.definition.comment",
|
||||
},
|
||||
{
|
||||
foreground: "6a737d",
|
||||
token: "string.comment",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "constant",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "entity.name.constant",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "variable.other.constant",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "variable.language",
|
||||
},
|
||||
{
|
||||
foreground: "6f42c1",
|
||||
token: "entity",
|
||||
},
|
||||
{
|
||||
foreground: "6f42c1",
|
||||
token: "entity.name",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
token: "variable.parameter.function",
|
||||
},
|
||||
{
|
||||
foreground: "22863a",
|
||||
token: "entity.name.tag",
|
||||
},
|
||||
{
|
||||
foreground: "d73a49",
|
||||
token: "keyword",
|
||||
},
|
||||
{
|
||||
foreground: "d73a49",
|
||||
token: "storage",
|
||||
},
|
||||
{
|
||||
foreground: "d73a49",
|
||||
token: "storage.type",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
token: "storage.modifier.package",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
token: "storage.modifier.import",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
token: "storage.type.java",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "punctuation.definition.string",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string punctuation.section.embedded source",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "support",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "meta.property-name",
|
||||
},
|
||||
{
|
||||
foreground: "e36209",
|
||||
token: "variable",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
token: "variable.other",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
fontStyle: "bold italic underline",
|
||||
token: "invalid.broken",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
fontStyle: "bold italic underline",
|
||||
token: "invalid.deprecated",
|
||||
},
|
||||
{
|
||||
foreground: "fafbfc",
|
||||
background: "b31d28",
|
||||
fontStyle: "italic underline",
|
||||
token: "invalid.illegal",
|
||||
},
|
||||
{
|
||||
foreground: "fafbfc",
|
||||
background: "d73a49",
|
||||
fontStyle: "italic underline",
|
||||
token: "carriage-return",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
fontStyle: "bold italic underline",
|
||||
token: "invalid.unimplemented",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
token: "message.error",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
token: "string source",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "string variable",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "source.regexp",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string.regexp",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string.regexp.character-class",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string.regexp constant.character.escape",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string.regexp source.ruby.embedded",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
token: "string.regexp string.regexp.arbitrary-repitition",
|
||||
},
|
||||
{
|
||||
foreground: "22863a",
|
||||
fontStyle: "bold",
|
||||
token: "string.regexp constant.character.escape",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "support.constant",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "support.variable",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "meta.module-reference",
|
||||
},
|
||||
{
|
||||
foreground: "735c0f",
|
||||
token: "markup.list",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
fontStyle: "bold",
|
||||
token: "markup.heading",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
fontStyle: "bold",
|
||||
token: "markup.heading entity.name",
|
||||
},
|
||||
{
|
||||
foreground: "22863a",
|
||||
token: "markup.quote",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
fontStyle: "italic",
|
||||
token: "markup.italic",
|
||||
},
|
||||
{
|
||||
foreground: "24292e",
|
||||
fontStyle: "bold",
|
||||
token: "markup.bold",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "markup.raw",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
background: "ffeef0",
|
||||
token: "markup.deleted",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
background: "ffeef0",
|
||||
token: "meta.diff.header.from-file",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
background: "ffeef0",
|
||||
token: "punctuation.definition.deleted",
|
||||
},
|
||||
{
|
||||
foreground: "22863a",
|
||||
background: "f0fff4",
|
||||
token: "markup.inserted",
|
||||
},
|
||||
{
|
||||
foreground: "22863a",
|
||||
background: "f0fff4",
|
||||
token: "meta.diff.header.to-file",
|
||||
},
|
||||
{
|
||||
foreground: "22863a",
|
||||
background: "f0fff4",
|
||||
token: "punctuation.definition.inserted",
|
||||
},
|
||||
{
|
||||
foreground: "e36209",
|
||||
background: "ffebda",
|
||||
token: "markup.changed",
|
||||
},
|
||||
{
|
||||
foreground: "e36209",
|
||||
background: "ffebda",
|
||||
token: "punctuation.definition.changed",
|
||||
},
|
||||
{
|
||||
foreground: "f6f8fa",
|
||||
background: "005cc5",
|
||||
token: "markup.ignored",
|
||||
},
|
||||
{
|
||||
foreground: "f6f8fa",
|
||||
background: "005cc5",
|
||||
token: "markup.untracked",
|
||||
},
|
||||
{
|
||||
foreground: "6f42c1",
|
||||
fontStyle: "bold",
|
||||
token: "meta.diff.range",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "meta.diff.header",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
fontStyle: "bold",
|
||||
token: "meta.separator",
|
||||
},
|
||||
{
|
||||
foreground: "005cc5",
|
||||
token: "meta.output",
|
||||
},
|
||||
{
|
||||
foreground: "586069",
|
||||
token: "brackethighlighter.tag",
|
||||
},
|
||||
{
|
||||
foreground: "586069",
|
||||
token: "brackethighlighter.curly",
|
||||
},
|
||||
{
|
||||
foreground: "586069",
|
||||
token: "brackethighlighter.round",
|
||||
},
|
||||
{
|
||||
foreground: "586069",
|
||||
token: "brackethighlighter.square",
|
||||
},
|
||||
{
|
||||
foreground: "586069",
|
||||
token: "brackethighlighter.angle",
|
||||
},
|
||||
{
|
||||
foreground: "586069",
|
||||
token: "brackethighlighter.quote",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
token: "brackethighlighter.unmatched",
|
||||
},
|
||||
{
|
||||
foreground: "b31d28",
|
||||
token: "sublimelinter.mark.error",
|
||||
},
|
||||
{
|
||||
foreground: "e36209",
|
||||
token: "sublimelinter.mark.warning",
|
||||
},
|
||||
{
|
||||
foreground: "959da5",
|
||||
token: "sublimelinter.gutter-mark",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
fontStyle: "underline",
|
||||
token: "constant.other.reference.link",
|
||||
},
|
||||
{
|
||||
foreground: "032f62",
|
||||
fontStyle: "underline",
|
||||
token: "string.other.link",
|
||||
},
|
||||
],
|
||||
colors: {
|
||||
"editor.foreground": "#24292e",
|
||||
"editor.background": "#ffffff",
|
||||
"editor.selectionBackground": "#c8c8fa",
|
||||
"editor.inactiveSelectionBackground": "#fafbfc",
|
||||
"editor.lineHighlightBackground": "#fafbfc",
|
||||
"editorCursor.foreground": "#24292e",
|
||||
"editorWhitespace.foreground": "#959da5",
|
||||
"editorIndentGuide.background": "#959da5",
|
||||
"editorIndentGuide.activeBackground": "#24292e",
|
||||
"editor.selectionHighlightBorder": "#fafbfc",
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user