Selecting a variable name with a dollar symbol in it

That makes sense. Thanks for the further clarification. :slight_smile:

@mike.bronner, as far as I can see, the ‘oddity’ comes from the mode you’re in.

If you’re using the PHP-HTML mode, the problem is that, outside the PHP block (i. e. outside <?php ... ?>), dollar signs have no particular significance, and putting brackets around them are, well, only symbols without any semantic meaning. They’re just dollar signs (and just bracket symbols), which are treated as ‘punctuation’ by default when double-clicking a word to select it.

When you switch to Blade mode, however, I’m assuming you’re using @melvinbeemer’s language extension. It is sufficiently clever to understand that Laravel Blade templates have symbols with ‘special meaning’, and flags those to Nova; that’s why Nova ‘knows’ that variables are preceded by $ and therefore $ is selected with the next characters as being part of the ‘word’.

As far as I could see in @melvinbeemer’s extension definition, you’re supposed to use files with the *.blade.php extension when writing Blade templates — that way, Nova will automatically switch to the ‘correct’ mode. If you use any other extension (such as plain old *.php…), Nova will give precedence to the built-in PHP-HTML language extension…

I hope this makes some sense to you.

1 Like

Hi @GwynethLlewelyn, thanks for chiming in. :slight_smile:

As a PHP developer, my expectation would be that the PHP-HTML language syntax would account for php variables being dispersed among HTML code, regardless of which php escape tags they are wrapped in. For example, you can define arbitrary PHP shorttags other than <? and <?php. Not that it would make sense in most cases, but the point is that it could be done. As such, I wouldn’t expect the syntax to rely on that. It’s not a big deal, it just didn’t match my initial expectations. I totally agree that your explanation makes sense, and if it fits 80% of developers’ expectations, then it’s the right way to go. :slight_smile:

Yes, I am using the Blade extension, and have properly named my files. I was just experimenting, as I had the same question originally before I had the Blade extension installed. (I finally have Nova set up to where I can use it as my daily driver. Yay!)

1 Like

Well… I guess you’re right about the expectations — in other words, ideally, Nova ought to have the same degree of knowledge about a language’s syntax & semantics as, well, the language parser, or at least a language analyser/linter.

This isn’t something provided by Nova, the text editor. What you wish is an integration with a PHP Language Server — something that ‘speaks’ the Language Server Protocol invented by Microsoft for its VS Code editor, but widely adopted by many popular, contemporary code editors.

Therefore, you need two more components: the PHP Language Server itself (a separate application), and some ‘glue code’ to let Nova ‘talk’ to this PHP Language Server, which is usually provided by a Nova extension.

