file_regex for Cargo builds in Sublime Text 3
Question
What would be the right file_regex
to capture Cargo / Rustc's error messages in a Sublime Text 3 build system? I'm asking specifically about relatively recent cargo/rustc versions (it seems that the older versions used a somewhat more easily parsable single-line error output format).
Example
Example output of cargo build
on a broken hello-world project (default code autogenerated by cargo new --bin broken
, with one double quote removed to create an error message):
error: unterminated double quote string
--> src/main.rs:2:14
|
2 | println!("Hello, world!);
| ______________^
3 | | }
| |__^
error: aborting due to previous error
error: Could not compile `broken`.
The relative file path is src/main.rs
, line-column is 2:14
, the error message that I personally would prefer to see directly between the lines is
unterminated double quote string
1st Solution Attempt
This kind-of works, but it doesn't capture the error messages properly, because they are on a separate line that preceeds the line with the file path and line numbers:
{
"name": "cargo build",
"shell_cmd": "cargo build",
"working_dir":
"/home/you/path/to/cargo/project/with/the/toml",
"file_regex":
"^ *--> *([a-zA-Z0-9_/.]+):([0-9]+):([0-9]+)()$"
},
2nd Solution Attempt
This funny regex here that uses this awesome lookahead-with-matching-groups-trick:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
would have solved the problem, but Sublime doesn't seem to work with multiline regexes.
regex sublimetext3 rust-cargo
|
show 1 more comment
Question
What would be the right file_regex
to capture Cargo / Rustc's error messages in a Sublime Text 3 build system? I'm asking specifically about relatively recent cargo/rustc versions (it seems that the older versions used a somewhat more easily parsable single-line error output format).
Example
Example output of cargo build
on a broken hello-world project (default code autogenerated by cargo new --bin broken
, with one double quote removed to create an error message):
error: unterminated double quote string
--> src/main.rs:2:14
|
2 | println!("Hello, world!);
| ______________^
3 | | }
| |__^
error: aborting due to previous error
error: Could not compile `broken`.
The relative file path is src/main.rs
, line-column is 2:14
, the error message that I personally would prefer to see directly between the lines is
unterminated double quote string
1st Solution Attempt
This kind-of works, but it doesn't capture the error messages properly, because they are on a separate line that preceeds the line with the file path and line numbers:
{
"name": "cargo build",
"shell_cmd": "cargo build",
"working_dir":
"/home/you/path/to/cargo/project/with/the/toml",
"file_regex":
"^ *--> *([a-zA-Z0-9_/.]+):([0-9]+):([0-9]+)()$"
},
2nd Solution Attempt
This funny regex here that uses this awesome lookahead-with-matching-groups-trick:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
would have solved the problem, but Sublime doesn't seem to work with multiline regexes.
regex sublimetext3 rust-cargo
Can you include a sample of an error output? Along withfile_regex
there is alsoline_regex
that can be paired with it for situations where the error output is on two lines. However it works by matchingline_regex
and then going backwards to get the file, so if the outputs are in the wrong order it may not work.
– OdatNurd
Nov 13 '18 at 17:43
@OdatNurd I've updated the question with an example error message. Thanks for the hint withline_regex
, will look up what that is, didn't know about it.
– Andrey Tyukin
Nov 13 '18 at 19:00
line_regex
doesn't seem to help here: it's only for the cases where file name and line/column are on different lines, but it does not help me to permute the matched groups into the right order.
– Andrey Tyukin
Nov 13 '18 at 19:06
Indeed so, unfortunately. Only thefile_regex
can match the name of the file, while theline_regex
can match everything BUT the file; in use the two merge together but since it matches line and then goes backwards to get the file, the output of this is in the wrong order.
– OdatNurd
Nov 13 '18 at 19:18
In such a case as far as I'm aware the only way to get it to be able to determine the error message in this case is to massage the output of the tool to conform to what Sublime expects. If you're only interested in inline build errors and not clickable build results, it's possible with some work to modify the internalexec
command to handle something like this, but that's more involved.
– OdatNurd
Nov 13 '18 at 19:20
|
show 1 more comment
Question
What would be the right file_regex
to capture Cargo / Rustc's error messages in a Sublime Text 3 build system? I'm asking specifically about relatively recent cargo/rustc versions (it seems that the older versions used a somewhat more easily parsable single-line error output format).
Example
Example output of cargo build
on a broken hello-world project (default code autogenerated by cargo new --bin broken
, with one double quote removed to create an error message):
error: unterminated double quote string
--> src/main.rs:2:14
|
2 | println!("Hello, world!);
| ______________^
3 | | }
| |__^
error: aborting due to previous error
error: Could not compile `broken`.
The relative file path is src/main.rs
, line-column is 2:14
, the error message that I personally would prefer to see directly between the lines is
unterminated double quote string
1st Solution Attempt
This kind-of works, but it doesn't capture the error messages properly, because they are on a separate line that preceeds the line with the file path and line numbers:
{
"name": "cargo build",
"shell_cmd": "cargo build",
"working_dir":
"/home/you/path/to/cargo/project/with/the/toml",
"file_regex":
"^ *--> *([a-zA-Z0-9_/.]+):([0-9]+):([0-9]+)()$"
},
2nd Solution Attempt
This funny regex here that uses this awesome lookahead-with-matching-groups-trick:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
would have solved the problem, but Sublime doesn't seem to work with multiline regexes.
regex sublimetext3 rust-cargo
Question
What would be the right file_regex
to capture Cargo / Rustc's error messages in a Sublime Text 3 build system? I'm asking specifically about relatively recent cargo/rustc versions (it seems that the older versions used a somewhat more easily parsable single-line error output format).
Example
Example output of cargo build
on a broken hello-world project (default code autogenerated by cargo new --bin broken
, with one double quote removed to create an error message):
error: unterminated double quote string
--> src/main.rs:2:14
|
2 | println!("Hello, world!);
| ______________^
3 | | }
| |__^
error: aborting due to previous error
error: Could not compile `broken`.
The relative file path is src/main.rs
, line-column is 2:14
, the error message that I personally would prefer to see directly between the lines is
unterminated double quote string
1st Solution Attempt
This kind-of works, but it doesn't capture the error messages properly, because they are on a separate line that preceeds the line with the file path and line numbers:
{
"name": "cargo build",
"shell_cmd": "cargo build",
"working_dir":
"/home/you/path/to/cargo/project/with/the/toml",
"file_regex":
"^ *--> *([a-zA-Z0-9_/.]+):([0-9]+):([0-9]+)()$"
},
2nd Solution Attempt
This funny regex here that uses this awesome lookahead-with-matching-groups-trick:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
would have solved the problem, but Sublime doesn't seem to work with multiline regexes.
regex sublimetext3 rust-cargo
regex sublimetext3 rust-cargo
edited Nov 14 '18 at 0:28
Andrey Tyukin
asked Nov 13 '18 at 17:21
Andrey TyukinAndrey Tyukin
27.2k42349
27.2k42349
Can you include a sample of an error output? Along withfile_regex
there is alsoline_regex
that can be paired with it for situations where the error output is on two lines. However it works by matchingline_regex
and then going backwards to get the file, so if the outputs are in the wrong order it may not work.
– OdatNurd
Nov 13 '18 at 17:43
@OdatNurd I've updated the question with an example error message. Thanks for the hint withline_regex
, will look up what that is, didn't know about it.
– Andrey Tyukin
Nov 13 '18 at 19:00
line_regex
doesn't seem to help here: it's only for the cases where file name and line/column are on different lines, but it does not help me to permute the matched groups into the right order.
– Andrey Tyukin
Nov 13 '18 at 19:06
Indeed so, unfortunately. Only thefile_regex
can match the name of the file, while theline_regex
can match everything BUT the file; in use the two merge together but since it matches line and then goes backwards to get the file, the output of this is in the wrong order.
– OdatNurd
Nov 13 '18 at 19:18
In such a case as far as I'm aware the only way to get it to be able to determine the error message in this case is to massage the output of the tool to conform to what Sublime expects. If you're only interested in inline build errors and not clickable build results, it's possible with some work to modify the internalexec
command to handle something like this, but that's more involved.
– OdatNurd
Nov 13 '18 at 19:20
|
show 1 more comment
Can you include a sample of an error output? Along withfile_regex
there is alsoline_regex
that can be paired with it for situations where the error output is on two lines. However it works by matchingline_regex
and then going backwards to get the file, so if the outputs are in the wrong order it may not work.
– OdatNurd
Nov 13 '18 at 17:43
@OdatNurd I've updated the question with an example error message. Thanks for the hint withline_regex
, will look up what that is, didn't know about it.
– Andrey Tyukin
Nov 13 '18 at 19:00
line_regex
doesn't seem to help here: it's only for the cases where file name and line/column are on different lines, but it does not help me to permute the matched groups into the right order.
– Andrey Tyukin
Nov 13 '18 at 19:06
Indeed so, unfortunately. Only thefile_regex
can match the name of the file, while theline_regex
can match everything BUT the file; in use the two merge together but since it matches line and then goes backwards to get the file, the output of this is in the wrong order.
– OdatNurd
Nov 13 '18 at 19:18
In such a case as far as I'm aware the only way to get it to be able to determine the error message in this case is to massage the output of the tool to conform to what Sublime expects. If you're only interested in inline build errors and not clickable build results, it's possible with some work to modify the internalexec
command to handle something like this, but that's more involved.
– OdatNurd
Nov 13 '18 at 19:20
Can you include a sample of an error output? Along with
file_regex
there is also line_regex
that can be paired with it for situations where the error output is on two lines. However it works by matching line_regex
and then going backwards to get the file, so if the outputs are in the wrong order it may not work.– OdatNurd
Nov 13 '18 at 17:43
Can you include a sample of an error output? Along with
file_regex
there is also line_regex
that can be paired with it for situations where the error output is on two lines. However it works by matching line_regex
and then going backwards to get the file, so if the outputs are in the wrong order it may not work.– OdatNurd
Nov 13 '18 at 17:43
@OdatNurd I've updated the question with an example error message. Thanks for the hint with
line_regex
, will look up what that is, didn't know about it.– Andrey Tyukin
Nov 13 '18 at 19:00
@OdatNurd I've updated the question with an example error message. Thanks for the hint with
line_regex
, will look up what that is, didn't know about it.– Andrey Tyukin
Nov 13 '18 at 19:00
line_regex
doesn't seem to help here: it's only for the cases where file name and line/column are on different lines, but it does not help me to permute the matched groups into the right order.– Andrey Tyukin
Nov 13 '18 at 19:06
line_regex
doesn't seem to help here: it's only for the cases where file name and line/column are on different lines, but it does not help me to permute the matched groups into the right order.– Andrey Tyukin
Nov 13 '18 at 19:06
Indeed so, unfortunately. Only the
file_regex
can match the name of the file, while the line_regex
can match everything BUT the file; in use the two merge together but since it matches line and then goes backwards to get the file, the output of this is in the wrong order.– OdatNurd
Nov 13 '18 at 19:18
Indeed so, unfortunately. Only the
file_regex
can match the name of the file, while the line_regex
can match everything BUT the file; in use the two merge together but since it matches line and then goes backwards to get the file, the output of this is in the wrong order.– OdatNurd
Nov 13 '18 at 19:18
In such a case as far as I'm aware the only way to get it to be able to determine the error message in this case is to massage the output of the tool to conform to what Sublime expects. If you're only interested in inline build errors and not clickable build results, it's possible with some work to modify the internal
exec
command to handle something like this, but that's more involved.– OdatNurd
Nov 13 '18 at 19:20
In such a case as far as I'm aware the only way to get it to be able to determine the error message in this case is to massage the output of the tool to conform to what Sublime expects. If you're only interested in inline build errors and not clickable build results, it's possible with some work to modify the internal
exec
command to handle something like this, but that's more involved.– OdatNurd
Nov 13 '18 at 19:20
|
show 1 more comment
2 Answers
2
active
oldest
votes
The TL;DR version of the answer is that unfortunately I think the only way to get Sublime to recognize the error output in your question is to either make the tool generate output in a different format (either directly or by way of some filter app that sits in the middle) or by creating your own custom build target for your build that can recognize this error output (but it would only work for inline errors, see below).
Background
Build systems in Sublime Text have two regular expressions that can be applied to try and match error output/build results, file_regex
and line_regex
. Both are applied to the results of the build in the output panel in order to obtain the list of build results.
file_regex
is the "general purpose" regex for matching build results, and should contain anywhere from 2 to 4 capture groups that capture the appropriate data. The capture groups (used in order) are filename
, line
, column
, message
.
line_regex
is used in cases where the information about location of the error is on a different line than the error message/location. Here the captures are in the order line
, column
, message
and you can use anywhere from 1 to 3 of them.
In both cases the captures are used in the order given above, which can necessitate having empty capture groups to make sure things line up as expected.
In normal use you just use file_regex
and nothing else, and that captures the results for you. If you also use line_regex
, then internally Sublime matches on line_regex
instead, and then if it finds a match, it looks backwards through the result output for the first line that matches file_regex
, and combines the results from the captures together.
Inherently this means that there are some restrictions placed on the sort of results that Sublime can capture; the file name has to appear prior to the other information about the error in order for it to be captured.
Massaging the output
In your example above, the error is displayed first and the location for the error is displayed second, so inherently there's no way to correctly associate the two regular expression matches together.
The most common way around this is to modify the output of the tool in order to rework it into a format that Sublime can detect with the above regular expressions.
For example you might change your build so that it executes your command and pipes the result to another shell script or program that can alter the information on the fly as it goes through. Another example would be to alter your build so that it invokes a script/batch file that executes the tool and does the output alteration internally, so that the final output matches what Sublime expects.
Custom build targets
Although there's no way to use the regex system to match your build output fully, if you're primarily interested in inline build errors being displayed, there is some recourse if you want to get your hands dirty with a little Sublime plugin development. In this case you need to know a bit of Python. There is documentation on custom build targets as well as the Sublime API available.
Internally, when you run a build, Sublime gathers the information from the sublime-build
file, expands any variables in it, and then invokes the exec
internal command to actually perform the build providing the keys in the sublime-build
as arguments (some, such as selector
, are not provided because Sublime handles that for you), and it's the exec
command that sets the file_regex
and line_regex
settings into the output buffer.
From here, the applied settings are used by the Sublime core directly to perform navigation on build results, such as by clicking on the results to open the file, or using the navigation commands to go to the next and previous errors.
However, it's the exec
command that is responsible for using those same results to show you the inline build errors, so it's possible to still get inline error messages working, although result navigation can only take you to the location in the file.
One of the keys that you can provide in a sublime-build
file is target
, which specifies the command that should execute the build; this defaults to exec
if not given.
By creating your own custom command that mimics what exec
does and using it in the target
directive of your sublime-build
, you can hook into the build process to capture the appropriate data.
The exec
command is stored in Default/exec.py
, which you can view by using the View Package File
command from the command palette.
As a minimal example, the following plugin defines a new command named cargo_exec
which exactly mimics what the exec
command does. The call to self.output_view.find_all_results_with_text()
is the API call that makes the Sublime core return all of the error information from the build output view, which is used to set up the phantoms used for inline build errors.
By modifying that code to examine the contents of the buffer and use your custom knowledge of what errors look like, the remainder of the code in the core exec
command will display the inline errors for you.
import sublime
import sublime_plugin
from Default.exec import ExecCommand
# Subclass the exec command to hook into the output processing.
class CargoExecCommand(ExecCommand):
def run(self, **kwargs):
# If we are being told to kill a running build, kill it right away
# and leave.
if kwargs.get("kill", False):
return super().run(kill=True)
# Use our super class to execute the build from this point.
super().run(**kwargs)
# override the super class method so we can handle output as it
# arrives in the output panel.
def service_text_queue(self):
is_empty = False
with self.text_queue_lock:
if len(self.text_queue) == 0:
# this can happen if a new build was started, which will clear
# the text_queue
return
characters = self.text_queue.popleft()
is_empty = (len(self.text_queue) == 0)
self.output_view.run_command(
'append',
{'characters': characters, 'force': True, 'scroll_to_end': True})
if self.show_errors_inline and characters.find('n') >= 0:
errs = self.output_view.find_all_results_with_text()
errs_by_file = {}
for file, line, column, text in errs:
if file not in errs_by_file:
errs_by_file[file] =
errs_by_file[file].append((line, column, text))
self.errs_by_file = errs_by_file
self.update_phantoms()
if not is_empty:
sublime.set_timeout(self.service_text_queue, 1)
# Use the latest build results to add inline errors to newly opened files.
class CargoExecEventListener(sublime_plugin.EventListener):
def on_load(self, view):
w = view.window()
if w is not None:
w.run_command('cargo_exec', {'update_phantoms_only': True})
To use this as a custom build target, you need to add a couple of extra keys to your sublime-build
file:
// Specify a custom build target to execute this build, and specify what
// argument to the command will cause it to cancel a build that is currently
// running.
"target": "cargo_exec",
"cancel": {"kill": true},
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: ifrustc
usedprint
instead ofprintln
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.
– Andrey Tyukin
Nov 14 '18 at 0:41
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order infile_regex
or the capture groups don't capture what you expect.
– OdatNurd
Nov 14 '18 at 0:47
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
add a comment |
This AWK script combines the error message with the line numbers, and brings it into the order that Sublime wants:
awk 'BEGIN { errmsg="" } /error([E[0-9]+])?:.*/ {errmsg=$0; next} / *--> *.*/ { printf "%s::::%sn", $0, errmsg; next} {print $0}'
The output is trivially matched by the following regex:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
You can use |
and AWK scripts inside the shell_cmd
, so this build config captures all the error messages and displays them at the correct line numbers:
{
"name": "cargo build",
"working_dir": "/wherever/your/project",
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /error(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
"file_regex": " +--> +([a-zA-Z_\/.-]+):(\d+):(\d+)::::(.*)"
}
This also treats warning
s in the same way:
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /(error|warning)(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53286429%2ffile-regex-for-cargo-builds-in-sublime-text-3%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The TL;DR version of the answer is that unfortunately I think the only way to get Sublime to recognize the error output in your question is to either make the tool generate output in a different format (either directly or by way of some filter app that sits in the middle) or by creating your own custom build target for your build that can recognize this error output (but it would only work for inline errors, see below).
Background
Build systems in Sublime Text have two regular expressions that can be applied to try and match error output/build results, file_regex
and line_regex
. Both are applied to the results of the build in the output panel in order to obtain the list of build results.
file_regex
is the "general purpose" regex for matching build results, and should contain anywhere from 2 to 4 capture groups that capture the appropriate data. The capture groups (used in order) are filename
, line
, column
, message
.
line_regex
is used in cases where the information about location of the error is on a different line than the error message/location. Here the captures are in the order line
, column
, message
and you can use anywhere from 1 to 3 of them.
In both cases the captures are used in the order given above, which can necessitate having empty capture groups to make sure things line up as expected.
In normal use you just use file_regex
and nothing else, and that captures the results for you. If you also use line_regex
, then internally Sublime matches on line_regex
instead, and then if it finds a match, it looks backwards through the result output for the first line that matches file_regex
, and combines the results from the captures together.
Inherently this means that there are some restrictions placed on the sort of results that Sublime can capture; the file name has to appear prior to the other information about the error in order for it to be captured.
Massaging the output
In your example above, the error is displayed first and the location for the error is displayed second, so inherently there's no way to correctly associate the two regular expression matches together.
The most common way around this is to modify the output of the tool in order to rework it into a format that Sublime can detect with the above regular expressions.
For example you might change your build so that it executes your command and pipes the result to another shell script or program that can alter the information on the fly as it goes through. Another example would be to alter your build so that it invokes a script/batch file that executes the tool and does the output alteration internally, so that the final output matches what Sublime expects.
Custom build targets
Although there's no way to use the regex system to match your build output fully, if you're primarily interested in inline build errors being displayed, there is some recourse if you want to get your hands dirty with a little Sublime plugin development. In this case you need to know a bit of Python. There is documentation on custom build targets as well as the Sublime API available.
Internally, when you run a build, Sublime gathers the information from the sublime-build
file, expands any variables in it, and then invokes the exec
internal command to actually perform the build providing the keys in the sublime-build
as arguments (some, such as selector
, are not provided because Sublime handles that for you), and it's the exec
command that sets the file_regex
and line_regex
settings into the output buffer.
From here, the applied settings are used by the Sublime core directly to perform navigation on build results, such as by clicking on the results to open the file, or using the navigation commands to go to the next and previous errors.
However, it's the exec
command that is responsible for using those same results to show you the inline build errors, so it's possible to still get inline error messages working, although result navigation can only take you to the location in the file.
One of the keys that you can provide in a sublime-build
file is target
, which specifies the command that should execute the build; this defaults to exec
if not given.
By creating your own custom command that mimics what exec
does and using it in the target
directive of your sublime-build
, you can hook into the build process to capture the appropriate data.
The exec
command is stored in Default/exec.py
, which you can view by using the View Package File
command from the command palette.
As a minimal example, the following plugin defines a new command named cargo_exec
which exactly mimics what the exec
command does. The call to self.output_view.find_all_results_with_text()
is the API call that makes the Sublime core return all of the error information from the build output view, which is used to set up the phantoms used for inline build errors.
By modifying that code to examine the contents of the buffer and use your custom knowledge of what errors look like, the remainder of the code in the core exec
command will display the inline errors for you.
import sublime
import sublime_plugin
from Default.exec import ExecCommand
# Subclass the exec command to hook into the output processing.
class CargoExecCommand(ExecCommand):
def run(self, **kwargs):
# If we are being told to kill a running build, kill it right away
# and leave.
if kwargs.get("kill", False):
return super().run(kill=True)
# Use our super class to execute the build from this point.
super().run(**kwargs)
# override the super class method so we can handle output as it
# arrives in the output panel.
def service_text_queue(self):
is_empty = False
with self.text_queue_lock:
if len(self.text_queue) == 0:
# this can happen if a new build was started, which will clear
# the text_queue
return
characters = self.text_queue.popleft()
is_empty = (len(self.text_queue) == 0)
self.output_view.run_command(
'append',
{'characters': characters, 'force': True, 'scroll_to_end': True})
if self.show_errors_inline and characters.find('n') >= 0:
errs = self.output_view.find_all_results_with_text()
errs_by_file = {}
for file, line, column, text in errs:
if file not in errs_by_file:
errs_by_file[file] =
errs_by_file[file].append((line, column, text))
self.errs_by_file = errs_by_file
self.update_phantoms()
if not is_empty:
sublime.set_timeout(self.service_text_queue, 1)
# Use the latest build results to add inline errors to newly opened files.
class CargoExecEventListener(sublime_plugin.EventListener):
def on_load(self, view):
w = view.window()
if w is not None:
w.run_command('cargo_exec', {'update_phantoms_only': True})
To use this as a custom build target, you need to add a couple of extra keys to your sublime-build
file:
// Specify a custom build target to execute this build, and specify what
// argument to the command will cause it to cancel a build that is currently
// running.
"target": "cargo_exec",
"cancel": {"kill": true},
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: ifrustc
usedprint
instead ofprintln
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.
– Andrey Tyukin
Nov 14 '18 at 0:41
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order infile_regex
or the capture groups don't capture what you expect.
– OdatNurd
Nov 14 '18 at 0:47
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
add a comment |
The TL;DR version of the answer is that unfortunately I think the only way to get Sublime to recognize the error output in your question is to either make the tool generate output in a different format (either directly or by way of some filter app that sits in the middle) or by creating your own custom build target for your build that can recognize this error output (but it would only work for inline errors, see below).
Background
Build systems in Sublime Text have two regular expressions that can be applied to try and match error output/build results, file_regex
and line_regex
. Both are applied to the results of the build in the output panel in order to obtain the list of build results.
file_regex
is the "general purpose" regex for matching build results, and should contain anywhere from 2 to 4 capture groups that capture the appropriate data. The capture groups (used in order) are filename
, line
, column
, message
.
line_regex
is used in cases where the information about location of the error is on a different line than the error message/location. Here the captures are in the order line
, column
, message
and you can use anywhere from 1 to 3 of them.
In both cases the captures are used in the order given above, which can necessitate having empty capture groups to make sure things line up as expected.
In normal use you just use file_regex
and nothing else, and that captures the results for you. If you also use line_regex
, then internally Sublime matches on line_regex
instead, and then if it finds a match, it looks backwards through the result output for the first line that matches file_regex
, and combines the results from the captures together.
Inherently this means that there are some restrictions placed on the sort of results that Sublime can capture; the file name has to appear prior to the other information about the error in order for it to be captured.
Massaging the output
In your example above, the error is displayed first and the location for the error is displayed second, so inherently there's no way to correctly associate the two regular expression matches together.
The most common way around this is to modify the output of the tool in order to rework it into a format that Sublime can detect with the above regular expressions.
For example you might change your build so that it executes your command and pipes the result to another shell script or program that can alter the information on the fly as it goes through. Another example would be to alter your build so that it invokes a script/batch file that executes the tool and does the output alteration internally, so that the final output matches what Sublime expects.
Custom build targets
Although there's no way to use the regex system to match your build output fully, if you're primarily interested in inline build errors being displayed, there is some recourse if you want to get your hands dirty with a little Sublime plugin development. In this case you need to know a bit of Python. There is documentation on custom build targets as well as the Sublime API available.
Internally, when you run a build, Sublime gathers the information from the sublime-build
file, expands any variables in it, and then invokes the exec
internal command to actually perform the build providing the keys in the sublime-build
as arguments (some, such as selector
, are not provided because Sublime handles that for you), and it's the exec
command that sets the file_regex
and line_regex
settings into the output buffer.
From here, the applied settings are used by the Sublime core directly to perform navigation on build results, such as by clicking on the results to open the file, or using the navigation commands to go to the next and previous errors.
However, it's the exec
command that is responsible for using those same results to show you the inline build errors, so it's possible to still get inline error messages working, although result navigation can only take you to the location in the file.
One of the keys that you can provide in a sublime-build
file is target
, which specifies the command that should execute the build; this defaults to exec
if not given.
By creating your own custom command that mimics what exec
does and using it in the target
directive of your sublime-build
, you can hook into the build process to capture the appropriate data.
The exec
command is stored in Default/exec.py
, which you can view by using the View Package File
command from the command palette.
As a minimal example, the following plugin defines a new command named cargo_exec
which exactly mimics what the exec
command does. The call to self.output_view.find_all_results_with_text()
is the API call that makes the Sublime core return all of the error information from the build output view, which is used to set up the phantoms used for inline build errors.
By modifying that code to examine the contents of the buffer and use your custom knowledge of what errors look like, the remainder of the code in the core exec
command will display the inline errors for you.
import sublime
import sublime_plugin
from Default.exec import ExecCommand
# Subclass the exec command to hook into the output processing.
class CargoExecCommand(ExecCommand):
def run(self, **kwargs):
# If we are being told to kill a running build, kill it right away
# and leave.
if kwargs.get("kill", False):
return super().run(kill=True)
# Use our super class to execute the build from this point.
super().run(**kwargs)
# override the super class method so we can handle output as it
# arrives in the output panel.
def service_text_queue(self):
is_empty = False
with self.text_queue_lock:
if len(self.text_queue) == 0:
# this can happen if a new build was started, which will clear
# the text_queue
return
characters = self.text_queue.popleft()
is_empty = (len(self.text_queue) == 0)
self.output_view.run_command(
'append',
{'characters': characters, 'force': True, 'scroll_to_end': True})
if self.show_errors_inline and characters.find('n') >= 0:
errs = self.output_view.find_all_results_with_text()
errs_by_file = {}
for file, line, column, text in errs:
if file not in errs_by_file:
errs_by_file[file] =
errs_by_file[file].append((line, column, text))
self.errs_by_file = errs_by_file
self.update_phantoms()
if not is_empty:
sublime.set_timeout(self.service_text_queue, 1)
# Use the latest build results to add inline errors to newly opened files.
class CargoExecEventListener(sublime_plugin.EventListener):
def on_load(self, view):
w = view.window()
if w is not None:
w.run_command('cargo_exec', {'update_phantoms_only': True})
To use this as a custom build target, you need to add a couple of extra keys to your sublime-build
file:
// Specify a custom build target to execute this build, and specify what
// argument to the command will cause it to cancel a build that is currently
// running.
"target": "cargo_exec",
"cancel": {"kill": true},
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: ifrustc
usedprint
instead ofprintln
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.
– Andrey Tyukin
Nov 14 '18 at 0:41
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order infile_regex
or the capture groups don't capture what you expect.
– OdatNurd
Nov 14 '18 at 0:47
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
add a comment |
The TL;DR version of the answer is that unfortunately I think the only way to get Sublime to recognize the error output in your question is to either make the tool generate output in a different format (either directly or by way of some filter app that sits in the middle) or by creating your own custom build target for your build that can recognize this error output (but it would only work for inline errors, see below).
Background
Build systems in Sublime Text have two regular expressions that can be applied to try and match error output/build results, file_regex
and line_regex
. Both are applied to the results of the build in the output panel in order to obtain the list of build results.
file_regex
is the "general purpose" regex for matching build results, and should contain anywhere from 2 to 4 capture groups that capture the appropriate data. The capture groups (used in order) are filename
, line
, column
, message
.
line_regex
is used in cases where the information about location of the error is on a different line than the error message/location. Here the captures are in the order line
, column
, message
and you can use anywhere from 1 to 3 of them.
In both cases the captures are used in the order given above, which can necessitate having empty capture groups to make sure things line up as expected.
In normal use you just use file_regex
and nothing else, and that captures the results for you. If you also use line_regex
, then internally Sublime matches on line_regex
instead, and then if it finds a match, it looks backwards through the result output for the first line that matches file_regex
, and combines the results from the captures together.
Inherently this means that there are some restrictions placed on the sort of results that Sublime can capture; the file name has to appear prior to the other information about the error in order for it to be captured.
Massaging the output
In your example above, the error is displayed first and the location for the error is displayed second, so inherently there's no way to correctly associate the two regular expression matches together.
The most common way around this is to modify the output of the tool in order to rework it into a format that Sublime can detect with the above regular expressions.
For example you might change your build so that it executes your command and pipes the result to another shell script or program that can alter the information on the fly as it goes through. Another example would be to alter your build so that it invokes a script/batch file that executes the tool and does the output alteration internally, so that the final output matches what Sublime expects.
Custom build targets
Although there's no way to use the regex system to match your build output fully, if you're primarily interested in inline build errors being displayed, there is some recourse if you want to get your hands dirty with a little Sublime plugin development. In this case you need to know a bit of Python. There is documentation on custom build targets as well as the Sublime API available.
Internally, when you run a build, Sublime gathers the information from the sublime-build
file, expands any variables in it, and then invokes the exec
internal command to actually perform the build providing the keys in the sublime-build
as arguments (some, such as selector
, are not provided because Sublime handles that for you), and it's the exec
command that sets the file_regex
and line_regex
settings into the output buffer.
From here, the applied settings are used by the Sublime core directly to perform navigation on build results, such as by clicking on the results to open the file, or using the navigation commands to go to the next and previous errors.
However, it's the exec
command that is responsible for using those same results to show you the inline build errors, so it's possible to still get inline error messages working, although result navigation can only take you to the location in the file.
One of the keys that you can provide in a sublime-build
file is target
, which specifies the command that should execute the build; this defaults to exec
if not given.
By creating your own custom command that mimics what exec
does and using it in the target
directive of your sublime-build
, you can hook into the build process to capture the appropriate data.
The exec
command is stored in Default/exec.py
, which you can view by using the View Package File
command from the command palette.
As a minimal example, the following plugin defines a new command named cargo_exec
which exactly mimics what the exec
command does. The call to self.output_view.find_all_results_with_text()
is the API call that makes the Sublime core return all of the error information from the build output view, which is used to set up the phantoms used for inline build errors.
By modifying that code to examine the contents of the buffer and use your custom knowledge of what errors look like, the remainder of the code in the core exec
command will display the inline errors for you.
import sublime
import sublime_plugin
from Default.exec import ExecCommand
# Subclass the exec command to hook into the output processing.
class CargoExecCommand(ExecCommand):
def run(self, **kwargs):
# If we are being told to kill a running build, kill it right away
# and leave.
if kwargs.get("kill", False):
return super().run(kill=True)
# Use our super class to execute the build from this point.
super().run(**kwargs)
# override the super class method so we can handle output as it
# arrives in the output panel.
def service_text_queue(self):
is_empty = False
with self.text_queue_lock:
if len(self.text_queue) == 0:
# this can happen if a new build was started, which will clear
# the text_queue
return
characters = self.text_queue.popleft()
is_empty = (len(self.text_queue) == 0)
self.output_view.run_command(
'append',
{'characters': characters, 'force': True, 'scroll_to_end': True})
if self.show_errors_inline and characters.find('n') >= 0:
errs = self.output_view.find_all_results_with_text()
errs_by_file = {}
for file, line, column, text in errs:
if file not in errs_by_file:
errs_by_file[file] =
errs_by_file[file].append((line, column, text))
self.errs_by_file = errs_by_file
self.update_phantoms()
if not is_empty:
sublime.set_timeout(self.service_text_queue, 1)
# Use the latest build results to add inline errors to newly opened files.
class CargoExecEventListener(sublime_plugin.EventListener):
def on_load(self, view):
w = view.window()
if w is not None:
w.run_command('cargo_exec', {'update_phantoms_only': True})
To use this as a custom build target, you need to add a couple of extra keys to your sublime-build
file:
// Specify a custom build target to execute this build, and specify what
// argument to the command will cause it to cancel a build that is currently
// running.
"target": "cargo_exec",
"cancel": {"kill": true},
The TL;DR version of the answer is that unfortunately I think the only way to get Sublime to recognize the error output in your question is to either make the tool generate output in a different format (either directly or by way of some filter app that sits in the middle) or by creating your own custom build target for your build that can recognize this error output (but it would only work for inline errors, see below).
Background
Build systems in Sublime Text have two regular expressions that can be applied to try and match error output/build results, file_regex
and line_regex
. Both are applied to the results of the build in the output panel in order to obtain the list of build results.
file_regex
is the "general purpose" regex for matching build results, and should contain anywhere from 2 to 4 capture groups that capture the appropriate data. The capture groups (used in order) are filename
, line
, column
, message
.
line_regex
is used in cases where the information about location of the error is on a different line than the error message/location. Here the captures are in the order line
, column
, message
and you can use anywhere from 1 to 3 of them.
In both cases the captures are used in the order given above, which can necessitate having empty capture groups to make sure things line up as expected.
In normal use you just use file_regex
and nothing else, and that captures the results for you. If you also use line_regex
, then internally Sublime matches on line_regex
instead, and then if it finds a match, it looks backwards through the result output for the first line that matches file_regex
, and combines the results from the captures together.
Inherently this means that there are some restrictions placed on the sort of results that Sublime can capture; the file name has to appear prior to the other information about the error in order for it to be captured.
Massaging the output
In your example above, the error is displayed first and the location for the error is displayed second, so inherently there's no way to correctly associate the two regular expression matches together.
The most common way around this is to modify the output of the tool in order to rework it into a format that Sublime can detect with the above regular expressions.
For example you might change your build so that it executes your command and pipes the result to another shell script or program that can alter the information on the fly as it goes through. Another example would be to alter your build so that it invokes a script/batch file that executes the tool and does the output alteration internally, so that the final output matches what Sublime expects.
Custom build targets
Although there's no way to use the regex system to match your build output fully, if you're primarily interested in inline build errors being displayed, there is some recourse if you want to get your hands dirty with a little Sublime plugin development. In this case you need to know a bit of Python. There is documentation on custom build targets as well as the Sublime API available.
Internally, when you run a build, Sublime gathers the information from the sublime-build
file, expands any variables in it, and then invokes the exec
internal command to actually perform the build providing the keys in the sublime-build
as arguments (some, such as selector
, are not provided because Sublime handles that for you), and it's the exec
command that sets the file_regex
and line_regex
settings into the output buffer.
From here, the applied settings are used by the Sublime core directly to perform navigation on build results, such as by clicking on the results to open the file, or using the navigation commands to go to the next and previous errors.
However, it's the exec
command that is responsible for using those same results to show you the inline build errors, so it's possible to still get inline error messages working, although result navigation can only take you to the location in the file.
One of the keys that you can provide in a sublime-build
file is target
, which specifies the command that should execute the build; this defaults to exec
if not given.
By creating your own custom command that mimics what exec
does and using it in the target
directive of your sublime-build
, you can hook into the build process to capture the appropriate data.
The exec
command is stored in Default/exec.py
, which you can view by using the View Package File
command from the command palette.
As a minimal example, the following plugin defines a new command named cargo_exec
which exactly mimics what the exec
command does. The call to self.output_view.find_all_results_with_text()
is the API call that makes the Sublime core return all of the error information from the build output view, which is used to set up the phantoms used for inline build errors.
By modifying that code to examine the contents of the buffer and use your custom knowledge of what errors look like, the remainder of the code in the core exec
command will display the inline errors for you.
import sublime
import sublime_plugin
from Default.exec import ExecCommand
# Subclass the exec command to hook into the output processing.
class CargoExecCommand(ExecCommand):
def run(self, **kwargs):
# If we are being told to kill a running build, kill it right away
# and leave.
if kwargs.get("kill", False):
return super().run(kill=True)
# Use our super class to execute the build from this point.
super().run(**kwargs)
# override the super class method so we can handle output as it
# arrives in the output panel.
def service_text_queue(self):
is_empty = False
with self.text_queue_lock:
if len(self.text_queue) == 0:
# this can happen if a new build was started, which will clear
# the text_queue
return
characters = self.text_queue.popleft()
is_empty = (len(self.text_queue) == 0)
self.output_view.run_command(
'append',
{'characters': characters, 'force': True, 'scroll_to_end': True})
if self.show_errors_inline and characters.find('n') >= 0:
errs = self.output_view.find_all_results_with_text()
errs_by_file = {}
for file, line, column, text in errs:
if file not in errs_by_file:
errs_by_file[file] =
errs_by_file[file].append((line, column, text))
self.errs_by_file = errs_by_file
self.update_phantoms()
if not is_empty:
sublime.set_timeout(self.service_text_queue, 1)
# Use the latest build results to add inline errors to newly opened files.
class CargoExecEventListener(sublime_plugin.EventListener):
def on_load(self, view):
w = view.window()
if w is not None:
w.run_command('cargo_exec', {'update_phantoms_only': True})
To use this as a custom build target, you need to add a couple of extra keys to your sublime-build
file:
// Specify a custom build target to execute this build, and specify what
// argument to the command will cause it to cancel a build that is currently
// running.
"target": "cargo_exec",
"cancel": {"kill": true},
answered Nov 13 '18 at 20:38
OdatNurdOdatNurd
8,96522335
8,96522335
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: ifrustc
usedprint
instead ofprintln
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.
– Andrey Tyukin
Nov 14 '18 at 0:41
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order infile_regex
or the capture groups don't capture what you expect.
– OdatNurd
Nov 14 '18 at 0:47
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
add a comment |
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: ifrustc
usedprint
instead ofprintln
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.
– Andrey Tyukin
Nov 14 '18 at 0:41
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order infile_regex
or the capture groups don't capture what you expect.
– OdatNurd
Nov 14 '18 at 0:47
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: if
rustc
used print
instead of println
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.– Andrey Tyukin
Nov 14 '18 at 0:41
That's impressive, but I somehow expected that passing four strings from one program to another shouldn't take much more than a single line of configuration. It even almost works without any massaging of the output: if
rustc
used print
instead of println
, it would work; likewise, had Sublime allowed to use multiline regex, then it would work too. I decided to use an AWK script to rewrite the error messages into the format that Sublime wants. It's ugly, but it fits into the said one (long) line, and it has no chance of sprawling into a "pet project" that will haunt me forever.– Andrey Tyukin
Nov 14 '18 at 0:41
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order in
file_regex
or the capture groups don't capture what you expect.– OdatNurd
Nov 14 '18 at 0:47
Indeed, this is one of the pitfalls of the current way this works and many are unhappy with it to some degree or another (including myself). Other failings include that even with the current system, items must appear in a certain order in
file_regex
or the capture groups don't capture what you expect.– OdatNurd
Nov 14 '18 at 0:47
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
The order is not the problem: you can work around it using lookaheads, Sublime's regex flavor supports it (see second solution attempt in the question for an example: it reorders 4 1 2 3 into 1 2 3 4). Still, writing an entire plugin simply because of a whim of some compiler-writer who decided to add too many line breaks seems like a disproportionally heavyweight solution. I think it's not even really sublime's responsibility: configuring parsing is much harder than configuring formatted printout. It would be much easier to fix on the side that emits the error messages.
– Andrey Tyukin
Nov 14 '18 at 0:51
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
Anyway, I thank you for your effort and the detailed explanation. I will keep this answer in mind as a possible entry point into sublime plugin development.
– Andrey Tyukin
Nov 14 '18 at 0:53
add a comment |
This AWK script combines the error message with the line numbers, and brings it into the order that Sublime wants:
awk 'BEGIN { errmsg="" } /error([E[0-9]+])?:.*/ {errmsg=$0; next} / *--> *.*/ { printf "%s::::%sn", $0, errmsg; next} {print $0}'
The output is trivially matched by the following regex:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
You can use |
and AWK scripts inside the shell_cmd
, so this build config captures all the error messages and displays them at the correct line numbers:
{
"name": "cargo build",
"working_dir": "/wherever/your/project",
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /error(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
"file_regex": " +--> +([a-zA-Z_\/.-]+):(\d+):(\d+)::::(.*)"
}
This also treats warning
s in the same way:
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /(error|warning)(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
add a comment |
This AWK script combines the error message with the line numbers, and brings it into the order that Sublime wants:
awk 'BEGIN { errmsg="" } /error([E[0-9]+])?:.*/ {errmsg=$0; next} / *--> *.*/ { printf "%s::::%sn", $0, errmsg; next} {print $0}'
The output is trivially matched by the following regex:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
You can use |
and AWK scripts inside the shell_cmd
, so this build config captures all the error messages and displays them at the correct line numbers:
{
"name": "cargo build",
"working_dir": "/wherever/your/project",
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /error(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
"file_regex": " +--> +([a-zA-Z_\/.-]+):(\d+):(\d+)::::(.*)"
}
This also treats warning
s in the same way:
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /(error|warning)(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
add a comment |
This AWK script combines the error message with the line numbers, and brings it into the order that Sublime wants:
awk 'BEGIN { errmsg="" } /error([E[0-9]+])?:.*/ {errmsg=$0; next} / *--> *.*/ { printf "%s::::%sn", $0, errmsg; next} {print $0}'
The output is trivially matched by the following regex:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
You can use |
and AWK scripts inside the shell_cmd
, so this build config captures all the error messages and displays them at the correct line numbers:
{
"name": "cargo build",
"working_dir": "/wherever/your/project",
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /error(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
"file_regex": " +--> +([a-zA-Z_\/.-]+):(\d+):(\d+)::::(.*)"
}
This also treats warning
s in the same way:
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /(error|warning)(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
This AWK script combines the error message with the line numbers, and brings it into the order that Sublime wants:
awk 'BEGIN { errmsg="" } /error([E[0-9]+])?:.*/ {errmsg=$0; next} / *--> *.*/ { printf "%s::::%sn", $0, errmsg; next} {print $0}'
The output is trivially matched by the following regex:
error(?:[Ed+])?: (?=.+n +--> +([a-zA-Z0-9_/.-]+):([d]+):([d]+))(.+)
You can use |
and AWK scripts inside the shell_cmd
, so this build config captures all the error messages and displays them at the correct line numbers:
{
"name": "cargo build",
"working_dir": "/wherever/your/project",
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /error(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
"file_regex": " +--> +([a-zA-Z_\/.-]+):(\d+):(\d+)::::(.*)"
}
This also treats warning
s in the same way:
"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg="" } /(error|warning)(\[E[0-9]+\])?:.*/ {errmsg=\$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", \$0, errmsg; next} {print \$0}'",
edited Nov 15 '18 at 22:02
answered Nov 14 '18 at 0:27
Andrey TyukinAndrey Tyukin
27.2k42349
27.2k42349
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53286429%2ffile-regex-for-cargo-builds-in-sublime-text-3%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Can you include a sample of an error output? Along with
file_regex
there is alsoline_regex
that can be paired with it for situations where the error output is on two lines. However it works by matchingline_regex
and then going backwards to get the file, so if the outputs are in the wrong order it may not work.– OdatNurd
Nov 13 '18 at 17:43
@OdatNurd I've updated the question with an example error message. Thanks for the hint with
line_regex
, will look up what that is, didn't know about it.– Andrey Tyukin
Nov 13 '18 at 19:00
line_regex
doesn't seem to help here: it's only for the cases where file name and line/column are on different lines, but it does not help me to permute the matched groups into the right order.– Andrey Tyukin
Nov 13 '18 at 19:06
Indeed so, unfortunately. Only the
file_regex
can match the name of the file, while theline_regex
can match everything BUT the file; in use the two merge together but since it matches line and then goes backwards to get the file, the output of this is in the wrong order.– OdatNurd
Nov 13 '18 at 19:18
In such a case as far as I'm aware the only way to get it to be able to determine the error message in this case is to massage the output of the tool to conform to what Sublime expects. If you're only interested in inline build errors and not clickable build results, it's possible with some work to modify the internal
exec
command to handle something like this, but that's more involved.– OdatNurd
Nov 13 '18 at 19:20