mirror of
https://github.com/h-sphere/sql-seal.git
synced 2026-07-22 10:10:28 +00:00
feat: linking to other files from codeblock
This commit is contained in:
parent
cd0bcfd8e2
commit
03434dca10
9 changed files with 80 additions and 9 deletions
|
|
@ -1,3 +1,7 @@
|
|||
# 0.34.0 (2025-04-30)
|
||||
- feat: you can now navigate to linked CSV and JSON file sources
|
||||
- feat: improved support for minimal theme custom classes
|
||||
|
||||
# 0.33.0 (2025-04-09)
|
||||
- fix: better text links for images (by @satkowski)
|
||||
- fix: lists are now rendered properly (by @satkowski)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "sqlseal",
|
||||
"name": "SQLSeal",
|
||||
"version": "0.33.0",
|
||||
"version": "0.34.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Use SQL in your notes to query your vault files and CSV content.",
|
||||
"author": "hypersphere",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sqlseal",
|
||||
"version": "0.33.0",
|
||||
"version": "0.34.0",
|
||||
"description": "A plugin for Obsidian that allows you to run SQL queries on your notes.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { SQLSealLangDefinition } from '../grammar/parser';
|
|||
import { RendererRegistry } from '../renderer/rendererRegistry';
|
||||
import { Range } from '@codemirror/state';
|
||||
import { Decorator, highlighterOperation } from '../grammar/highlighterOperation';
|
||||
import { FilePathWidget } from './widgets/FilePathWidget';
|
||||
|
||||
const markDecorations = {
|
||||
blockFlag: Decoration.mark({ class: 'cm-sqlseal-block-flag' }),
|
||||
|
|
@ -85,12 +86,32 @@ export class SQLSealViewPlugin implements PluginValue {
|
|||
|
||||
if (decorations) {
|
||||
decorations.forEach(dec => {
|
||||
const decoration = markDecorations[dec.type as keyof typeof markDecorations];
|
||||
if (decoration) {
|
||||
builder.push(decoration.range(
|
||||
if (dec.type === 'filename') {
|
||||
// Get the actual filename text from the document
|
||||
const filePath = view.state.doc.sliceString(
|
||||
contentStart + dec.start,
|
||||
contentStart + dec.end
|
||||
);
|
||||
|
||||
console.log('FOUND FILENAME', filePath)
|
||||
|
||||
// Create widget decoration for the filename
|
||||
const widget = new FilePathWidget(filePath, this.app);
|
||||
builder.push(Decoration.replace({
|
||||
widget,
|
||||
inclusive: true
|
||||
}).range(
|
||||
contentStart + dec.start,
|
||||
contentStart + dec.end
|
||||
));
|
||||
} else {
|
||||
const decoration = markDecorations[dec.type as keyof typeof markDecorations];
|
||||
if (decoration) {
|
||||
builder.push(decoration.range(
|
||||
contentStart + dec.start,
|
||||
contentStart + dec.end
|
||||
));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
17
src/editorExtension/widgets/FilePathWidget.ts
Normal file
17
src/editorExtension/widgets/FilePathWidget.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { WidgetType } from "@codemirror/view";
|
||||
import { App, Notice } from "obsidian";
|
||||
|
||||
export class FilePathWidget extends WidgetType {
|
||||
constructor(private filePath: string, private app: App) {
|
||||
super();
|
||||
}
|
||||
|
||||
toDOM() {
|
||||
const link = document.createElement("a");
|
||||
link.textContent = this.filePath;
|
||||
link.href = this.filePath
|
||||
link.className = "internal-link";
|
||||
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ const nodes = new Map([
|
|||
['tableKeyword', { terminal: true, type: 'keyword' }],
|
||||
['fileOpening', { terminal: true, type: 'function' }],
|
||||
['tableOpening', { terminal: true, type: 'function' }],
|
||||
['filename', { terminal: true, type: 'identifier' }],
|
||||
['filename', { terminal: true, type: 'filename' }],
|
||||
['digit', { terminal: true, type: 'identifier' }],
|
||||
['tableDefinitionClosing', { terminal: true, type: 'function' }],
|
||||
['selectKeyword', { terminal: false, type: 'keyword' }],
|
||||
|
|
|
|||
|
|
@ -37,6 +37,18 @@ describe('Ohm parser', () => {
|
|||
})
|
||||
})
|
||||
|
||||
it('should parse table expression with name quoted', () => {
|
||||
expect(parse('TABLE x = file("abcdef.csv")', DEFAULT_VIEWS)).toEqual({
|
||||
query: '',
|
||||
tables: [{ arguments: ['abcdef.csv'], type: 'file', tableAlias: 'x' }],
|
||||
flags: {},
|
||||
renderer: {
|
||||
name: 'GRID',
|
||||
options: ''
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('should parse SELECT statement alone', () => {
|
||||
expect(parse('SELECT * FROM files', DEFAULT_VIEWS)).toEqual({
|
||||
query: 'SELECT * FROM files',
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ export const SQLSealLangDefinition = (views: ViewDefinition[], flags: readonly F
|
|||
| caseInsensitive<"EXPLAIN"> -- explain
|
||||
${flags.length ? '| ExtraFlags -- extraFlags' : ''}
|
||||
TableExpression = tableKeyword identifier "=" TableDefinition
|
||||
TableDefinition = fileOpening NonemptyListOf<listElement, ","> tableDefinitionClosing -- file
|
||||
TableDefinition = fileOpening TableFileExpressionArgs tableDefinitionClosing -- file
|
||||
| tableOpening NonemptyListOf<listElement, ","> tableDefinitionClosing -- mdtable
|
||||
TableFileExpressionArgs = filename ("," NonemptyListOf<listElement, ",">)?
|
||||
identifier = (alnum | "_")+
|
||||
filename = (alnum | "." | "-" | space | "_" | "/" | "\\" | "$" | "[" | "]" | "\"")+
|
||||
fileOpening = caseInsensitive<"file(">
|
||||
|
|
@ -109,10 +110,18 @@ const generateSemantic = (grammar: ohm.Grammar) => {
|
|||
},
|
||||
TableDefinition_file: (_file, args, _close) => {
|
||||
return {
|
||||
arguments: args.asIteration().children.map((c: ohm.Node) => c.toObject().trim()),
|
||||
arguments: args.toObject(),
|
||||
type: 'file'
|
||||
}
|
||||
},
|
||||
TableFileExpressionArgs: (filename, _sep, rest) => {
|
||||
// ...rest.asIteration().children.map((c: ohm.Node) => c.toObject().trim())
|
||||
let remaining = []
|
||||
if (rest.children.length) {
|
||||
remaining = rest.children[0].asIteration().children.map((c: ohm.Node) => c.toObject().trim())
|
||||
}
|
||||
return [filename.toObject(), ...remaining]
|
||||
},
|
||||
TableDefinition_mdtable: (_file, args, _close) => {
|
||||
return {
|
||||
arguments: args.asIteration().children.map((c: ohm.Node) => c.toObject().trim()),
|
||||
|
|
@ -136,6 +145,13 @@ const generateSemantic = (grammar: ohm.Grammar) => {
|
|||
},
|
||||
listElement_quoted: (_q, value, _q2) => value.sourceString,
|
||||
listElement_unquoted: (v) => v.sourceString,
|
||||
filename: (v) => {
|
||||
const f = v.sourceString
|
||||
if (f.length && f[0] === '"' && f[f.length - 1] === '"') {
|
||||
return f.substring(1, f.length - 1)
|
||||
}
|
||||
return v.sourceString.trim()
|
||||
},
|
||||
_terminal() {
|
||||
return this.sourceString
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,5 +59,6 @@
|
|||
"0.30.1": "0.15.0",
|
||||
"0.31.0": "0.15.0",
|
||||
"0.32.0": "0.15.0",
|
||||
"0.33.0": "0.15.0"
|
||||
"0.33.0": "0.15.0",
|
||||
"0.34.0": "0.15.0"
|
||||
}
|
||||
Loading…
Reference in a new issue