Is there a built-in way to determine if the cursor is within a codeblock?

Hi,

I’ve written an EditorSuggest class and can’t find a way to determine if the current EditorPosition (cursor) is within a codeblock for the onTrigger method.

The alternative seems to be reading the body of the entire file and determining if the cursor position is within a codeblock or not which seems incredibly inefficient for a method that runs on each text input (onTrigger).

I’d assume this would be available on the Editor context object, since not triggering a suggestion within a codeblock seems like common behavior, but I’m unable to find it.

Any ideas?

Relevant lines of code: https://github.com/Ebonsignori/obsidian-at-symbol-linking/blob/1f246453f57b0d837507a3bad62921282631cead/src/popup.ts#L132-L133

2 Likes

Probably you need to use CodeMirror/Lezer.

A EditorSuggest object has context property, and it has editor in it.
You can access the EditorView instance associated with the editor using editor.cm.

For example, you will be able to check whether the current cursor is inside an inline code. (Sorry, I don’t have time to test it but something like this should do.)

const {editor} = this.context;
if (editor.cm) {
    const cursor = editor.cm.state.selection.main;
    syntaxTree(editor.cm.state).iterate({
        from: cursor.from, 
        to: cursor.to,
        enter(node) {
            if (node.name == “inline-code”) {
                console.log(“I’m inside an inline code!”);
            }
        }
    })
}
1 Like

@ush Thank you! This worked perfectly.

For anyone else who comes across this, here is the solution in a bit more detail. The includes("codeblock") accounts for multiline code blocks, e.g. ```

import { syntaxTree } from "@codemirror/language";

let isInCodeBlock = false;
if ((editor as any)?.cm) {
	const cm = (editor as any).cm;
	const cursor = cm.state?.selection?.main as {
		from: number;
		to: number;
	};
	syntaxTree(cm.state).iterate({
		from: cursor.from,
		to: cursor.to,
		enter(node) {
			if (
				node.type.name === "inline-code" ||
				node.type.name?.includes("codeblock")
			) {
				isInCodeBlock = true;
			}
		},
	});
}

3 Likes