Skip to content

Commit

Permalink
Migrate brace -> ace-code@latest
Browse files Browse the repository at this point in the history
  • Loading branch information
xingrz committed Mar 27, 2024
1 parent 11893f5 commit 64d5a46
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 105 deletions.
15 changes: 9 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lint": "eslint --ext .ts,.vue src"
},
"dependencies": {
"brace": "^0.11.1",
"ace-code": "^1.32.8",
"md5": "^2.3.0",
"pinia": "^2.1.7",
"qs": "^6.12.0",
Expand Down
61 changes: 31 additions & 30 deletions src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,11 @@ import {
useCssModule,
} from 'vue';
import brace, {
type Position,
type IEditSession,
type Editor,
} from 'brace';
import 'brace/theme/tomorrow';
import 'brace/ext/language_tools';
import '@/editor/rdt';
import { Ace, edit as aceEdit, config as aceConfig } from 'ace-code';
import 'ace-code/src/ext/language_tools';
import 'ace-code/styles/ace.css';
import 'ace-code/styles/theme/tomorrow.css';
import * as RDT from '@/editor/rdt';
import type ISelection from '@/types/selection';
import type IIcon from '@/types/icon';
Expand All @@ -40,7 +37,7 @@ const props = defineProps<{
}>();
const holder = ref<HTMLElement>();
const editor = ref<Editor>();
const editor = ref<Ace.Editor>();
const content = defineModel<string>('content');
bindEditorValue(editor, content);
Expand All @@ -51,15 +48,21 @@ bindEditorSelection(editor, selection);
const scroll = defineModel<number>('scroll');
bindEditorScroll(editor, scroll);
onMounted(() => {
editor.value = brace.edit(holder.value!);
editor.value.$blockScrolling = Infinity;
const aceModules: Record<string, unknown> = {
'ace/theme/tomorrow': { cssClass: 'ace-tomorrow' },
'ace/mode/rdt': RDT,
};
const session = editor.value.getSession();
session.setMode('ace/mode/rdt');
aceConfig.setLoader((path, callback) => {
callback(null, aceModules[path]);
});
editor.value.setTheme('ace/theme/tomorrow');
editor.value.setOption('enableLiveAutocompletion', [{ getCompletions, getDocTooltip }]);
onMounted(() => {
editor.value = aceEdit(holder.value!, {
theme: 'ace/theme/tomorrow',
mode: 'ace/mode/rdt',
enableLiveAutocompletion: [new Completer()],
});
});
onBeforeUnmount(() => {
Expand All @@ -70,21 +73,19 @@ onBeforeUnmount(() => {
const holderSize = useClientSize(holder);
watch(holderSize, () => editor.value?.resize());
function getCompletions(
_editor: Editor,
_session: IEditSession,
_pos: Position,
_prefix: string,
callback: (err: Error | null, completions?: { value: string }[]) => void
): void {
callback(null, Object.keys(props.icons)
.filter((icon) => !!props.icons[icon])
.map((icon) => ({ value: icon })));
}
class Completer implements Ace.Completer {
private style = useCssModule();
getCompletions(_editor: Ace.Editor, _session: Ace.EditSession, _pos: Ace.Point, _prefix: string, callback: Ace.CompleterCallback): void {
callback(null, Object.keys(props.icons)
.filter((icon) => !!props.icons[icon])
.map((icon) => ({ value: icon })));
}
const style = useCssModule();
function getDocTooltip(item: { value: string; docHTML: string }): void {
item.docHTML = `<img src="${props.icons[item.value]?.data}" class="${style.preview}" />`;
getDocTooltip(item: Ace.ValueCompletion): string | Ace.ValueCompletion | undefined {
item.docHTML = `<img src="${props.icons[item.value]?.data}" class="${this.style.preview}" />`;
return;
}
}
</script>

Expand Down
4 changes: 2 additions & 2 deletions src/composables/bindEditorScroll.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { watch, type Ref } from 'vue';
import type { Editor } from 'brace';
import type { Ace } from 'ace-code';

import onRefAssigned from './onRefAssigned';

export default function bindEditorScroll(editor: Ref<Editor | undefined>, scroll: Ref<number | undefined>): void {
export default function bindEditorScroll(editor: Ref<Ace.Editor | undefined>, scroll: Ref<number | undefined>): void {
onRefAssigned(editor, (value) => {
const session = value.getSession();
session.on('changeScrollTop', () => {
Expand Down
14 changes: 7 additions & 7 deletions src/composables/bindEditorSelection.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { watch, type Ref } from 'vue';
import type { Editor, Range, VirtualRenderer } from 'brace';
import type { Ace } from 'ace-code';

import onRefAssigned from './onRefAssigned';

import type ISelection from '@/types/selection';

interface Renderer extends VirtualRenderer {
interface Renderer extends Ace.VirtualRenderer {
scrollTop: number;
scrollSelectionIntoView(): void;
}

export default function bindEditorSelection(editorRef: Ref<Editor | undefined>, selection: Ref<ISelection | undefined>): void {
export default function bindEditorSelection(editorRef: Ref<Ace.Editor | undefined>, selection: Ref<ISelection | undefined>): void {
onRefAssigned(editorRef, (editor) => {
applyRange(editor, toRange({ row: 0, offset: 0, length: 0 }));

Expand All @@ -32,22 +32,22 @@ export default function bindEditorSelection(editorRef: Ref<Editor | undefined>,
});
}

function toRange({ row, offset, length }: Omit<ISelection, 'from'>): Range {
function toRange({ row, offset, length }: Omit<ISelection, 'from'>): Ace.Range {
return {
start: { row: row, column: offset },
end: { row: row, column: offset + length },
} as Range;
} as Ace.Range;
}

function applyRange(editor: Editor, range: Range) {
function applyRange(editor: Ace.Editor, range: Ace.Range) {
const renderer = editor.renderer as Renderer;
editor.selection.setRange(range, false);
renderer.scrollToX(0);
renderer.scrollSelectionIntoView();
editor.focus();
}

function toSelection(range: Range, from: ISelection['from']): ISelection {
function toSelection(range: Ace.Range, from: ISelection['from']): ISelection {
return {
row: range.start.row,
offset: range.start.column,
Expand Down
4 changes: 2 additions & 2 deletions src/composables/bindEditorValue.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Ref } from 'vue';
import type { Editor } from 'brace';
import type { Ace } from 'ace-code';

import onRefAssigned from './onRefAssigned';

export default function bindEditorValue(editor: Ref<Editor | undefined>, val: Ref<string | undefined>): void {
export default function bindEditorValue(editor: Ref<Ace.Editor | undefined>, val: Ref<string | undefined>): void {
onRefAssigned(editor, (value) => {
if (val.value) {
value.setValue(val.value);
Expand Down
57 changes: 0 additions & 57 deletions src/editor/rdt.js

This file was deleted.

31 changes: 31 additions & 0 deletions src/editor/rdt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Mode as TextMode } from 'ace-code/src/mode/text';
import { TextHighlightRules } from 'ace-code/src/mode/text_highlight_rules';

export class RDTHighlightRules extends TextHighlightRules {
constructor() {
super();
this.normalizeRules();
}

$rules = {
start: [
{
token: 'keyword.operator.rdt',
regex: '(?:\\\\|!~)',
},
{
token: 'punctuation.definition.string',
regex: '(?:~~.*$)',
},
{
token: 'keyword.control.statement.rdt',
regex: '(?:[^\\\\(~~)(!~)]+)',
},
],
};
}

export class Mode extends TextMode {
$id = 'ace/mode/rdt';
HighlightRules = RDTHighlightRules;
}

0 comments on commit 64d5a46

Please sign in to comment.