├── .gitignore
├── README.md
├── design
├── logo-128px.png
├── logo-48px.png
├── logo-inner.png
├── logo.afdesign
├── logo.png
├── logo.svg
├── screenshot.afphoto
└── screenshot.png
└── src
├── background.js
├── logo-128px.png
├── logo-48px.png
├── manifest.json
├── openinide.html
├── openinide.js
├── options.html
├── options.js
├── panel.html
├── panel.js
└── tutorial-linkhandling.png
/.gitignore:
--------------------------------------------------------------------------------
1 | keyfile
2 | work
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Open in IntelliJ - Chrome DevTools Extension
2 | This is an extension for Google Chrome to open resources from the Dev Tools (like CSS, SCSS, JS files) directly inside your JetBrains IntelliJ IDE (IntelliJ IDEA, WebStorm, PHPStorm etc.)
3 |
4 |
5 | 
6 |
7 |
8 | ## Installation
9 |
10 | 1. Install the extension from the Chrome Web Store:
11 | https://chrome.google.com/webstore/detail/open-in-intellij/gpmmlokoechmmeboecialijibkjajlaj
12 |
13 | 2. Now you can right-click on any file link in Chrome Devtools and select "Open using Open In IntelliJ".
14 | If you want to open all files in IntelliJ automatically, open Chrome DevTools, go to Settings. Under *Extensions* -> *Link Handling* select *Open In IntelliJ*.
15 | .
16 |
17 |
18 | 3. Open one of your projects in your IntelliJ IDE (WebStorm, PHPStorm etc.).
19 | Open the corresponding website in Chrome, inspect it, right-click on any resource and select *Open in IntelliJ*.
20 | Now the resource will be opened in your IDE.
21 |
22 | 4. If the web root of your IntelliJ project is different from your project root, you have to do one the following methods in order for this extension to work:
23 | - Method 1: In IntelliJ right-click on the the directory that is the web root of the project and select *Mark directory as* -> *Sources Root*
24 | - Method 2: In Chrome go to chrome://extensions/ -> Open In Intellij -> Options. Under *Root Paths* set up the path mappings for your project. For example, if your site is www.yoursite.com (live) and yoursite.priv (local)) and within your IntelliJ project the web root for this site is under dist/web/, enter those site names under *Site* and the path under *Root Path*.
25 |
26 |
27 |
28 | ## Troubleshooting
29 | If the links don't open in your IDE, try one or more of the following steps:
30 |
31 | - Restart Chrome and your IntelliJ IDE. It never hurts to turn things off and on again.
32 |
33 | - Read the debug messages: Make sure the Devtools are undocked into a separate window (open the three-dot Chrome Devtools settings menu and select the first icon from "Dock side"). Then inspect the current DevTools window by pressing Ctrl+Shift+I (Windows) or Option+Command+I (Mac). Yes, you can actually inspect the DevTools window itself. Switch to the console tab, there will be debug messages from this extension like 'Open In IntelliJ - received open resource event'. This may help with your troubleshooting process.
34 |
35 | - Go to your IntelliJ/WebStorm/PHPStorm Settings -> Build,Execution,Deployment -> Debugger -> Built-In Server and check *Allow unsigned requests*.
36 |
37 | - With your IntelliJ IDE open, open the following URL in Chrome: http://localhost:63342/ - if you get a 404 Not Found page that means the IntelliJ API is working.
38 | Otherwise check the Port in IntelliJ Settings -> Build,Execution,Deployment -> Debugger -> Port. If the port is not 63342 go to your Chrome preferences -> Extensions -> Open In IntelliJ -> Options and adjust the URL under *Built-in Webserver URL*.
39 |
40 | - Check if the IntelliJ REST API is working: Open a project in IntelliJ, choose any file and copy the relative path. Now in Chrome try to open *http://localhost:63342/api/file?file=path/to/file.js*, where you replace the file parameter with the path you just copied. If that doesn't open the file in IntelliJ there is a problem with the IntelliJ API on your machine.
41 |
42 | - Make sure to check if you need to set up any path mappings (See instructions step 4)
43 |
44 |
--------------------------------------------------------------------------------
/design/logo-128px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/logo-128px.png
--------------------------------------------------------------------------------
/design/logo-48px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/logo-48px.png
--------------------------------------------------------------------------------
/design/logo-inner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/logo-inner.png
--------------------------------------------------------------------------------
/design/logo.afdesign:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/logo.afdesign
--------------------------------------------------------------------------------
/design/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/logo.png
--------------------------------------------------------------------------------
/design/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
--------------------------------------------------------------------------------
/design/screenshot.afphoto:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/screenshot.afphoto
--------------------------------------------------------------------------------
/design/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/design/screenshot.png
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 |
2 | (function() {
3 |
4 | var thePort = null;
5 | chrome.runtime.onConnect.addListener(function(port) {
6 | if (port.name !== "openinintellij") return;
7 | thePort = port;
8 | });
9 |
10 | var sendMessage = function(msg) {
11 | if (thePort) {
12 | thePort.postMessage(msg);
13 | }
14 | else {
15 | alert('Sorry, please open DevTools first!');
16 | }
17 | };
18 |
19 |
20 | chrome.tabs.onCreated.addListener(function (tab) {
21 | if (tab && tab.url) {
22 |
23 | var url = tab.url; // example: http://openfile/?/Users/test/projects/src/openinide.js&200
24 | if (url.startsWith('http://openfile/')) {
25 |
26 | chrome.tabs.remove(tab.id);
27 |
28 | var parts = url.split('?');
29 | var params = parts[1].split('&');
30 | var filePath = params[0];
31 | var lineNumber = params[1];
32 |
33 | sendMessage({
34 | file: filePath,
35 | line: lineNumber
36 | });
37 | }
38 |
39 | }
40 | });
41 |
42 |
43 |
44 | })();
--------------------------------------------------------------------------------
/src/logo-128px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/src/logo-128px.png
--------------------------------------------------------------------------------
/src/logo-48px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bernie43/open-in-intellij/933b948a1296a0cb13d07657f5c742ae184616ee/src/logo-48px.png
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Open In IntelliJ",
4 | "short_name": "Open In IntelliJ",
5 | "description": "Open files from Chrome Devtools in IntelliJ IDEs (Webstorm, PHPStorm etc.)",
6 | "version": "0.8",
7 | "devtools_page": "openinide.html",
8 | "options_ui": {
9 | "page": "options.html",
10 | "open_in_tab": true
11 | },
12 | "background": {
13 | "scripts": ["background.js"]
14 | },
15 | "permissions": [
16 | "tabs"
17 | ],
18 | "icons": {
19 | "48": "logo-48px.png",
20 | "128": "logo-128px.png" }
21 | }
--------------------------------------------------------------------------------
/src/openinide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/openinide.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | (function() {
4 |
5 |
6 | const consoleLog = function(sLogfn, args) {
7 | let messageJson = JSON.stringify(args);
8 | messageJson = messageJson.split('\'').join('\\\'');
9 | messageJson = messageJson.split('\\n').join('\\\\n');
10 | const cmd = sLogfn+'(JSON.parse(\''+messageJson+'\'));';
11 |
12 | chrome.devtools.inspectedWindow.eval(cmd);
13 | };
14 |
15 | const devConsoleError = function(message) {
16 | console.error(message);
17 | consoleLog('console.error', message);
18 | };
19 |
20 | const devConsoleLog = function(message) {
21 | console.log(message);
22 | consoleLog('console.log', message);
23 | };
24 |
25 | console.log('Open In IntelliJ - Extension loaded');
26 |
27 | if (typeof localStorage["enabled"] === "undefined") {
28 | localStorage["enabled"] = "1"; // default
29 | }
30 |
31 | // parseUri 1.2.2
32 | // (c) Steven Levithan
33 | // MIT License
34 | const parseUri = function(str) {
35 | const o = {
36 | key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
37 | q: {
38 | name: "queryKey",
39 | parser: /(?:^|&)([^&=]*)=?([^&]*)/g
40 | },
41 | parser: {
42 | strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/
43 | }
44 | };
45 |
46 | let m = o.parser["strict"].exec(str),
47 | uri = {},
48 | i = 14;
49 |
50 | while (i--) uri[o.key[i]] = m[i] || "";
51 |
52 | uri[o.q.name] = {};
53 | uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
54 | if ($1) uri[o.q.name][$1] = $2;
55 | });
56 |
57 | return uri;
58 | };
59 |
60 |
61 | const openInChromePanel = function(url, lineNumber) {
62 | chrome.devtools.panels.openResource(url, lineNumber);
63 | };
64 |
65 |
66 | const readURLContent = function(url, thisServer, filePath, hasRootPath, urlOrig, lineNumber) {
67 |
68 | console.log('Open In IntelliJ - calling IntelliJ API:', url);
69 |
70 | let xhr = new XMLHttpRequest();
71 |
72 | const xhrEvent = function() {
73 |
74 | let bOK = false;
75 |
76 | if (!xhr || xhr.readyState == XMLHttpRequest.DONE) {
77 | if (xhr) {
78 | switch (xhr.status) {
79 | case 200:
80 | console.log('Open In IntelliJ - IntelliJ API response:', 'HTTP 200 OK - file opened in IntelliJ successfully');
81 | bOK = true;
82 | break;
83 | case 0:
84 | console.log('Open In IntelliJ - IntelliJ API response:', 'Error 0');
85 | devConsoleError('Couldn\'t open file in IntelliJ! Please first start your IDE and open the project.\n(IntelliJ API Request URL: ' + url + ')');
86 | break;
87 | case 404:
88 | console.log('Open In IntelliJ - IntelliJ API response:', 'HTTP Error 404');
89 | let sErrorAdd = 'Please first open the project in your IDE.';
90 | if (!hasRootPath) {
91 | sErrorAdd += '\nAlso make sure the file ' + filePath + ' can be found relative to your project root. Otherwise please map your web document root to the appropriate folder within your project. See options: chrome-extension://jeanncccmcklcoklpimhmpkgphdingci/options.html\n';
92 | }
93 | devConsoleError('Couldn\'t open file in IntelliJ: File not found! ' + sErrorAdd + '\n(IntelliJ API Request URL: ' + url + ')');
94 | break;
95 | default:
96 | console.log('Open In IntelliJ - IntelliJ API response:', 'HTTP Error ' + xhr.status);
97 | devConsoleError('Couldn\'t open file in IntelliJ! HTTP error ' + xhr.status + ' for IntelliJ API Request URL ' + url);
98 | break;
99 | }
100 | xhr = null;
101 | }
102 |
103 | if (!bOK) {
104 | console.log('Open In IntelliJ - failed, opening resource in Chrome instead');
105 | openInChromePanel(urlOrig, lineNumber);
106 | }
107 | }
108 | };
109 |
110 | xhr.onreadystatechange = xhrEvent;
111 | xhr.onerror = xhrEvent;
112 | xhr.open('GET', url, true);
113 | xhr.send(null);
114 | };
115 |
116 |
117 |
118 | chrome.devtools.panels.create("Open In IntelliJ", "logo-48px.png", "panel.html");
119 |
120 |
121 |
122 | //
123 | // https://developer.chrome.com/extensions/devtools_panels#method-setOpenResourceHandler
124 | //
125 | chrome.devtools.panels.setOpenResourceHandler(function onOpenResource(resource, lineNumber) {
126 |
127 | const url = resource.url;
128 |
129 | console.log('Open In IntelliJ - received open resource event:', url, lineNumber);
130 |
131 | const urlParse = parseUri(url);
132 |
133 | let openInChrome = false;
134 |
135 | let isAbsolute = false;
136 |
137 | if (url.startsWith("/")) {
138 | // URL is actually an absolute path on the file system
139 | isAbsolute = true;
140 | }
141 |
142 | if (urlParse.protocol == "file") {
143 | // Absolute path on file system (Chrome Devtools workspace mapping)
144 | isAbsolute = true;
145 | }
146 |
147 | if (localStorage["enabled"] != "1") {
148 | // Extension is disabled => Open in Chrome Resource Panel
149 | openInChrome = true;
150 | console.log('Open In IntelliJ - You disabled this extension, resources will open in Chrome. To enable this extension again click the "Open In IntelliJ" tab in the Devtools');
151 | }
152 | if (urlParse.protocol == "debugger") {
153 | // Links like 'debugger:///VM1192' => internal Chrome stuff, open in Chrome
154 | openInChrome = true;
155 | }
156 | if (typeof lineNumber === "undefined") {
157 | // No line number => Resource was most likely opened via right-click "Open Using Open In IntelliJ"
158 | // => force open with intellij
159 | openInChrome = false;
160 | }
161 | if (urlParse.protocol == "webpack") {
162 | // Links like 'webpack:///./node_modules/react-dom/cjs/react-dom.development.js' or 'webpack:///(webpack)-dev-server/client?0ee4'
163 | urlParse.path = urlParse.path.substring(1);
164 | urlParse.path = urlParse.path.replace(/[\(\)']+/g, '');
165 | }
166 |
167 |
168 | if (openInChrome) {
169 | console.log('Open In IntelliJ - opening resource in Chrome:', url, lineNumber)
170 | openInChromePanel(url, lineNumber);
171 | }
172 | else {
173 | const filePath = urlParse.path;
174 | let fileString = filePath;
175 |
176 | if (!isAbsolute) {
177 | const isSourceMappedStylesheet = resource.type && resource.type == 'sm-stylesheet';
178 | if (isSourceMappedStylesheet) {
179 | fileString = fileString.replace(/^(\/source\/)/,'');
180 | }
181 |
182 | if (fileString.startsWith('/')) {
183 | fileString = fileString.substring(1);
184 | }
185 | }
186 |
187 | let rootPaths = {};
188 | if (typeof localStorage["rootPaths"] !== "undefined") {
189 | rootPaths = JSON.parse(localStorage["rootPaths"]);
190 | }
191 |
192 | let hasRootPath = false;
193 | let thisServer = urlParse.host + (urlParse.port ? ':' + urlParse.port : '');
194 |
195 | let foundRootPath = rootPaths[thisServer]; // check for user path mappings
196 | if (!foundRootPath) {
197 | thisServer = urlParse.protocol + "://" + thisServer;
198 | foundRootPath = rootPaths[thisServer];
199 | }
200 | if (!foundRootPath) {
201 | foundRootPath = rootPaths[thisServer + "/"];
202 | }
203 | if (!foundRootPath) {
204 | foundRootPath = rootPaths[thisServer + urlParse.directory];
205 | }
206 | if (foundRootPath) {
207 | fileString = foundRootPath.replace(/\/$/, "") + "/" + fileString.replace(/^\//,"");
208 | hasRootPath = true;
209 | }
210 |
211 | console.log('Open In IntelliJ - destination resource path:', fileString);
212 |
213 | const intellijServer = localStorage["intellijserver"] || 'http://localhost:63342';
214 |
215 | //
216 | // IntelliJ REST API!
217 | // http://develar.org/idea-rest-api/
218 | //
219 | let ideOpenUrl = intellijServer + '/api/file?file=' + encodeURI(fileString);
220 |
221 | if (lineNumber) {
222 | ideOpenUrl += '&line=' + lineNumber;
223 | }
224 |
225 | readURLContent(ideOpenUrl, thisServer, filePath, hasRootPath, url, lineNumber);
226 | }
227 | });
228 |
229 |
230 |
231 | const port = chrome.runtime.connect({name: 'openinintellij'});
232 |
233 | port.onMessage.addListener(function(msg) {
234 |
235 | console.log('Open In IntelliJ - opening file from IntelliJ in Chrome', msg);
236 |
237 | const file = 'file://'+decodeURIComponent(msg.file);
238 | let line = parseInt(msg.line);
239 | if (line > 0) {
240 | line--;
241 | }
242 |
243 | chrome.devtools.panels.openResource(file, line, function(res) {
244 | if (res.code == "E_NOTFOUND") {
245 | devConsoleLog(res);
246 | alert("\n\n----------------------------------------------------\n\nDevTools couldn't open "+file+".\n\nMake sure the file is within one of your Workspaces in DevTools.\n\n----------------------------------------------------\n\n\n\n");
247 | }
248 | });
249 | });
250 |
251 |
252 |
253 |
254 | })();
--------------------------------------------------------------------------------
/src/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Open In IntelliJ Options
4 |
5 |
53 |
54 |
55 |
56 |
Open In IntelliJ
57 |
58 |
59 |
60 |
61 |
62 |
Root Paths
63 |
64 |
65 | Site (e.g. www.mysite.com)
66 | Relative path of web document root inside your IntelliJ project (e.g. dist/www/)
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
IntelliJ Settings
107 |
108 |
109 |
Built-in Webserver URL
110 |
(Default: http://localhost:63342)
111 |
This extension uses the Built-in Webserver of the IntelliJ platform, which is activated by default, in combination with the IntelliJ REST API, to open the files. Usually you won't need to change this setting.
112 |
To activate auto open, besides checking the checkbox above, you need to go to Devtools Settings (F1) -> General. Change the very last setting, 'Link Handling' from auto to Open In IntelliJ.
85 |
86 |
87 |
88 |
89 |
90 | To disable auto open again, just uncheck the above checkbox, you don't neet to change Link Handling back to auto.
91 |