Sublime Forum

Python syntax - import/from

#1

Hello. Modifying the ‘Python.tmLanguage’ file I can capture the words import/from/as so as to colour them within a theme-file using:

<string>\b(?:(import)|(from)|(as))\b</string>

Is it possible to capture the other words (the libraries) that occur on the same line, so that I might colour them differently?

However, I would be happy just to capture the whole line that begins with either import or from :smile:

Also, is it technically possible to then reference the captured library-names elsewhere in the Python file? I’m thinking that all references to the library could use the same colour that is given to them on the import/from line. *

Andy.*

0 Likes

#2

[quote=“agibsonsw”]<string>\b(?:(import)|(from)|(as))\b</string>
Is it possible to capture the other words (the libraries) that occur on the same line, so that I might colour them differently?

Also, is it technically possible to then reference the captured library-names elsewhere in the Python file? I’m thinking that all references to the library could use the same colour that is given to them on the import/from line. *

Andy.*

Yeah, edit the regex to <string>\b(?:(import)|(from)|(as))\b(\w]+)</string>
Or you can add a new dict match for each individual package or you can just match the entire line like you said with a greedy asterisk period match (.*).
You have lots of options and all the examples you should need to learn them are in the tmLanguage files.
I find regex to be fun and I hope you like it too because you will need to know it well to edit these files.
Also there are 11 groups you can use to scope your sytanx in Sublime which uses the TextMate scopes which are listed here:
manual.macromates.com/en/language_grammars

Good luck.[/quote]

0 Likes

#3

Hello @atomi and thank you.

I’ve been working in the dark a little, as the ST documentation is limited. That link should prove v. useful :wink:

<string>\b(?:(import)|(from)|(as))\b(\w]+)</string>

I believe this would capture a word, but not comma separated items:

import sublime, sublime_plugin

I would like to capture the words if possible (although I might revert to .* in the end)?

I’m assuming it’s not possible to reference the captured words later on :cry:. The linked page confirms “it is not possible to use a pattern that matches multiple lines”.

Ta, Andy.

0 Likes

#4

You can just add a comma

<string>\b(?:(import)|(from)|(as))\b(\w,]+)</string>

These matches will work throughout the entire page.
If you want to match blocks of code use begin and end keys and use patterns key for matching inside those code blocks as long as there is a well defined end match.
You can also use include key to include syntax definitions inside matching code blocks.

Again play with the tmLanguage file. It’s easy to check the scope you’ve defined by pressing ctrl+shift+alt+p

0 Likes

#5

@atomi. Just to say thanks again. I shall explore :wink:

0 Likes

#6

No problem. I’ve been hanging out here kind of bored, recovering from a minor surgery - I’ll be fine and back to coding in a couple of weeks. :smiley:
I’m glad I could help.

Also check out these examples I posted for others


The tmLanguage files seem complicated at first but it’s not too bad once you start to separate all the xml elements out.
You can spread the various dict elements out so you can focus on them better. The xml tends to blend together at first.

0 Likes

#7

Related to this topic :wink: I’m sort of botching the ‘Python.tmLanguage’ file to achieve what I’m after. The following code allows me to colour-code specific methods. However, I cannot persuade it to insist on a leading dot . before the method call. No matter how I modify it - using (?:.) .{1} or (?<=.) the method drops into the ‘meta.function-call.python’ scope.

Is there a way I can achieve this behaviour? Either by modifying my expression or the ‘meta.function-call.python’ equivalent expression? I would like to achieve this without having to delve into a substantial editing (begin, end, endCaptures, etc.) of the tmLanguage file.

Andy.

