https://github.com/zakame/emacs-for-javascript
- @zakame in GitHub, Twitter, FB
- Co-Founder, Chief Architect, YOYO Holdings
- Recovering Sysadmin
- Hacks on Perl, Docker, Emacs, Android
Gave a talk last time on KnockoutJS with One-Punch Man š
Blame this post in Facebook:
If there is a talk I want to here(sic) badly it would involve two things:
Javascript
andEmacs
.
So, Iāll be showing off a setup for writing JS with Emacs š
Iāll try to cover Vim though š
This doc is on GitHub!
This is also an Emacs init file! :peace:
Should work on GNU Emacs 24.1 and up š
# clone to somewhere
git clone --recursive https://github.com/zakame/emacs-for-javascript.git
# run Emacs using this repo as a fake $HOME
HOME=./emacs-for-javascript /usr/bin/emacs
- Very C/Java like, from syntax perspective
- Good tooling for writing, error checking and beautifying
- Started on the browser, now on the server
- So functional!
An OS masquerading as a text editor
- Probably one of the most portable OS ever
- Good tooling/API to invoke external resources
- Made with Secret Alien Technology (plus a bit of Human C)
- So very functional!
This document is written with it! š
- org-present letās me present this as slides!
- Babel lets me embed code in Org documents!
var os = require('os');
console.log(os.platform());
- Great for Literate Programming!
- Bonus: Literate DevOps!
(use-package org
:ensure t
:mode ("\\.\\(org\\|org_archive\\)$" . org-mode)
:bind (("\C-cl" . org-store-link)
("\C-cc" . org-capture)
("\C-ca" . org-agenda)
("\C-cb" . org-iswitchb))
:config
;; make windmove work well with org-mode
(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)
;; add some langs to to babel
(org-babel-do-load-languages
'org-babel-load-languages
'((js . t)
(sh . t)))
;; other org tweaks
(setq org-ellipsis "ā¼"
org-src-fontify-natively t
org-src-preserve-indentation nil
org-edit-src-content-indentation 0))
Fancy list bullets instead of asterisks
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
aka curl in Org!
GET https://api.github.com/repos/zakame/emacs-for-javascript/languages
Accept: application/vnd.github.moondragon+json
#+RESULTS: : { : "Emacs Lisp": 14185 : }
(use-package ob-http
:after org
:ensure t
:config
(add-to-list 'org-babel-load-languages '(http . t))
(org-babel-do-load-languages
'org-babel-load-languages org-babel-load-languages))
Turn your Org outline into slides for meetups!
(use-package org-present
:bind (("C-c m" . org-present))
:ensure t
:config
(add-hook 'org-present-mode-hook
(lambda ()
(org-present-big)
(org-display-inline-images)))
(add-hook 'org-present-mode-quit-hook
(lambda ()
(org-present-small)
(org-remove-inline-images))))
The best porcelain for git! http://magit.vc š
(use-package magit
:ensure t
:defines magit-mode-map
:bind (("C-c g" . magit-status)
("M-g b" . magit-blame)
:map magit-mode-map
("v" . endless/visit-pull-request-url)
:map magit-status-mode-map
("q" . zakame/magit-quit-session))
:init
(setq magit-last-seen-setup-instructions "2.1.0")
(setq magit-push-always-verify nil)
:config
(defun endless/visit-pull-request-url ()
"Visit the current branch's PR on Github."
(interactive)
(browse-url
(format "https://github.com/%s/compare/%s"
(replace-regexp-in-string
"\\`.+github\\.com:\\(.+\\)\\.git\\'" "\\1"
(magit-get "remote"
(magit-get-upstream-remote)
"url"))
(magit-get-current-branch))))
(defun endless/add-PR-fetch ()
"If refs/pull is not defined on a GH repo, define it."
(let ((fetch-address
"+refs/pull/*/head:refs/pull/origin/*")
(magit-remotes
(magit-get-all "remote" "origin" "fetch")))
(unless (or (not magit-remotes)
(member fetch-address magit-remotes))
(when (string-match
"github" (magit-get "remote" "origin" "url"))
(magit-git-string
"config" "--add" "remote.origin.fetch"
fetch-address)))))
(add-hook 'magit-mode-hook #'endless/add-PR-fetch)
(defadvice magit-status (around magit-fullscreen activate)
(window-configuration-to-register :magit-fullscreen)
ad-do-it
(delete-other-windows))
(defun zakame/magit-quit-session ()
"Restores the previous window configuration and kills the magit buffer."
(interactive)
(kill-buffer)
(jump-to-register :magit-fullscreen)))
(use-package js2-mode
:ensure t
:interpreter (("node" . js2-mode))
:bind (:map js2-mode-map ("C-c C-p" . js2-print-json-path))
:mode "\\.\\(js\\|json\\)$"
:config
(add-hook 'js-mode-hook 'js2-minor-mode)
(setq js2-basic-offset 2
js2-highlight-level 3
js2-mode-show-parse-errors nil
js2-mode-show-strict-warnings nil))
- Bin Chen from Google+ says theres a
js2-print-json-path
command in the latestjs2-mode
for printing path of a an object under point, saving it also in the kill ring. Contrast withjson-snatcher
below.
var v = {
foo: "bar",
baz: "quuz",
xxx: {
aaa: "bbb",
ccc: {
ddd: "yyy"
}
}
};
// when point is under `yyy`, js2-print-json-path will save
// `xxx.ccc.ddd` in the kill ring
(use-package js2-refactor
:defer t
:diminish js2-refactor-mode
:commands js2-refactor-mode
:ensure t
:init
(add-hook 'js2-mode-hook #'js2-refactor-mode)
:config
(js2r-add-keybindings-with-prefix "C-c C-m"))
(use-package auto-complete
:diminish auto-complete-mode
:ensure t
:config
(use-package auto-complete-config)
(ac-config-default)
(add-to-list 'ac-modes 'html-mode)
(setq ac-use-menu-map t)
(ac-set-trigger-key "TAB")
(ac-set-trigger-key "<tab>"))
(use-package ac-js2
:defer t
:ensure t
:init
(add-hook 'js2-mode-hook 'ac-js2-mode)
(setq ac-js2-evaluate-calls t))
(use-package json-snatcher
:ensure t
:after js2-mode
:config
(bind-key "C-c C-g" 'jsons-print-path js2-mode-map))
- works primarily in
JSON
buffers, contrast withjs2-print-json-path
in actual JavaScript code.
;; also do `npm install -g js-beautify' in your shell
(use-package web-beautify
:after js2-mode
:ensure t
:config
(bind-key "C-c C-b" 'web-beautify-js js2-mode-map))
(use-package tern
:defer t
:diminish tern-mode
:ensure t
:init
(add-hook 'js2-mode-hook 'tern-mode))
;; auto-completion for Tern
(use-package tern-auto-complete
:ensure t
:after tern
:config
(tern-ac-setup))
(use-package skewer-mode
:bind (("C-c K" . run-skewer))
:diminish skewer-mode
:ensure t
:init
(add-hook 'js2-mode-hook 'skewer-mode)
(add-hook 'css-mode-hook 'skewer-css-mode)
(add-hook 'html-mode-hook 'skewer-html-mode))
(use-package yasnippet
:diminish yas-minor-mode
:ensure t
:init
(setq yas-verbosity 2)
:config
(yas-global-mode 1)
(push 'yas-hippie-try-expand hippie-expand-try-functions-list)
(add-hook 'term-mode-hook (lambda () (yas-minor-mode -1))))
(use-package web-mode
:ensure t
:mode "\\.html?\\'"
:init
(dolist (hook '(emmet-mode ac-emmet-html-setup ac-emmet-css-setup))
(add-hook 'web-mode-hook hook))
:config
(setq web-mode-markup-indent-offset 2
web-mode-css-indent-offset 2
web-mode-code-indent-offset 2
web-mode-enable-auto-pairing nil
web-mode-enable-auto-closing t
web-mode-enable-current-element-highlight t
web-mode-enable-current-column-highlight t
web-mode-ac-sources-alist
'(("css" . (ac-source-css-property ac-source-emmet-css-snippets))
("html" . (ac-source-emmet-html-aliases
ac-source-emmet-html-snippets))))
(add-hook 'web-mode-before-auto-complete-hooks
'(lambda ()
(let ((web-mode-cur-language (web-mode-language-at-pos)))
(if (string= web-mode-cur-language "css")
(setq emmet-use-css-transform t)
(setq emmet-use-css-transform nil)))))
(defun zakame/sp-web-mode-code-context-p (id action context)
"Set smartparens context when in web-mode."
(and (eq action 'insert)
(not (or (get-text-property (point) 'part-side)
(get-text-property (point) 'block-side)))))
(sp-local-pair 'web-mode "<" nil :when '(zakame/sp-web-mode-code-context-p)))
(use-package react-snippets
:ensure t)
(use-package angular-mode
:ensure t
:config
(mapc (lambda (mode)
(add-to-list 'ac-modes mode))
'(angular-mode angular-html-mode)))
(use-package angular-snippets
:ensure t
:config
(eval-after-load "web-mode"
'(bind-key "C-c C-d" 'ng-snip-show-docs-at-point web-mode-map)))
(use-package projectile
:diminish projectile-mode
:ensure t
:config
(setq projectile-switch-project-action 'projectile-dired)
(projectile-global-mode))
(use-package flycheck
:diminish flycheck-mode
:ensure t
:init
(add-hook 'after-init-hook #'global-flycheck-mode))
(use-package smartparens
:diminish smartparens-mode
:ensure t
:config
(use-package smartparens-config)
(smartparens-global-mode 1))
(use-package emmet-mode
:diminish emmet-mode
:ensure t
:init
(dolist (hook '(sgml-mode-hook css-mode-hook kolon-mode-hook))
(add-hook hook 'emmet-mode)))
;; AutoComplete for emmet
(use-package ac-emmet
:ensure t
:commands (ac-emmet-html-setup ac-emmet-css-setup)
:init
(add-hook 'sgml-mode-hook 'ac-emmet-html-setup)
(add-hook 'css-mode-hook 'ac-emmet-css-setup))
(mapc (lambda (mode)
(if (package-installed-p mode)
t
(if (assoc mode package-archive-contents)
(package-install mode)
(progn
(package-refresh-contents)
(package-install mode)))))
'(jade-mode scss-mode sass-mode))
(use-package markdown-mode
:ensure t
:mode "\\.md\\'")
Be sure to check out the ./.emacs.d/init.el for more!
- use-package
- Ido (lightweight item selection framework)
- Recentf
- undo-tree
- Eshell
Also, emacs-fireplace š„ and nyan-mode š±
TODO:
- Helm (replacing Ido, basically a new Emacs UI)
- Swank backend for Node.JS and in-browser JS (replacing skewer-mode)
- Use spacemacs!
git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d
- Install the JavaScript configuration layer
Using vim-plug:
Plug 'pangloss/vim-javascript' Plug 'ternjs/tern_for_vim' Plug 'moll/vim-node'
- Add sensible.vim, UltiSnips, delimitMate, Unite (or fzf), etc.
I only learned of TypeScript just now (lolwut) but fortunately thereās already an Emacs environment for it:
https://github.com/ananthakumaran/tide
Go bonkers! :D
- Zakameās ~/.emacs.d and ~/.vim configurations
- azerās JavaScript and Go setup for Emacs
- Trįŗ§n XuĆ¢n TrĘ°į»ngās blog on JS and Emacs, plus JSX setup with web-mode
U done yet?!? š±
Thanks! š