├── LICENSE ├── README.md ├── chromeserv.el ├── devtools.html ├── devtools.js └── manifest.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Tomasz Szarstuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Chrome extension integrating devtools with Emacs 2 | ================================================ 3 | 4 | This extension is supposed to provide some features of emacsclient command 5 | line tool inside browser. Basic feature it tries to provide, is to allow 6 | opening source files in your Emacs from Chrome Devtool panels. 7 | 8 | ## How does it work? 9 | 10 | Extension hooks into `chrome.devtools.panels.setOpenResourceHandler`, which 11 | is trigger when user click link in panels. 12 | 13 | Once we get file details we can send it to http server inside emacs. It sent 14 | via XMLHttpReques with url-enncoded body having file url and line. 15 | 16 | There is lisp function on Emacs side, similar to `compilation-find-file` which 17 | searches path part of url inside `compilation-search-path`. This variable may 18 | already have reasonable paths if people are ruining unit tests, or jlint from Emacs. 19 | 20 | ## Installation 21 | 22 | Right now extension is still in development and is not relased. You need to 23 | checkout git repository and add it to your browser via "Loadn unpacked extension..." 24 | button. 25 | 26 | Once you have extension installed you will be able to open resource link in 27 | emacs by choosing right option from link context menu. If you want to open links 28 | to resources in emacs by default, you can change setting "Open links in" in 29 | "General" section of devtool settings. 30 | 31 | Extension requires small server running in Emacs which will listen to requests 32 | from Chrome Devtools. To run server you need to install `simple-httpd` package 33 | first. You can do that by calling in emacs 34 | 35 | M-x package-install 36 | 37 | Emacs will ask you for package name, which is `simple-httpd`. 38 | 39 | After installation you will need to change default port to 8080. I find that default 40 | `simple-httpd` port is often coliding with tomcat and other projects. You can use 41 | command 42 | 43 | M-x customize-variable 44 | 45 | to change value of `httpd-port` variable to 8081, which Chrome extension expects. 46 | After taht you can start server. 47 | 48 | M-x httpd-start 49 | 50 | The only remaining bit is loading emacs functions to deal with Chrome extension 51 | requests. Just load `chromeserv.el` file from this project folder. 52 | 53 | M-x load-file 54 | 55 | I am still thinking how to simplify setup on Emacs. 56 | 57 | ## Why not use native protocol? 58 | 59 | It is all possible from Emacs side, but apparently Chrome extensions are not 60 | allowed to used plain socket API. Ony Native apps. 61 | 62 | The Emacs server listens to TCP connection. TO establish connection we need 63 | to know host (default to localhost), port (often randomized by emacs) and 64 | security token. All that information is duped into server file when emacs 65 | server is started. It is still open question how to make Chrome know about 66 | this stuff with as little hassle to user as possible. Even Chrome apps are 67 | not allowed to access user filesystem. 68 | 69 | Once we get that information, we can connect to socket as described in 70 | [network communications guide at Chrome Developer Doc](http://developer.chrome.com/apps/app_network.html). 71 | 72 | To eval any list expression in emacs you can send through socket 73 | 74 | -auth -eval compilation-search-path 75 | 76 | The server will respond with something like: 77 | 78 | -print ("c:/Home/mobile&-html5"&_nil)&n 79 | 80 | Detailed description of protocol and available commands can be read in emacs 81 | documentation to `server-process-filter` function. 82 | 83 | ## How do you plan to have console mirrored in Emacs? 84 | 85 | Once we sort out reliable channel of communication, extension could add hook to 86 | [Devtools Console](http://developer.chrome.com/extensions/experimental_devtools_console.html), 87 | to get all messages. They could be forwarded to emacs and displayed in emacs 88 | buffer with whole editing power of Emacs. Extra minor modes like 89 | `compilation-shell-minor-mode` may than be used for extra features. 90 | 91 | It is still open question how to make user friendly management of multiple 92 | console buffers. 93 | 94 | ## Current Status 95 | 96 | Right now this project is only proof of concept, having basic functionality, opening 97 | files working. 98 | 99 | Any feedback is much appreciated. You can raise feature requests or report bugs 100 | at [project GitHub page](https://github.com/szarsti/chrome-emacsclient/issues) 101 | -------------------------------------------------------------------------------- /chromeserv.el: -------------------------------------------------------------------------------- 1 | ;;; chromeserv.el --- Collection of utilities used by chrome-emacsclient extension 2 | 3 | (require 'compile) 4 | (require 'url-parse) 5 | (require 'simple-httpd) 6 | 7 | 8 | (defun chromeserv-find-file (url line) 9 | "Find file to open in buffer by url. 10 | 11 | If file is not found in `compilation-search-path` then it will be opened via http." 12 | (message "chromeserv-find-file visiting %s, line %s" url line) 13 | (let ((path (car (split-string (url-filename (url-generic-parse-url url)) "?"))) 14 | (search-dirs compilation-search-path) 15 | (spec-dir (directory-file-name default-directory)) 16 | buffer this-dir this-parts filename parts) 17 | (setq filename (file-name-nondirectory path) 18 | parts (cdr (split-string (directory-file-name (file-name-directory path)) "/"))) 19 | (while (and search-dirs (null buffer)) 20 | (setq this-dir (or (car search-dirs) spec-dir) 21 | search-dirs (cdr search-dirs) 22 | this-parts parts) 23 | ; Strip potential top level paths to find common in path which exists on disk 24 | (while (and this-parts 25 | (not (file-exists-p (concat this-dir "/" (car this-parts))))) 26 | (setq this-parts (cdr this-parts))) 27 | ; Now try matching reminder of path 28 | (while (and (file-exists-p this-dir) this-parts) 29 | (setq this-dir (concat this-dir "/" (car this-parts)) 30 | this-parts (cdr this-parts))) 31 | (when (null this-parts) 32 | (let ((name (expand-file-name filename this-dir))) 33 | (setq buffer (and (file-exists-p name) 34 | (find-file-noselect name)))))) 35 | (if buffer 36 | (let ((win (get-buffer-window buffer))) 37 | (if win (select-window win) 38 | (switch-to-buffer buffer))) 39 | (browse-url-emacs url)) 40 | (goto-line line) 41 | (select-frame-set-input-focus (window-frame (selected-window))))) 42 | 43 | 44 | ;; Servlets 45 | 46 | (defun httpd/chromeserv/visit (proc _path query _req &rest _args) 47 | (let ((url (nth 1 (assoc "url" query))) 48 | (line (string-to-number (nth 1 (assoc "line" query))))) 49 | (chromeserv-find-file url line) 50 | (ignore-errors 51 | (with-temp-buffer "OK" (httpd-send-header proc 200))))) 52 | 53 | (provide 'chromeserv) 54 | -------------------------------------------------------------------------------- /devtools.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /devtools.js: -------------------------------------------------------------------------------- 1 | /*global chrome*/ 2 | 3 | /** 4 | * TODO: Add some authentication token to improve security of connection. Somehow there should be way to 5 | * pair emacs and browser 6 | */ 7 | function EmacsClient() { 8 | var host = 'localhost', 9 | port = 8080; 10 | 11 | function visit(resource, lineNo) { 12 | var req = new XMLHttpRequest(); 13 | req.open('POST', 'http://' + host + ':' + port + '/chromeserv/visit'); 14 | req.onerror = function() { 15 | alert('There was error sending request to emacs: ' +req.statusText); 16 | }; 17 | req.send([ 18 | 'url=' + encodeURIComponent(resource.url), 19 | 'line=' + lineNo 20 | ].join('&')); 21 | }; 22 | 23 | this.visit = visit; 24 | }; 25 | 26 | var client = new EmacsClient(); 27 | chrome.devtools.panels.setOpenResourceHandler(client.visit); 28 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Emacs Client", 4 | "description": "Extension allows to open your source files from Chrome Devtools in Emacs. It connects Chrome to Emacs server.", 5 | "version": "0.2.1", 6 | "devtools_page": "devtools.html" 7 | } 8 | --------------------------------------------------------------------------------