mirror of
https://github.com/h-sphere/sql-seal.git
synced 2026-07-22 10:10:28 +00:00
123 lines
No EOL
4.2 KiB
TypeScript
123 lines
No EOL
4.2 KiB
TypeScript
import { EditorView, ViewPlugin, ViewUpdate, DecorationSet, Decoration, WidgetType } from "@codemirror/view";
|
|
import { RangeSetBuilder } from "@codemirror/state";
|
|
import { syntaxTree } from "@codemirror/language";
|
|
import { App } from "obsidian";
|
|
import { SqlSealDatabase } from "../database/database";
|
|
import { Sync } from "../datamodel/sync";
|
|
import { SqlSealInlineHandler } from "../codeblockHandler/inline/InlineCodeHandler";
|
|
import { InlineProcessor } from "../codeblockHandler/inline/InlineProcessor";
|
|
|
|
export function createSqlSealEditorExtension(
|
|
app: App,
|
|
db: SqlSealDatabase,
|
|
sync: Sync,
|
|
) {
|
|
return ViewPlugin.fromClass(
|
|
class {
|
|
decorations: DecorationSet;
|
|
inlineHandler: SqlSealInlineHandler;
|
|
|
|
constructor(view: EditorView) {
|
|
this.inlineHandler = new SqlSealInlineHandler(app, db, sync);
|
|
this.decorations = this.buildDecorations(view);
|
|
}
|
|
|
|
update(update: ViewUpdate) {
|
|
if (update.docChanged || update.viewportChanged || update.selectionSet) {
|
|
this.decorations = this.buildDecorations(update.view);
|
|
}
|
|
}
|
|
|
|
buildDecorations(view: EditorView) {
|
|
const builder = new RangeSetBuilder<Decoration>();
|
|
const tree = syntaxTree(view.state);
|
|
|
|
tree.iterate({
|
|
enter: ({ type, from, to }) => {
|
|
if (type.name.includes("inline-code")) {
|
|
const text = view.state.doc.sliceString(from, to);
|
|
if (text.startsWith('S>')) {
|
|
// Check if we're currently editing this specific inline code
|
|
const isEditing = view.hasFocus &&
|
|
view.state.selection.ranges.some(range =>
|
|
range.from >= from && range.to <= to);
|
|
|
|
if (!isEditing) {
|
|
// Create a replacement decoration
|
|
builder.add(from, to, Decoration.replace({
|
|
widget: new SqlSealInlineWidget(
|
|
text,
|
|
this.inlineHandler,
|
|
view.state.doc.lineAt(from).number,
|
|
app
|
|
)
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return builder.finish();
|
|
}
|
|
},
|
|
{
|
|
decorations: (v) => v.decorations
|
|
}
|
|
);
|
|
}
|
|
|
|
class SqlSealInlineWidget extends WidgetType {
|
|
constructor(
|
|
private query: string,
|
|
private handler: SqlSealInlineHandler,
|
|
private line: number,
|
|
private app: App
|
|
) {
|
|
super();
|
|
}
|
|
|
|
eq(other: SqlSealInlineWidget): boolean {
|
|
return (
|
|
other.query === this.query &&
|
|
other.line === this.line
|
|
);
|
|
}
|
|
|
|
processor: InlineProcessor
|
|
|
|
toDOM(): HTMLElement {
|
|
const container = document.createElement('span');
|
|
container.classList.add('sqlseal-inline-result');
|
|
|
|
// Create a new context for the inline query
|
|
const ctx = {
|
|
sourcePath: this.app.workspace.getActiveFile()?.path ?? '',
|
|
addChild: () => {},
|
|
getSectionInfo: () => ({
|
|
lineStart: this.line,
|
|
lineEnd: this.line
|
|
})
|
|
};
|
|
|
|
// Show the original query on hover
|
|
container.setAttribute('aria-label', this.query);
|
|
container.classList.add('has-tooltip');
|
|
|
|
this.processor = this.handler.instantiateProcessor(this.query, container, ctx.sourcePath)
|
|
|
|
this.processor.load()
|
|
return container;
|
|
}
|
|
|
|
destroy(dom: HTMLElement): void {
|
|
if (this.processor) {
|
|
this.processor.unload()
|
|
}
|
|
}
|
|
|
|
ignoreEvent(event: Event): boolean {
|
|
// Return false to allow events to propagate (important for editing)
|
|
return false;
|
|
}
|
|
} |