How do I get the relative path of a file in a project? - sublimetext3

I want to create a build system for my app where it will open a url to the target file. For example, if I run the build on a project file components/flower.html, it should run
open http://localhost:8080/app/components/flower.html
The list of variables for ST don't have relative path. so the closest I get is
http://localhost:8080/app//dev/myproject/components/flower.html
It contains the full path. Perhaps there is an easy way to remove the /dev/myproject part?
This is the build setting I want to further customise:
"cmd": ["open", "http://localhost:8080/app/${file_path}"]

If we look at the documentation on Build Systems, we see that we can use snippet substitution in the variables used in the build system. This is really handy when the built in variables don't quite meet our needs.
Therefore, we can replace the project dir with nothing to get a relative path.
I find the easiest way to test substitutions is using a snippet for $SELECTION, so you can just change the selected text and try a different test case, without needing to worry about saving the file with different names or running the build system and waiting for the results.
The substitution is done with regular expressions, where forward slashes need to be escaped, as they have special meaning. One slash after the variable name, one slash after the find regex pattern, one slash after that, followed by the replacement pattern, followed by a slash to indicate the end of the replacement pattern and optionally followed by some regex flags. Therefore, the snippet I'm using is:
<snippet>
<content><![CDATA[
${SELECTION/^\/dev\/myproject\///}
]]></content>
<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
<!-- <tabTrigger>hello</tabTrigger> -->
<!-- Optional: Set a scope to limit where the snippet will trigger -->
<!-- <scope>source.python</scope> -->
</snippet>
This just matches from the beginning of the string (^), then the literal /dev/myproject/ (unfortunately variables can't be used in regex patterns, otherwise we could maybe use $project_path) and replaces it with nothing. As we are only expecting one match, we don't need to use the global regex modifier flag.
The output we get from that with a selection of /dev/myproject/components/flower.html is:
components/flower.html
Which seems to be what we want, because with http://localhost:8080/app/ preceding it, it becomes http://localhost:8080/app/components/flower.html.
So, now we can just take the variable part out the snippet, and replace SELECTION with file_path, so it will operate on the current file's path instead of the selection, just like you had originally, and plug that into your build system:
"cmd": ["open", "http://localhost:8080/app/${file_path/^\/dev\/myproject\///}"]

Related

Is there a quick way to delete everything between certain tags, e.g. <head> and </head>, throughout the whole project (multiple pages) in VS Code?

I am trying to find a way to remove all from a tag pair in VS Code.
I’ve been using Notepad++ for this purpose, but for some unknown reason it doesn't work all the time. So, I hope if there is such a possibility in VS Code, it’d be more reliable.
Here is the instruction for Notepad++:
Search for -
<wp:post_name>[^<>]+</wp:post_name>
and replace all with -
<wp:post_name></wp:post_name>
Is there anything like this in VS Code?
I’d really appreciate it if someone can help.
Before using what is suggested in this solution, backup your files, and run the search and replace on a small sample. Be sure to check the outcome to all the possible combinations you can have in your files.
You can achieve what you need with Notepad++ (and SublimeText 3, with RegEx search and replace), and this answer will cover that. Since I've never used Visual Studio Code, I can't say if it will work in it as well.
Consider the following regular expression.
<foo>(.*?)<\/foo>
If we were to apply it to the following text:
<foo><some special chars>!##$%^&*</foo> sure, why not
<foo>Lorem</foo>
<foo>ipsum</foo>
<foo>sit</foo>
<foo>dolor</foo>
<foo>amet</foo>
<bar>elm stuff</bar>
more stuff for you <foo> something </foo> and even more stuff <foo>yes</foo>
it would match all the parts of the text which begin with <foo> and end with </foo>, regardless of what's between them.
If you want to play around with this, I've created an example here.
As far as using this in Notepad++, open the search window, navigate to the Find in files tab, and set it up like in the following image.
You would, of course, need to change the search and replacement strings to those you plan on using, optionally set up a file extension for which to do the replacement (Filters), and set the directory in which to perform find-and-replace.
Limitations
1. Nesting
In case your text contains nested tags of the same kind, like this:
Let's deal with nesting: <foo> some text <foo> a child foo!</foo> let's close the parent</foo>
doing the suggested RegEx search and replace, will turn the previous line of text into this:
Let's deal with nesting: <foo></foo> let's close the parent</foo>
If you don't have nested tags of the same kind, you should be in the clear. Unless...
2. Newlines
The provided RegEx will not match cases where your opening tag shows up in one line, and the closing tag shows up in another line. To match those, you would need to change the original RegEx:
<foo>(.*?)<\/foo>
to this:
<foo>([\s\S]*?)<\/foo>
\s will match any whitespace character (including newlines), while \S will match any non-whitespace character.

Why does Rust output escape backslashes on paths in windows? What is best way to remove the extra backslashes from output?

Background
Writing a program that watches a directory and subdirs and alerts user when file(s) in the path are created, updated, edited. Code is shared on github.
I'm new to Rust (about 1 week of experience).
Make Output Path Easy to Use
I want user to be able to easily copy the output path (see pic below) and copy / paste it for use.
When I run the program on Linux it works great with directory separators (/ - forward slash) and the user can easily copy the path and use it.
Problem : Windows Platform Uses Backslashes
The problem is that on Windows platform paths are separated by backslashes (which are also escape chars).
Double-Backslashes
When the program outputs the path on Windows it always shows double backslashes and the path isn't easily copy-able.
Here's a snapshot of the output:
As an example I am using the following output:
println!("{:?}", Path::new("c:\\windows\\"));
The output is from the Path::new() method itself, but it always outputs the path string with the double backslashes.
Can you help me find a better way to format the output so that it has single backslashes like a normal path (which excludes the escape backslashes)?
EDIT
Someone mentioned trying raw string input so I tried the following:
println!("{:?}", Path::new(r"c:\windows\"));
However, the Path::new method still outputs double backslashes.
The Problem is that you are using the Debug formatting to print the path, this causes characters that would need to be escaped in a string literal to be escaped in the output.
Instead you should use the normal Display formatting, though as Path does not directly implement Display you will need to call display on the path to display it.
println!("{}", Path::new("c:\\windows\\").display());
Note that Path::display is not loss-less in case the path contains non-unicode data.

Using search/replace in filename output in build system

How can I search/replace the output filename in my build system command? For example if the file I'm editing was called file_src, then I would want my build system to output it as file_build.
"shell_cmd": "my_command ${file} > ${file_name_but_search_replaced}"
Variable expansions in build systems are performed using the same underlying mechanism as that which is used in snippet substitutions, which is:
${var_name/regex/format_string/options}
As outlined in the link above, in snippets the variable named can be snippet fields or other special variables that apply only in snippets such as $SELECTION. Inside of a sublime-build file, the build variables are used instead.
How you might apply that depends on your needs and the filenames involved. For example:
{
"shell_cmd": "echo '${file_path}/${file_name/_src/_build/}'"
}
The thing to keep in mind is that the replacement will apply to the first match in the file (unless you specify the option to make it global, in which case it applies to all), so here the expansion is the path of the file followed by the name of the file with the substitution in just that field.
That makes sure that only the filename is modified in cases where the path might also contain the regex. Depending on your use case that may not matter (or be desirable), in which case you could apply it to $file instead.

How to create a centralized syntax file that be able to recognize multiple parts with different syntaxes?

For i.e: I'd like to have a custom syntax file, may be called sugar.vim that includes multiple other syntax files(?) to have the ability to highlight, maybe a paragraph as python.vim and another paragraph as javascript.vim, may be separated by newline (paragraphs often distinct by newline)
The real case that I often catch myself writing a document (non-extension file) other than real config a specific filetype (specific extension file), but for clear readability in the document filetype (we called sugar above). I'm thinking about a mechanism to recognize and highlight different parts of a filetype as different syntaxes.
To narrow down this case. How would it be to have a syntax file called sugar.vim that would be able to recognize python syntax and javascript syntax in files that have an extension of .sugar then the recognized python text should have highlights applied as a normal python file, same for javascript part. All recognized text must be separated by newline (at least one before and one after that text)
Sample:
# this is a sample text for this question
# i'm writing a document that has an extension of `.sugar`
def py_func1(arg1, arg2) # python.vim and its highlights applied here.
print("bello world!")
square = function(x) { # javascript.vim and its highlights applied here.
return x * x;
};
System: gvim 8.1 / windows10
Thanks in advances.
Vim supports that with the :help :syn-include command. As it's intended for syntax script writers leveraging other syntaxes, its use is somewhat complicated, and it's not really suited for interactive, on-demand use.
My SyntaxRange plugin provides commands and functions to set up regions in the current buffer that either use a syntax different from the buffer's 'filetype', or completely ignore the syntax. With it, it's trivial to dynamically add a particular syntax highlighting for a range of lines, and public API functions also make the programmatic definition easier.
You're looking for :help :syn-include.
Excerpt from vim help :
If top-level syntax items in the included syntax file are to be
contained within a region in the including syntax, you can use the
":syntax include" command:
:sy[ntax] include [#{grouplist-name}] {file-name}
All syntax items declared in the included file will have the
"contained" flag added. In addition, if a group list is specified,
all top-level syntax items in the included file will be added to
that list. >
" In perl.vim:
:syntax include #Pod :p:h/pod.vim
:syntax region perlPOD start="^=head" end="^=cut" contains=#Pod
When {file-name} is an absolute path (starts with "/", "c:", "$VAR"
or "") that file is sourced. When it is a relative path
(e.g., "syntax/pod.vim") the file is searched for in 'runtimepath'.
All matching files are loaded. Using a relative path is
recommended, because it allows a user to replace the included file
with his own version, without replacing the file that does the ":syn
include".
As long as you can clearly define boundaries for your embedded language regions it is fairly straight forward to achieve this.
You can also refer to https://github.com/tpope/vim-markdown/blob/master/syntax/markdown.vim for reference on how tpope embeds other syntax definitions within the markdown syntax, driven by configuration to minimise the number of language syntax's that need embedding for optimal performance.

What is wrong with this vim regular expression?

I have a list of files with extension .elf like this
file1.elf
file2.elf
file3.elf
I am trying to run them in shell with run command like run file1.elf >file1.log and get the result in a log file with file name with .log addition.
My list of file is very big. I am trying out a vim regular expression so it will match the file name eg file1 in file1.elf and use it to create name for the log file. I am trying out like this
s/\(\(\<\w\+\)\#<=\.elf\)/\1 >\2\.log/
Here i try to match a text which is proceeded by .elf and keep it in \1 , i expect the entrire file name to be in it and \2 i was hoping would just contain the file name minus extension. but this gives me
run file1 >file1.run i.e \1 dose not take the full file name, it has some how missed .elf extension. I can do \1\.elf to get proper result but i was wondering why the expression is not working as i expected?
You use \#<= in your match pattern. This is the positiv lookahead assertion. As per documentation (:help /\#<=1),
Matches with zero width if the preceding atom matches just before what follows
The important part is that it matches with zero width, this is what you are experiancing, the .elf (which follows) is matched but with zero widht, so that \1 does not contain the suffix .elf.
Instead, it would be easier to go with a
%s/\v(.*)\.elf$/run \1.elf > \1.log/
Here, I've used \v to turn on very magic (:help magic). With this turned on, you don't need al those backslashes when you use grouping parantheses.
Then there is (.*) to match and store the filename up until
\.elf$ which seems to be each files suffix.
In the substitution part, after the / I add the literal run followed by \1. \1 will be replaced by the stored filename (without .elf suffix).
The \#<= seems pointless and unneeded. Removing it gets you the desired behavior.

Resources