Hi,
I have plugin for Jupyter lab that creates an inner language, to support SQL highlighting and autocomplete inside python strings in specific functions, for example:
my_module.exec("""
SELECT * FROM test -- this is highlighted
""")
When I press Ctrl+/ inside the sql string it adds an sql comment (ā), which is good, but in other regular python cells when I press Ctrl + / no comment is added and nothing happens, I expected a hash comment to be added like the original behaviour.
Here is how iām defining my mixed language:
import {PostgreSQL, sql, SQLDialect} from "@codemirror/lang-sql";
import {parser as pythonParser} from "@lezer/python";
import {parseMixed} from "@lezer/common";
import {LRParser} from "@lezer/lr";
import {styleTags, tags} from "@lezer/highlight";
import {LRLanguage} from "@codemirror/language";
import {Extension} from "@codemirror/state";
let mySQLSnowflakeDialect = SQLDialect.define({
charSetCasts: true,
doubleDollarQuotedStrings: true,
operatorChars: "+-*/<>=~!@#%^&|`?",
specialVar: "",
keywords: PostgreSQL.spec.keywords + snowflakeKeywords.join(" "),
types: PostgreSQL.spec.types + snowflakeFunctions.join(" "),
slashComments: true,
});
const config = {
dialect: mySQLSnowflakeDialect
}
const sqlLang = sql(config);
function mySQLPython() {
const mixedPythonLanguage = pythonParser.configure({
wrap: parseMixed((node, input) => {
const nodeIsAcceptedStringType =
node.name === 'String' || node.name === 'FormatString';
if (
!nodeIsAcceptedStringType ||
node.node.parent?.name !== 'ArgList' ||
node.node.parent?.parent?.name !== 'CallExpression'
) {
return null;
}
const functionExpression = node.node.parent.parent;
const ismySQLSearch =
input.chunk(functionExpression.from).match(/^my_module.exec/i) !== null;
if (!ismySQLSearch) {
return null;
}
const nodeText = input.read(node.from, node.to);
if (nodeText.length < 2) {
return null;
}
// We want to get the exact location of the string content inside the quotes
const openingQuoteStatement = nodeText.match(
/^(?<openingQuote>[furbFURB]{0,2}(?:['"]{3}|['"]{1}))/,
)?.groups?.openingQuote;
const from = openingQuoteStatement
? node.from + openingQuoteStatement.length
: node.from;
const nodeTextWithoutOpeningQuote = openingQuoteStatement
? nodeText.replace(openingQuoteStatement, '')
: nodeText;
const closingQuoteStatement = nodeTextWithoutOpeningQuote.match(
/(?<closingQuote>['"]{3}|['"]{1})$/,
)?.groups?.closingQuote;
const closingQuoteLength = closingQuoteStatement?.length ?? 0;
const to = node.to - closingQuoteLength;
const overlay = [
{
from,
to,
},
];
if (overlay[0].from >= overlay[0].to) {
return null;
}
let p: LRParser = sqlLang.language.parser as LRParser
/**
* Default highlighting ignores things that are not keywords (the green words)
* So we can further customize it here
*/
p = p.configure({
props: [
styleTags({
// Type - things like array, count
Type: tags.atom,
// Identifier: tags.atom
})
]
})
return {
parser: p,
overlay,
};
}),
});
return mixedPythonLanguage;
}
const mySQLParser = mySQLPython();
const mySQLPythonLRLanguage = LRLanguage.define({
parser: mySQLParser
})
export function languageSelection(): Extension {
return [
mySQLPythonLRLanguage,
];
}
Appreciate your help