|
|
@@ -24,9 +24,7 @@
|
|
|
|
|
|
<script lang="ts">
|
|
|
import $ from 'jquery';
|
|
|
- import Vue from 'vue';
|
|
|
- import Component from 'vue-class-component';
|
|
|
- import { Prop, Watch } from 'vue-property-decorator';
|
|
|
+ import { defineComponent } from 'vue';
|
|
|
|
|
|
import { formatSql } from 'apps/editor/api';
|
|
|
import { getAceMode } from 'ext/aceHelper';
|
|
|
@@ -40,128 +38,150 @@
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
const getAce = (): Ace => (window as any).ace;
|
|
|
|
|
|
- @Component
|
|
|
- export default class SqlText extends Vue {
|
|
|
- @Prop({ required: false })
|
|
|
- dialect = 'hive';
|
|
|
- @Prop({ required: false })
|
|
|
- value = '';
|
|
|
- @Prop({ required: false })
|
|
|
- format = false;
|
|
|
- @Prop({ required: false })
|
|
|
- enableOverflow = false;
|
|
|
- @Prop({ required: false })
|
|
|
- splitLines = false;
|
|
|
-
|
|
|
- @Watch('value')
|
|
|
- async renderAce(): Promise<void> {
|
|
|
- if (!this.value) {
|
|
|
- return;
|
|
|
+ export default defineComponent({
|
|
|
+ props: {
|
|
|
+ dialect: {
|
|
|
+ type: String,
|
|
|
+ default: 'hive'
|
|
|
+ },
|
|
|
+ value: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ format: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ enableOverflow: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ splitLines: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
}
|
|
|
- const ace = getAce();
|
|
|
- const tokenizer = ace.require('ace/tokenizer');
|
|
|
- const text = ace.require('ace/layer/text');
|
|
|
- const config = ace.require('ace/config');
|
|
|
-
|
|
|
- const Tokenizer = tokenizer.Tokenizer;
|
|
|
- let ruleModule;
|
|
|
- try {
|
|
|
- ruleModule = ace.require(`${getAceMode(this.dialect)}_highlight_rules`);
|
|
|
- } catch (err) {}
|
|
|
- const Rules =
|
|
|
- ruleModule && Object.keys(ruleModule).length === 1
|
|
|
- ? ruleModule[Object.keys(ruleModule)[0]]
|
|
|
- : ace.require(`sql_highlight_rules`).SqlHighlightRules;
|
|
|
- const res: string[] = [];
|
|
|
-
|
|
|
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
|
- config.loadModule(['theme', hueLocalStorage('hue.ace.theme') || 'ace/theme/hue']);
|
|
|
-
|
|
|
- const Text = text.Text;
|
|
|
-
|
|
|
- const tok = new Tokenizer(new Rules().getRules());
|
|
|
-
|
|
|
- let editorText = this.value;
|
|
|
- if (this.format) {
|
|
|
- editorText = await formatSql({ statements: this.value, silenceErrors: true });
|
|
|
+ },
|
|
|
+
|
|
|
+ watch: {
|
|
|
+ async value(): Promise<void> {
|
|
|
+ this.renderAce();
|
|
|
}
|
|
|
- const lines = editorText.split('\n');
|
|
|
-
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
- const renderSimpleLine = (txt: any, stringBuilder: string[], tokens: any[]) => {
|
|
|
- let screenColumn = 0;
|
|
|
- let token = tokens[0];
|
|
|
- let value = token.value;
|
|
|
- if (value) {
|
|
|
- try {
|
|
|
- screenColumn = txt.$renderToken(stringBuilder, screenColumn, token, value);
|
|
|
- } catch (e) {
|
|
|
- console.warn(
|
|
|
- value,
|
|
|
- 'Failed to get screen column due to some parsing errors, skip rendering.'
|
|
|
- );
|
|
|
- }
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted(): void {
|
|
|
+ this.renderAce();
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ async renderAce(): Promise<void> {
|
|
|
+ if (!this.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const ace = getAce();
|
|
|
+ const tokenizer = ace.require('ace/tokenizer');
|
|
|
+ const text = ace.require('ace/layer/text');
|
|
|
+ const config = ace.require('ace/config');
|
|
|
+
|
|
|
+ const Tokenizer = tokenizer.Tokenizer;
|
|
|
+ let ruleModule;
|
|
|
+ try {
|
|
|
+ ruleModule = ace.require(`${getAceMode(this.dialect)}_highlight_rules`);
|
|
|
+ } catch (err) {}
|
|
|
+ const Rules =
|
|
|
+ ruleModule && Object.keys(ruleModule).length === 1
|
|
|
+ ? ruleModule[Object.keys(ruleModule)[0]]
|
|
|
+ : ace.require(`sql_highlight_rules`).SqlHighlightRules;
|
|
|
+ const res: string[] = [];
|
|
|
+
|
|
|
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
|
+ config.loadModule(['theme', hueLocalStorage('hue.ace.theme') || 'ace/theme/hue']);
|
|
|
+
|
|
|
+ const Text = text.Text;
|
|
|
+
|
|
|
+ const tok = new Tokenizer(new Rules().getRules());
|
|
|
+
|
|
|
+ let editorText = this.value;
|
|
|
+ if (this.format) {
|
|
|
+ editorText = await formatSql({ statements: this.value, silenceErrors: true });
|
|
|
}
|
|
|
- for (let i = 1; i < tokens.length; i++) {
|
|
|
- token = tokens[i];
|
|
|
- value = token.value;
|
|
|
- try {
|
|
|
- screenColumn = txt.$renderToken(stringBuilder, screenColumn, token, value);
|
|
|
- } catch (e) {
|
|
|
- if (console && console.warn) {
|
|
|
+ const lines = editorText.split('\n');
|
|
|
+
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
+ const renderSimpleLine = (txt: any, stringBuilder: string[], tokens: any[]) => {
|
|
|
+ let screenColumn = 0;
|
|
|
+ let token = tokens[0];
|
|
|
+ let value = token.value;
|
|
|
+ if (value) {
|
|
|
+ try {
|
|
|
+ screenColumn = txt.$renderToken(stringBuilder, screenColumn, token, value);
|
|
|
+ } catch (e) {
|
|
|
console.warn(
|
|
|
value,
|
|
|
- 'This token has some parsing errors and it has been rendered without highlighting.'
|
|
|
+ 'Failed to get screen column due to some parsing errors, skip rendering.'
|
|
|
);
|
|
|
}
|
|
|
- stringBuilder.push(value);
|
|
|
- screenColumn = screenColumn + value.length;
|
|
|
}
|
|
|
+ for (let i = 1; i < tokens.length; i++) {
|
|
|
+ token = tokens[i];
|
|
|
+ value = token.value;
|
|
|
+ try {
|
|
|
+ screenColumn = txt.$renderToken(stringBuilder, screenColumn, token, value);
|
|
|
+ } catch (e) {
|
|
|
+ if (console && console.warn) {
|
|
|
+ console.warn(
|
|
|
+ value,
|
|
|
+ 'This token has some parsing errors and it has been rendered without highlighting.'
|
|
|
+ );
|
|
|
+ }
|
|
|
+ stringBuilder.push(value);
|
|
|
+ screenColumn = screenColumn + value.length;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ let additionalClass = 'pull-left';
|
|
|
+ if (!this.splitLines && !this.format) {
|
|
|
+ additionalClass = 'pull-left';
|
|
|
+ } else if (this.format) {
|
|
|
+ additionalClass = 'ace-highlight-pre';
|
|
|
}
|
|
|
- };
|
|
|
|
|
|
- let additionalClass = 'pull-left';
|
|
|
- if (!this.splitLines && !this.format) {
|
|
|
- additionalClass = 'pull-left';
|
|
|
- } else if (this.format) {
|
|
|
- additionalClass = 'ace-highlight-pre';
|
|
|
- }
|
|
|
+ lines.forEach(line => {
|
|
|
+ const renderedTokens: string[] = [];
|
|
|
+ const tokens = tok.getLineTokens(line);
|
|
|
|
|
|
- lines.forEach(line => {
|
|
|
- const renderedTokens: string[] = [];
|
|
|
- const tokens = tok.getLineTokens(line);
|
|
|
+ if (tokens && tokens.tokens.length) {
|
|
|
+ renderSimpleLine(
|
|
|
+ new Text(document.createElement('div')),
|
|
|
+ renderedTokens,
|
|
|
+ tokens.tokens
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
- if (tokens && tokens.tokens.length) {
|
|
|
- renderSimpleLine(new Text(document.createElement('div')), renderedTokens, tokens.tokens);
|
|
|
+ res.push(
|
|
|
+ '<div class="ace_line ' +
|
|
|
+ additionalClass +
|
|
|
+ '">' +
|
|
|
+ renderedTokens.join('') +
|
|
|
+ ' </div>'
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ const overflowStyle = this.enableOverflow ? ' overflow: initial !important;' : '';
|
|
|
+ //TODO - Move inline styles to CSS class
|
|
|
+ this.$el.innerHTML = `
|
|
|
+ <div class="ace_editor ace-hue" style="background-color: transparent; ${overflowStyle}">
|
|
|
+ <div class="ace_layer" style="position: static; ${overflowStyle}">${res.join('')}</div>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+
|
|
|
+ if (this.enableOverflow) {
|
|
|
+ $(this.$el).css({ overflow: 'auto' });
|
|
|
}
|
|
|
-
|
|
|
- res.push(
|
|
|
- '<div class="ace_line ' +
|
|
|
- additionalClass +
|
|
|
- '">' +
|
|
|
- renderedTokens.join('') +
|
|
|
- ' </div>'
|
|
|
- );
|
|
|
- });
|
|
|
-
|
|
|
- const overflowStyle = this.enableOverflow ? ' overflow: initial !important;' : '';
|
|
|
- //TODO - Move inline styles to CSS class
|
|
|
- this.$el.innerHTML = `
|
|
|
- <div class="ace_editor ace-hue" style="background-color: transparent; ${overflowStyle}">
|
|
|
- <div class="ace_layer" style="position: static; ${overflowStyle}">${res.join('')}</div>
|
|
|
- </div>
|
|
|
- `;
|
|
|
-
|
|
|
- if (this.enableOverflow) {
|
|
|
- $(this.$el).css({ overflow: 'auto' });
|
|
|
+ $(this.$el).find('.ace_invisible_space').remove();
|
|
|
}
|
|
|
- $(this.$el).find('.ace_invisible_space').remove();
|
|
|
}
|
|
|
-
|
|
|
- mounted(): void {
|
|
|
- this.renderAce();
|
|
|
- }
|
|
|
- }
|
|
|
+ });
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped></style>
|