Tips or documentation excerpts, triggered as snippets


#1

Hi everyone!
I’m new to the forums and to Atom, so hello there, first of all :slight_smile:

I am a VIM user, most of the time, but I really like the expandability of Atom, and I’d like to expoit it to write a package to help MBDyn users to write their input files. I’m very much a newbie in javascript and coffee development, so please bear with me :sweat:.

I’ve already written a syntax highlighting package (language-mbdyn) and I began to extend it with snippets.

Here is where I’ve encountered the first doubts, as Atom does not support nested snippets (as far as I understand). I’ll make and example to clarify.

Suppose that I want to add a structural node to my model with the following syntax:

structural: <node_label>, <node_type>,
  <initial absolute position>,
  <initial absolute orientation>,
  <initial absolute linear velocity>,
  <initial absolute angular velocity>;

Now, one of the possible realizations of the above syntax may be

structural: HUB, dynamic,
   reference, REF_HUB, null,
   reference, REF_HUB, eye,
   null,
   null;

so that I cannot assign a snippet to, for example, the <initial absolute position> parameter, since writing reference, REF_HUB, null will cause the editor to exit from the snippet tab sequence.

So i thought that, instead of long snippets like the previous one, I might provide only simpler snippets (like, for example, the reference, <reference_label>, <relative_position> construct) while leaving the full definition of the currently edited entity (the structural node, in this case) in a side panel as a reference.

My question (at last! Sorry for the length of the post) is: which will be, in your opinion, the best way to achieve this? I’d like for the “hint” to be displayed in a side panel, possibily triggered by a prefix just like a snippet, but a manual intervention of the user, for example through a command, can be acceptable as well.

Thanks in advance to anyone who will take the time to help me.

Cheers


#2

Atom can support nested snippets in a sense. If you have a snippet that creates a construct with a specific scope, then you can set up other snippets to target that scope.


#3

This seems very interesting, but I’m not sure I understand what you mean exactly… Can I kindly ask you for an example? Or maybe to point me to the relevant documentation, maybe I’ve just missed it.

Thank you very much :slight_smile:


#4

I’m going to put this in web language terms because that’s what I work with most. If you have an HTML file and you type <script type="text/javascript"></script>, everything inside that tag will be scoped as JavaScript and any snippet that has source.js as its selector will apply even though the document itself is HTML. You can accomplish that with the contentName rule, like this:

{
  begin: '\\b(abstract|electric|hydraulic|parameter|structural|thermal)\\b(\:)'
  beginCaptures:
    1:
      name: 'entity.name.type.mbdyn.nodes'
    2:
      name: 'punctuation.definition.mbdyn'
  end: ';'
  endCaptures:
    0:
      name: 'punctuation.definition.mbdyn'
  contentName: 'nodes.properties.mbdyn'
}

Then you can make snippets like

'properties.mbdyn':
  'Node Properties':
    prefix: 'prop'
    body: """
<node_label>, <node_type>,
  <initial absolute position>,
  <initial absolute orientation>,
  <initial absolute linear velocity>,
  <initial absolute angular velocity>
"""

which will only apply inside the properties.mbdyn scope. That’s kind of a boring example since you could just make the snippet starting at the node type. There’s a lot more that can be done with this technique.


#5

OK, now I got it and it is, actually, very interesting and also very easy to implement.
What I’m still missing is how this is going to help me in keeping up with the placeholders sequence.

Following your example, I can understand that I can define new scopes, for example for the properties of a structural node as you have written. I could then limit the availability of some snippets to the specific scope in which I want them to appear. That’s very useful.

[spoiler]But, keeping up with the example, if I want to tab into the placeholder <initial absolute position>, type reference, REF_HUB, null, or something like 0.2, 0.3, 1.0, (which is another valid entry) I cannot then tab into the next placeholder, which in this case will be <initial absolute orientation>, right? The system will “forget” where it was in the placeholder sequence if I type more than one word inside of the current placeholder, as far as I understand (from experience).

Does the different scoping allow me to achieve a different behavior? If yes, how?[/spoiler]
EDIT: Actually, turns out I was doing things in the wrong way. Works perfectly.

Again, thank you a lot for taking your time to help me.
Cheers!


#6

No problem. :slight_smile:


#7

Probably I still haven’t figured out completely your suggestion, though. For example, I’ve made a rule to assign a specific scope to the “nodes” section of the input file, that is encapsulated by the statements

    begin: nodes;
       ...
    end: nodes;

The rule is the the following

{
	begin: '\\b(begin)\\b\: *\\b(nodes)\\b\;'
	beginCaptures:
	  '1':
		name: 'keyword.operator.mbdyn'
	  '2':
		name: 'punctuation.definition.mbdyn'
	  '3':
		name: 'entity.name.section.nodes.mbdyn'
	  '4':
		name: 'punctuation.terminator.mbdyn'
	end: '\\b(end)\\b\: *\\b(nodes)\\b\;'
	endCaptures:
	  '1':
		name: 'keyword.operator.mbdyn'
	  '2':
		name: 'punctuation.definition.mbdyn'
	  '3':
		name: 'entity.name.section.nodes.mbdyn'
	  '4':
		name: 'punctuation.terminator.mbdyn'
	contentName: 'entity.mbdyn.section.nodes'
}

Now the problem is, while indeed the portion of text between begin: nodes; and end: nodes; is assigned both the source.mbdyn and the entity.mbdyn.section.nodes scope, all the syntax highligthing rules that worked for the source.mbdyn scope now is (I think) superseded by the ones that belongs to the entity.mbdyn.section.nodes scope… With the result that basically all the global highlighting does not work inside of the nodes block.

Is there a way to have text inside the entity.mbdyn.section.nodes scope inherit all the grammar rules of the source.mbdyn scope? Kind of doing the same thing as at the top of the snippets definition file, where the scopes of validity are declared?


#8

Not exactly. What’s happening is that the parser travels through the document and starts matching at the end of each match. You nest patterns inside of each other to accomplish things like specialized rules for object declarations and tag attributes. If you want to match the whole grammar against the contents of a match, you can do the following:

{
	begin: '\\b(begin)\\b\: *\\b(nodes)\\b\;'
	beginCaptures:
	  '1':
		name: 'keyword.operator.mbdyn'
	  '2':
		name: 'punctuation.definition.mbdyn'
	  '3':
		name: 'entity.name.section.nodes.mbdyn'
	  '4':
		name: 'punctuation.terminator.mbdyn'
	end: '\\b(end)\\b\: *\\b(nodes)\\b\;'
	endCaptures:
	  '1':
		name: 'keyword.operator.mbdyn'
	  '2':
		name: 'punctuation.definition.mbdyn'
	  '3':
		name: 'entity.name.section.nodes.mbdyn'
	  '4':
		name: 'punctuation.terminator.mbdyn'
	contentName: 'entity.mbdyn.section.nodes'
	patterns: [
	  {
		include: '$self'
	  }
	]
}

#9

Works like a charm. Thank you very much! :smiley:

One last thing: is there a documentation reference for these aspects? I could not find much useful information in the Flight Manual or in the API reference on grammars and snippets implementation.

Cheers


#10

I wrote up a grammar template with annotations, back when I was learning how to make them work. For the snippet, I didn’t do anything that you can’t find in the appropriate section of the Flight Manual except that it seems that all of the examples there are about top-level scopes and a reader might not make the leap to think that scoped areas within the code are viable. That’s probably something that needs to be added.


#11

Thanks for pointing this out. And count me in the list of those that “did not make the leap” :sweat_smile: