Skip to content

Commit

Permalink
feat: improve code editor with better auto complete and coloring
Browse files Browse the repository at this point in the history
  • Loading branch information
invisal committed Apr 17, 2024
1 parent 09e14fa commit 25fcf99
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 3 deletions.
3 changes: 3 additions & 0 deletions gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@
"react-dom": "^18.2.0"
},
"dependencies": {
"@codemirror/autocomplete": "^6.16.0",
"@codemirror/commands": "^6.3.3",
"@codemirror/lang-sql": "^6.5.5",
"@codemirror/language": "^6.10.1",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.26.3",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
Expand Down
34 changes: 33 additions & 1 deletion gui/src/components/sql-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ import CodeMirror, {
EditorView,
ReactCodeMirrorRef,
} from "@uiw/react-codemirror";
import {
acceptCompletion,
completionStatus,
startCompletion,
} from "@codemirror/autocomplete";
import { sql, SQLite } from "@codemirror/lang-sql";
import { forwardRef, KeyboardEventHandler, useMemo } from "react";

import { defaultKeymap } from "@codemirror/commands";
import { defaultKeymap, insertTab } from "@codemirror/commands";
import { keymap } from "@codemirror/view";
import { KEY_BINDING } from "@gui/lib/key-matcher";
import useCodeEditorTheme from "./use-editor-theme";
import createSQLTableNameHighlightPlugin from "./sql-tablename-highlight";

interface SqlEditorProps {
value: string;
Expand Down Expand Up @@ -37,13 +43,38 @@ const SqlEditor = forwardRef<ReactCodeMirrorRef, SqlEditorProps>(
) {
const theme = useCodeEditorTheme();

const tableNameHighlightPlugin = useMemo(() => {
if (schema) {
return createSQLTableNameHighlightPlugin(Object.keys(schema));
}
return createSQLTableNameHighlightPlugin([]);
}, [schema]);

const keyExtensions = useMemo(() => {
return keymap.of([
{
key: KEY_BINDING.run.toCodeMirrorKey(),
preventDefault: true,
run: () => true,
},
{
key: "Tab",
preventDefault: true,
run: (target) => {
if (completionStatus(target.state) === "active") {
acceptCompletion(target);
} else {
insertTab(target);
}
return true;
},
},
{
key: "Ctrl-Space",
mac: "Cmd-i",
preventDefault: true,
run: startCompletion,
},
...defaultKeymap,
]);
}, []);
Expand Down Expand Up @@ -72,6 +103,7 @@ const SqlEditor = forwardRef<ReactCodeMirrorRef, SqlEditorProps>(
dialect: SQLite,
schema,
}),
tableNameHighlightPlugin,
EditorView.updateListener.of((state) => {
const pos = state.state.selection.main.head;
const line = state.state.doc.lineAt(pos);
Expand Down
67 changes: 67 additions & 0 deletions gui/src/components/sql-editor/sql-tablename-highlight.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
EditorView,
ViewPlugin,
Decoration,
DecorationSet,
ViewUpdate,
} from "@codemirror/view";
import { Range } from "@codemirror/state";
import { syntaxTree } from "@codemirror/language";

const underlineMark = Decoration.mark({ class: "cm-table-name" });

export default function createSQLTableNameHighlightPlugin(
tableNameList: string[]
) {
const tableNameSet = new Set(
tableNameList.map((table) => table.toLowerCase())
);

function highlightTableName(view: EditorView) {
const decorationList: Range<Decoration>[] = [];

for (const { from, to } of view.visibleRanges) {
syntaxTree(view.state).iterate({
from,
to,
enter: (node) => {
if (node.name == "Identifier") {
const word = view.state.doc
.sliceString(node.from, node.to)
.toLowerCase();

const lastChar = node.node.prevSibling
? view.state.doc
.sliceString(
node.node.prevSibling.from,
node.node.prevSibling.to
)
.toLowerCase()
: "";

if (tableNameSet.has(word) && lastChar !== ".") {
decorationList.push(underlineMark.range(node.from, node.to));
}
}
},
});
}

return Decoration.set(decorationList);
}

return ViewPlugin.fromClass(
class {
decorations: DecorationSet;

constructor(view: EditorView) {
this.decorations = highlightTableName(view);
}

update(update: ViewUpdate) {
this.decorations = highlightTableName(update.view);
}
},
{ decorations: (v) => v.decorations }
);
}
7 changes: 6 additions & 1 deletion gui/src/contexts/schema-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function useSchema() {
}

export function SchemaProvider({ children }: Readonly<PropsWithChildren>) {
const { updateTableList } = useAutoComplete();
const { updateTableList, updateTableSchema } = useAutoComplete();
const [error, setError] = useState<string>();
const [schemaItems, setSchemaItems] = useState<DatabaseSchemaItem[]>([]);
const [loading, setLoading] = useState(true);
Expand All @@ -49,6 +49,11 @@ export function SchemaProvider({ children }: Readonly<PropsWithChildren>) {

setSchemaItems(sortedTableList);
updateTableList(tableList.map((table) => table.name));
for (const table of tableList) {
if (table.tableSchema) {
updateTableSchema(table.name, table.tableSchema.columns);
}
}

setError(undefined);
setLoading(false);
Expand Down
1 change: 1 addition & 0 deletions gui/src/drivers/base-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface DatabaseSchemaItem {
type: "table" | "trigger" | "view";
name: string;
tableName?: string;
tableSchema?: DatabaseTableSchema;
}

export interface DatabaseTableColumn {
Expand Down
10 changes: 9 additions & 1 deletion gui/src/drivers/sqlite-base-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ export abstract class SqliteLikeBaseDriver extends BaseDriver {

for (const row of rows) {
if (row.type === "table") {
tmp.push({ type: "table", name: row.name });
try {
tmp.push({
type: "table",
name: row.name,
tableSchema: parseCreateTableScript(row.sql),
});
} catch {
tmp.push({ type: "table", name: row.name });
}
} else if (row.type === "trigger") {
tmp.push({ type: "trigger", name: row.name, tableName: row.tbl_name });
} else if (row.type === "view") {
Expand Down
8 changes: 8 additions & 0 deletions gui/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@
}
}

/* ------------------------------- */
.cm-table-name {
color: #e84393;
}

.dark .cm-table-name {
color: #fd79a8;
}
/* ------------------------------- */

.libsql-window-tab .libsql-window-close {
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit 25fcf99

Please sign in to comment.