In the case of PHP, I found two options for PHP Language Servers (there might be more). The first is simply called ‘PHP Language Server’. It’s written in PHP (this is not obvious; many Language Servers are written in languages different from those they provide — writing them in JavaScript or TypeScript is popular), it’s free, it’s open-source, released under a minimalistic ISC license. It’s also… abandoned in 2018, meaning that it only supports PHP up to 7.0 (unless anyone wishes to ‘take over’ the project — there have been many, many PRs submitted in the past three years on GitHub, but nothing has ever been approved. The original developer is currently very actively involved into SourceGraph, so I guess he’s too busy to ‘go back’ to his old code…

The second option is to use PHP Intelephense. This is a closed-source, freemium PHP language server, developed by Ben Mewburn, who also wrote the integration code with VS Code. It seems to be kept up-to-date with all the latest PHP versions.

For Nova, there are two different extensions that essentially provide the ‘glue’ between Nova and Intelephense:

Both seem to be quite up-to-date and are free to use; and while Intelephense is a paid application, according to some reviews, the free version is ‘good enough’ for most uses, and you have always the option to unlocking the advanced options by buying a lifetime license for merely $15 or so — but you’ll have to see if any of the above-mentioned extensions actually provide any of those advanced options to Nova.

I’d say that either of these options would be worth of your attention, but ultimately only you can decide if it’s ‘enough’, based on existing extensions.

In my case, when doing things in PHP, I usually stick with advanced PHP:

It’s just a more sophisticated syntax checker than the built-in ones which goes a long way to provide a bit more functionality. Note that I’m not a Laravel programmer myself (uh, long story, I had a really, really bad experience with an ancient Laravel version…) so I have no idea if the developer, @dennisosaj, has provided additional support for Blade (i.e. allowing you to use a single extension for both). One slight disadvantage of advanced PHP is that it also requires some ‘advanced’ features implemented on whatever theme you’re using. (Shameless plug: my own theme does support those nifty extra features and is therefore compatible with advanced PHP).

Happy extension-ing!

1 Like

Thanks for the suggestions. :slight_smile: The genealabs/intelephense is actually mine. :slight_smile: I’m happy to read your thorough replies, hoping to learn nuggets of extension development wherever I can.

1 Like

Without wanting to derail the conversation about Language Servers, which has a lot of excellent points made by @GwynethLlewelyn, these do not actually provide much at the most basic level of editor functionality (e.g. highlighting, selection etc.) in Nova.

I think what would help for the issue brought up here, and in many similar scenarios like highlighting TODOs, links etc., would be for Nova to provide a way to inject features into existing syntaxes. Currently, a syntax can include parts or all of another known syntax (like CSS / JS / PHP in HTML, or Markdown code blocks), but if you want to inject some new syntax elements into a pre-existing syntax, your only way is declaring a new language mode and either clone the original syntax, or use Template Scopes, which lack any kind of granularity (for instance, you cannot restrict them to specific scopes, e.g. comments for TODO highlighting).

With such a feature, additive syntax extensions providing just that that bit of extra functionality would be low hanging fruit; without it, the onus is on Panic, and, by extension, more or less exclusively on @logan, to provide all syntax functionality. Which is very much not a sustainable state of things.

2 Likes

*slaps her forehead*

@mike.bronner I’m so stupid… you’re right, I’m so sorry lol

It seems that you guys are reading my mind because I was also going to suggest something that @kopischke has just proposed!

Understanding now that @mike.bronner is running, at the same time, the PHP-HTML ‘built-in’ syntax highlighter, plus the Blade extension, and plus his own genealabs/intelephense extension, the original problem he described is due to the fact that the three extensions are not ‘active’ at the same time.

I actually faced that when starting to toy around with the Go extension. The one I had for Coda 2 worked quite well, but nothing was available for Nova. So I tried my best to replicate the syntax highlighting (but the actual format is quite different, so it took many trials & errors). I then noticed that I wasn’t getting even the most basic completions. Ok, so I added a completions XML file and registered the extension with ‘completions’ as well. But I was missing some nifty extra features, which only a Language Server could provide. Sure thing, I just added support for the Language Server (at a time when Nova still has many limitations in communicating with it). In the meantime, I noticed that my Go templates were being rendered as text-only. Bummer! Go templates are inspired on Smarty (or Blade), and there was a Smarty extension available, so I tried it out — but I couldn’t have both Go and Smarty running ‘simultaneously’. Ok, no problem, I copied the Smarty language extension, tweaked it a bit, then added it to ‘my’ Go extension… and so on. Recently I had to add a completely new syntax highlighter, this time for Go imports, which are stored inside go.mod files… so, aye, another syntax added… and this, of course, will go on and on…

And in the meantime, the GoTools extension was added to the library — because ‘my’ extension didn’t call any external commands to automate workflows. So that developer had no choice but to develop his own solution — but then he lost the syntax highlighting from ‘my’ extension… which meant grabbing ‘my’ syntax highlighting and add it to GoTools, and register it as a ‘language extension’ as well. It means that, right now, if you wish to use the powerful enhancements of a Language Server, you have to use ‘my’ extension; but if what you ultimately need is a set of post-processing tools, then you’ll have to pick GoTools instead. You can’t get both. As time passes, I’ve done substantial changes on the syntax highlighter — meaning now that ‘my’ extension is a bit better at doing syntax highlighting than GoTools; the developer will now have to pay attention to what I’m doing on my own, and, as soon as I release a new version of the syntax highlighting, he’ll have to copy it over to his own extension to keep both in sync… sure, we might get an agreement to mutually exchange the syntax highlighting XML file as soon as any of us updates it… but now imagine that someone, finding that ‘my’ extension does a rather poor job of dealing with Completions, decides to write his own Completions file and grabs the syntax highlighting XML from either of us. Now we’d have three different extensions, all providing different goodies on Go files, but all need to be installed simultaneously but only one can be ‘active’ — so there is no way to get the full functionality of all three at the same time. Unless, of course, we all agree to pour our efforts into a single, unified, mega-extension. But then someone else might develop a fourth extension to provide Snippets… you see how quickly it gets out of hand!

In @mike.bronner’s case, it seems that the ‘solution’ is basically grabbing the syntax highlighting from one of the PHP extensions (either the built-in one, or advanced PHP, or any other) and include it with his integration with Intelephense. Again, every time the syntax highlighting/completion files change, he’ll have to manually copy them over…

My original idea was simply to allow different extensions to register the same language, and get Nova to activate all of them at the same time, if they don’t ‘overlap’ — so you could have an extension providing syntax highlighting, another calling external CLI tools for post-processing, another integrate with the Language Server, another adding optional, additional syntax highlighting for Go-related files which are not Go source files, and so forth; so long as there was no overlap, this should work.

But after reading your suggestion, it makes so much more sense to have a way to ‘inject’ additional functionality in existing extensions. One thing that I’ve struggled with was how to deal with the auto-documenting tools that already exist for Go. These search for special formatting on the comments, like so many other auto-documenting tools on other languages. The Coda 2 syntax highlighter already added such functionality — at least, to a degree. The Language Server is supposed to also be ‘auto-documentation-aware’, but I’ve not even started looking at that yet. The point here is that I might not need to create a completely new mega-extension that does ‘everything’. I just want to have something working in tandem with the existing extension, but allow a new extension to focus exclusively on the auto-documentation aspects. The same also applies to TODOs, BUGs, etc. And probably it would be the ‘right’ approach for dealing with different templating engines which are a meta-syntax on top of an existing language — such as Blade/Smarty templates deployed on PHP. I imagine that similar strategies would also work best for dealing with CSS, since so many different tools deal with CSS generation.

So, in other words, what we’d like is some sort of ‘sub-extensions’, or ‘co-extensions’, that might override some functionality or add some more functionality on top of an existing, active extension (built-in or installed from the Library).

The closest I’ve seen so far is the pragmatic approach used by @dennisosaj for advanced PHP. Some of the features of his extension require theme developers to add a few more rules to fully support his extension. He documented those ‘requirements’ well enough, and they’re very easy to implement, so a handful of theme developers have already tweaked their own themes to be ‘advanced PHP-compliant’. Because themes are conceptually different from language extensions, even if they all come from the same source, this approach works — when using PHP, you can switch on advanced PHP for some extra juice, and, if your current theme enables those extra goodies, you’ll get even more ‘bang for the buck’, so to speak. This avoids the need for @dennisosaj to basically replicate all themes out there and include them with his own extension — a daunting task (and also a very un-pragmatic approach).

So, aye, I guess that this ought to become a Feature Request — implement ‘sub-extensions’, or ‘child extensions’, or an ‘injection’ functionality (because in some cases it might be necessary to ‘inject’ code not only on one ‘parent’ language extension, but on several). How exactly to do that in the simplest way possible — without having to redesign the whole extension mechanism from scratch, potentially creating a ‘Nova 2’ which would break all existing extensions! — is certainly a challenge; but I totally agree that this is the way to go.

Think WordPress plugins :slight_smile:

1 Like

I think what you describe is mostly an issue of syntax highlighting and symbolication. As that cannot be additive, trying to remedy shortcomings of existing syntaxes leads to duplication with new syntax variants that are mutually exclusive.

When it comes to tooling, however, Nova provides for cumulative extension functionality. AFAIK, any completion / snippet / LS / linting etc. extension that declares it supports a named syntax works for files of that syntax at the same time (for instance, my µESLint extension and @apexskier’s JSON extension, which both use ESLint for JSON linting, will happily duplicate issues in a JSON file), and Nova even provides an inheritance concept which allows newly defined syntax variants to opt into the tooling functionality of existing syntaxes (note the caveat: “This is not used in parsing”).

1 Like

Huh. I had no idea that you could have two Nova extensions acting on the same file extension simultaneously. I have a few ‘duplicate’ extensions myself, but I had always to manually switch the syntax type assigned to a particular file to get either one or the other extension’s functionality to be activated.

Or perhaps I’m not quite understanding what you mean. If one extension signals that it uses the .xxx extension and provides syntax highlighting and a second extension registers .xxx for completions, if both are active, that means that I get both highlighting and completions when opening file.xxx? If so, that’s a big step towards what I had in mind!

Based on what you’ve said, I thus assume that if two Nova extensions register different calls to external tools for the same filename extension, then opening file.xxx will result in both calls to external tools to be applied to file.xxx? Seriously, I had no idea that this was possible!

If so, it looks like it would be best to provide separate extensions to do different things, e.g. one for syntax highlighting, one for completion, one for linting (with an external tool), one for interfacing with a language server… That way, end-users can pick whatever combination they prefer! Is that how it works? Because if it is, I have a lot of work to do lol — breaking apart one extension in its individual components!

Inevitably, the question is: if two extensions register .xxx, and both provide syntax highlighting for that particular extension, which one will Nova pick? :smiley: I can easily imagine scenarios where the same filename extension is used by completely different languages (it’s not usual, but nevertheless possible) — which one will be picked? Is it First Come, First Served?

I guess that this requires a lot of testing and experimenting on my part; I really wasn’t aware of these amazing possibilities…

1 Like

Well, there‘s two things to keep in mind (or maybe they are two aspects of one and the same thing; sorry, it’s late im my TZ and I might have had a beer or two):

  1. Syntaxes are exclusive – there can only ever be one that is active per file, and the active syntax defines what highlighting and symbolication you get.
  2. File extensions do not map one to one onto syntaxes. You can define other heuristics for Nova to detect when to apply a syntax besides extension names (notably, content detection, used to detect hashbang lines in shell scripts). These heuristics are weighed, and the “heaviest” one wins (no idea what happens when two heuristics result in the same weight; maybe Nova reverts to plain text, or maybe to the nearest builtin syntax?).
  3. Tooling depends on the active syntax, not directly on the file extension. For instance, my JXA (JavaScript for Automation) extension defines a jxa syntax that is automatically applied to .jxa files, but needs to be manually applied to .js files. When applied, all tooling for the javascript syntax is available, because that is what the JXA syntax declares as its parent (in theory; some extensions perform their own type / file extension checking and will sabotage this mechanism), as well as anything specifically defined to apply to the jxa syntax (zilch as of now beyond what the extension itself provides).

… yeah, three items out of two. You know the old joke: “the two greatest gotchas in programming are naming things, cache invalidation, and off-by-one errors”.

2 Likes

It’s been about two years, where are we on this?

This request is still present on our list of possible considerations for the future. As far as I am aware, we have not received any other requests for it beyond this thread.

1 Like

I’ve found if people don’t know what they don’t have they will never know not to ask for it; i.e. someone in the Amazon rainforest doesn’t know how awesome a roller coaster is.

Perhaps we should advertise possible future functionality and ask if people are interested. There are certainly people in my office who want this, I see it in their faces every time they double-click on a variable name and it doesn’t select the dollar symbol

1 Like

I agree. Unfortunately there are many little things like this that prevent me from using Nova for my daily driver.

2 Likes

As always, if you have requests for new features or improvements in Nova, the best way to let us know about them is here or via the Nova Help form. We can only consider changes that we hear feedback on!

Thank you. Well you’ve just had several people suggest that this needs to be considered.

Yes we did! I will definitely include that if we ever consider doing this.

+1
I use $variables for styled-component “transient props”

@kopischke +100 Votes, Wow we need this on its very own Feature Request. I made a whole language extension for Javascript just to support two use cases of literal objects. My extension used the vanilla tree-sitter for JS without a single change.

If we had the ability to modify or extend the existing syntaxes that would solve so many issues and make Nova so much adaptable to each persons workflow and preferences.

I’m wondering if there has been any update to this. I truly want this feature