Commit 10b05c76 authored by Tharaka Wijebandara's avatar Tharaka Wijebandara Committed by Dan Abramov
Browse files

Open editor to exact column from build error overlay (#3465)

* Open editor to exact column from build error overlay

* Update launch editor validations
parent 85bf3a93
Showing with 39 additions and 10 deletions
+39 -10
...@@ -12,7 +12,9 @@ const launchEditorEndpoint = require('./launchEditorEndpoint'); ...@@ -12,7 +12,9 @@ const launchEditorEndpoint = require('./launchEditorEndpoint');
module.exports = function createLaunchEditorMiddleware() { module.exports = function createLaunchEditorMiddleware() {
return function launchEditorMiddleware(req, res, next) { return function launchEditorMiddleware(req, res, next) {
if (req.url.startsWith(launchEditorEndpoint)) { if (req.url.startsWith(launchEditorEndpoint)) {
launchEditor(req.query.fileName, req.query.lineNumber); const lineNumber = parseInt(req.query.lineNumber, 10) || 1;
const colNumber = parseInt(req.query.colNumber, 10) || 1;
launchEditor(req.query.fileName, lineNumber, colNumber);
res.end(); res.end();
} else { } else {
next(); next();
......
...@@ -103,7 +103,13 @@ function addWorkspaceToArgumentsIfExists(args, workspace) { ...@@ -103,7 +103,13 @@ function addWorkspaceToArgumentsIfExists(args, workspace) {
return args; return args;
} }
function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) { function getArgumentsForLineNumber(
editor,
fileName,
lineNumber,
colNumber,
workspace
) {
const editorBasename = path.basename(editor).replace(/\.(exe|cmd|bat)$/i, ''); const editorBasename = path.basename(editor).replace(/\.(exe|cmd|bat)$/i, '');
switch (editorBasename) { switch (editorBasename) {
case 'atom': case 'atom':
...@@ -112,17 +118,19 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) { ...@@ -112,17 +118,19 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) {
case 'subl': case 'subl':
case 'sublime': case 'sublime':
case 'sublime_text': case 'sublime_text':
return [fileName + ':' + lineNumber + ':' + colNumber];
case 'wstorm': case 'wstorm':
case 'charm': case 'charm':
return [fileName + ':' + lineNumber]; return [fileName + ':' + lineNumber];
case 'notepad++': case 'notepad++':
return ['-n' + lineNumber, fileName]; return ['-n' + lineNumber, '-c' + colNumber, fileName];
case 'vim': case 'vim':
case 'mvim': case 'mvim':
case 'joe': case 'joe':
return ['+' + lineNumber, fileName];
case 'emacs': case 'emacs':
case 'emacsclient': case 'emacsclient':
return ['+' + lineNumber, fileName]; return ['+' + lineNumber + ':' + colNumber, fileName];
case 'rmate': case 'rmate':
case 'mate': case 'mate':
case 'mine': case 'mine':
...@@ -132,7 +140,7 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) { ...@@ -132,7 +140,7 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) {
case 'code-insiders': case 'code-insiders':
case 'Code - Insiders': case 'Code - Insiders':
return addWorkspaceToArgumentsIfExists( return addWorkspaceToArgumentsIfExists(
['-g', fileName + ':' + lineNumber], ['-g', fileName + ':' + lineNumber + ':' + colNumber],
workspace workspace
); );
case 'appcode': case 'appcode':
...@@ -255,17 +263,24 @@ function printInstructions(fileName, errorMessage) { ...@@ -255,17 +263,24 @@ function printInstructions(fileName, errorMessage) {
} }
let _childProcess = null; let _childProcess = null;
function launchEditor(fileName, lineNumber) { function launchEditor(fileName, lineNumber, colNumber) {
if (!fs.existsSync(fileName)) { if (!fs.existsSync(fileName)) {
return; return;
} }
// Sanitize lineNumber to prevent malicious use on win32 // Sanitize lineNumber to prevent malicious use on win32
// via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333 // via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333
if (lineNumber && isNaN(lineNumber)) { // and it should be a positive integer
if (!(Number.isInteger(lineNumber) && lineNumber > 0)) {
return; return;
} }
// colNumber is optional, but should be a positive integer too
// default is 1
if (!(Number.isInteger(colNumber) && colNumber > 0)) {
colNumber = 1;
}
let [editor, ...args] = guessEditor(); let [editor, ...args] = guessEditor();
if (!editor) { if (!editor) {
...@@ -294,7 +309,13 @@ function launchEditor(fileName, lineNumber) { ...@@ -294,7 +309,13 @@ function launchEditor(fileName, lineNumber) {
let workspace = null; let workspace = null;
if (lineNumber) { if (lineNumber) {
args = args.concat( args = args.concat(
getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) getArgumentsForLineNumber(
editor,
fileName,
lineNumber,
colNumber,
workspace
)
); );
} else { } else {
args.push(fileName); args.push(fileName);
......
...@@ -30,7 +30,9 @@ ErrorOverlay.setEditorHandler(function editorHandler(errorLocation) { ...@@ -30,7 +30,9 @@ ErrorOverlay.setEditorHandler(function editorHandler(errorLocation) {
'?fileName=' + '?fileName=' +
window.encodeURIComponent(errorLocation.fileName) + window.encodeURIComponent(errorLocation.fileName) +
'&lineNumber=' + '&lineNumber=' +
window.encodeURIComponent(errorLocation.lineNumber || 1) window.encodeURIComponent(errorLocation.lineNumber || 1) +
'&colNumber=' +
window.encodeURIComponent(errorLocation.colNumber || 1)
); );
}); });
......
...@@ -4,6 +4,7 @@ import Anser from 'anser'; ...@@ -4,6 +4,7 @@ import Anser from 'anser';
export type ErrorLocation = {| export type ErrorLocation = {|
fileName: string, fileName: string,
lineNumber: number, lineNumber: number,
colNumber?: number,
|}; |};
const filePathRegex = /^\.(\/[^/\n ]+)+\.[^/\n ]+$/; const filePathRegex = /^\.(\/[^/\n ]+)+\.[^/\n ]+$/;
...@@ -25,6 +26,7 @@ function parseCompileError(message: string): ?ErrorLocation { ...@@ -25,6 +26,7 @@ function parseCompileError(message: string): ?ErrorLocation {
const lines: Array<string> = message.split('\n'); const lines: Array<string> = message.split('\n');
let fileName: string = ''; let fileName: string = '';
let lineNumber: number = 0; let lineNumber: number = 0;
let colNumber: number = 0;
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line: string = Anser.ansiToText(lines[i]).trim(); const line: string = Anser.ansiToText(lines[i]).trim();
...@@ -41,6 +43,8 @@ function parseCompileError(message: string): ?ErrorLocation { ...@@ -41,6 +43,8 @@ function parseCompileError(message: string): ?ErrorLocation {
const match: ?Array<string> = line.match(lineNumberRegexes[k]); const match: ?Array<string> = line.match(lineNumberRegexes[k]);
if (match) { if (match) {
lineNumber = parseInt(match[1], 10); lineNumber = parseInt(match[1], 10);
// colNumber starts with 0 and hence add 1
colNumber = parseInt(match[2], 10) + 1 || 1;
break; break;
} }
k++; k++;
...@@ -51,7 +55,7 @@ function parseCompileError(message: string): ?ErrorLocation { ...@@ -51,7 +55,7 @@ function parseCompileError(message: string): ?ErrorLocation {
} }
} }
return fileName && lineNumber ? { fileName, lineNumber } : null; return fileName && lineNumber ? { fileName, lineNumber, colNumber } : null;
} }
export default parseCompileError; export default parseCompileError;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment