I have been banging my head against the fact that many of the completions in my upcoming syntax extension are non-functional when the cursor is at the end of the line. I have managed to isolate and replicate the issue showing that subscopes are invisible to selector expressions when the cursor is at the end of the outer scope on any new line terminated line.
Yeah, this is a mouthful. Took me a while, too.
To reproduce, assume the following simplistic syntax extension:
<?xml version="1.0" encoding="UTF-8"?> <syntax name="buggsy" xmlns="https://www.nova.app/syntax"> <meta> <name>Syntax Bug Collection</name> <type>structured</type> <preferred-file-extension>buggsy</preferred-file-extension> </meta> <scopes> <scope name="buggsy.statement"> <symbol type="statement" /> <starts-with> <expression><![CDATA[(?x) (?=[^[:space:]]) ]]></expression> </starts-with> <ends-with> <expression><![CDATA[(?x) (?=[[:space:]]) ]]></expression> </ends-with> <subscopes> <scope name="buggsy.identifier.function"> <expression><![CDATA[(?x) \w+ ]]></expression> </scope> </subscopes> </scope> <include syntax="self" collection="functions" /> </scopes> </syntax>
with the following completions:
<?xml version="1.0" encoding="UTF-8"?> <completions> <provider> <syntax>buggsy</syntax> <selector>buggsy.statement</selector> <expression><![CDATA[(?x) \w+ ]]></expression> <set>buggsy.statements</set> </provider> <provider> <syntax>buggsy</syntax> <selector>buggsy.identifier.function</selector> <expression><![CDATA[(?x) \w+ ]]></expression> <set>buggsy.functions</set> </provider> <set name="buggsy.statements"> <completion string="compstate" /> </set> <set name="buggsy.functions"> <completion string="compfunc" /> </set> </completions>
follow these steps:
- Activate the above as a development extension.
- Create a new document and assign it the syntax type “Syntax Bug Collection”.
- In the blank document, type “c”: the completion “compfunc” is suggested, which matches the highlighting scope stack of
buggsy.statement > buggsy.identifier.function.
- Place the cursor at the begin of the line and insert a new line.
- Jump to the start of the document, right before the new line character.
- Type “c”: the completion “compstate” is suggested, which does not match the highlighting scope of
buggsy.statement > buggsy.identifier.function. Instead, it matches the outer scope only.
- Add “ word” (with the whitespace) on the same line. Jump back to behind the “c” at the start of the line, repeat 6. Same result.
As a side note, I suppose this has gone unnoticed until now because most static completions, including the ones included with Nova, are either scoped to delimited expressions, where the cursor ends up inside the outer scope, or use a root level exclusionary approach, i.e. some variant of
*:not(string, comment). This is not an option for my extension, as the syntax it highlights is highly positional; completions need to be scoped precisely to specific scope stacks to be useful.