<dict> <key>captures</key> <dict> <key>1</key> <dict> <key>name</key> <string>support.function.library.python</string> </dict> </dict> <key>match</key> <string>(?x)(?:[a-zA-Z_][a-zA-Z0-9_]*\.)*(fromtimestamp|getmtime|itemgetter|split|uuid[1345]{1})\s*(?=\()</string> </dict>

0 Likes

#8

This is more of a regex question.

[quote=“agibsonsw”]The following code allows me to colour-code specific methods. However, I cannot persuade it to insist on a leading dot . before the method call.

<key>match</key> <string>(?x)(?:[a-zA-Z_][a-zA-Z0-9_]*\.)*(fromtimestamp|getmtime|itemgetter|split|uuid[1345]{1})\s*(?=\()</string> [/quote]

What do you mean persuade it to insist on a leading dot? If you need this rule to absolutely always match a dot you use an escaped dot (.)
Here is a cool regex tester you can use if you want to make sure your regex is correct (someone posted earlier) gskinner.com/RegExr/

The best way to learn regex is to actually read what all the symbols mean: here is a cheatsheet cheatography.com/davechild/c … pressions/
Great resource here too regular-expressions.info/

If you still can’t get it to work try posting the code you want to match and it’s variations along with your regex attempt.
You’ll get more help that way too. GL HTH.

0 Likes

#9

Hello @atomi and thank you for your response.

I’m quite/reasonably comfortable with regex. Put another way, I want the default Python.tmLanguage to capture only the word ‘mycall’ (and brackets) - and to require a leading dot - for the scope ‘meta.function-call.python’ in:

someobj.mycall()

Currently, it grabs everything before the brackets(), whether or not there is a dot involved:

<string>meta.function-call.python</string> <key>patterns</key> <array> <dict> <key>begin</key> <string>(?=[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*\s*\()</string> <key>end</key> <string>(?=\s*\()</string> <key>patterns</key>

0 Likes

#10

Did you get this working how you wanted?

If you want to scope only the function call and not the objects preceding it use beginCaptures key.
Every key number in the beginCaptures array dict eg <key>1</key> corresponds to a back reference in your “begin” regex string (unless it’s a non-capturing group).

0 Likes

#11

Hello @atomi.

Unfortunately, I haven’t managed to obtain the behaviour I’m after. I believe that I need to modify the behaviour of the default ‘meta.function-call.python’ (as indicated by facelessuser), rather than trying to modify my own function lists’ regex.

I’ve tried modifying the first/begin regex in the following - I only want it to capture thisword() but *only *if it’s preceded by a dot. But I believe I need to modify the regex for ‘dotted.name’ as well. But dotted.name has other ‘includes’, and it’s just dawned on me that I probably need to amend all of those as well?! I think that if I could modify the behaviour of these scopes - to only capture single words at a time - then I could just use (.) within my function-lists/scope :question:

It’s been a little frustrating :cry: especially as the documentation is quite poor. [What’s the difference between ‘patterns’ and ‘repository’?]

<string>meta.function-call.python</string> <key>patterns</key> <array> <dict> <key>begin</key> <string>(?=[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*\s*\()</string> <key>end</key> <string>(?=\s*\()</string> <key>patterns</key> <array> <dict> <key>include</key> <string>#dotted_name</string>
I’ve even considered deleting huge chunks of ‘Python.tmLanguage’ :laughing:

0 Likes

#12

Hey, no worries, I’ve got the behaviour I wanted with a simple (?<=.) addition:

<string>(?x)(?:[a-zA-Z_][a-zA-Z0-9_]*\.)*(?&lt;=\.)(set_timeout|status_message|

I’m sure I tried this before :confused: - but hey, it works!

The point is that set_timeout(), and other methods, should only be recognised as an API call if it’s preceded by a dot.

0 Likes

#13

@atomi - thank you for these details :smiley:. My regex was added as part of the following, near the top of the file.

<dict> <key>captures</key> <dict> <key>1</key> <dict> <key>name</key> <string>support.function.api.python</string> </dict> </dict> <key>match</key> <string>(?x)(?:[a-zA-Z_][a-zA-Z0-9_]*\.)*(?&lt;=\.)(set_timeout|status_message|
I need all the complicated a-z business to prevent everything (prior to ‘(’ ) being gobbled-up into the scope ‘meta.function-call.python’, and coloured according to this scope.

I’ve achieved my main aim :wink: which was to require that method calls be preceded by a dot; otherwise, they are treated as normal/general function calls.

0 Likes