Search code examples
regexsublimetext3sublimetext-snippet

Match Parent Folder in Sublime Text 3 Snippet


I'm trying to create a snippet that outputs a file's parent folder name. For example: /Users/user/src/Page/index.js

returns

Page

I've got this regex pattern:

([^\/]+)(?:\/[^\/]+)$

Which, according to Regex101, matches Page/index.js with Page in group 1.

Trying this: ${1:${TM_FILEPATH/([^\/]+)(?:\/[^\/]+)$/$2/}}

returns

/Users/user/src/

Which makes me think I'm doing this entirely wrong.

I'm not sure how to use Sublime/Perl's string format options to actually return the proper string. I may not even have a correct pattern. What is the best way to do this?


Solution

  • I think you might be falling victim to the assumption that when you use a substitution to rewrite a field (or in this case variable) that the entire variable is replaced with the replacement text in the regular expression.

    In fact what happens is that the regular expression is matched, the matched text in the variable is replaced with the replacement that you provide in the regex, and then the whole (newly modified) variable value is inserted.

    For example, take the following snippet:

    <snippet>
        <content><![CDATA[
    ${TM_FILEPATH/./=/}
    ]]></content>
        <tabTrigger>lpc</tabTrigger>
        <description>Last path component of the current file</description>
    </snippet>
    

    That is "match any character, replace it with an equal sign". If you expand this snippet, the result is:

    =home/tmartin/Test/sample.txt
    

    The first slash matched and was replaced, and then the variable expands out as a weirdly broken path.

    As such, in order to capture just the last path component, the regular expression that you use has to entirely consume the whole of the variable value, so that the replacement replaces the whole value with just the part you want.

    A (probably ham-handed) example of that is this snippet:

    <snippet>
        <content><![CDATA[
    ${TM_FILEPATH/^.*\/([^\/]+)\/[^\/]+$/$1/}
    ]]></content>
        <tabTrigger>lpc</tabTrigger>
        <description>Last path component of the current file</description>
    </snippet>
    

    Now from the start of the string it greedily matches everything, followed by a slash, then a capture group that captures the last path segment, followed by one last slash and the remainder of the line right up to the end of the string.

    The replacement in this case is more what you would expect:

    Test