emacs-for-javascript icon indicating copy to clipboard operation
emacs-for-javascript copied to clipboard

Quick talk+demo+live coding for Manila JavaScript meetup #5

#+TITLE: Emacs for JavaScript #+AUTHOR: Zak B. Elep [email protected]

[[https://github.com/zakame/emacs-for-javascript]]

  • About Me
  • @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 [[https://github.com/zakame/knockout-1punch-talk][KnockoutJS with One-Punch Man]] :punch:

  • What's this for?

Blame this [[https://www.facebook.com/events/765455226922029/permalink/771885296279022/?ref=1&action_history=null][post in Facebook]]:

#+BEGIN_QUOTE If there is a talk I want to here(sic) badly it would involve two things:

=Javascript= and =Emacs=. #+END_QUOTE

So, I'll be showing off a setup for writing JS with Emacs :notebook:

I'll try to cover Vim though :+1:

  • Try this out!

This doc is on GitHub!

This is also an Emacs init file! :peace:

Should work on GNU Emacs 24.1 and up :+1:

#+BEGIN_SRC sh

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 #+END_SRC

  • JavaScript
  • 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/!
  • Emacs
  • =An OS masquerading as a text editor=
    • Probably one of the most portable OS ever
    • Good tooling/API to invoke external resources
  • Made with [[http://lispers.org][Secret Alien Technology]] (plus a bit of Human C)
  • So very /functional/!
  • Org Mode

This document is written with it! :+1:

  • [[https://github.com/rlister/org-present][org-present]] let's me present this as slides!
  • [[http://orgmode.org/worg/org-contrib/babel/][Babel]] lets me embed code in Org documents!

#+BEGIN_SRC js :results output var os = require('os'); console.log(os.platform()); #+END_SRC

#+RESULTS: : linux

  • Great for [[https://github.com/limist/literate-programming-examples][Literate Programming]]!
    • Bonus: [[http://www.howardism.org/Technical/Emacs/literate-devops.html][Literate DevOps]]!

** org core

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

** org-bullets

Fancy list bullets instead of asterisks

#+BEGIN_SRC emacs-lisp (use-package org-bullets :ensure t :config (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))) #+END_SRC

** ob-http

aka curl in Org!

#+BEGIN_SRC http :pretty GET https://api.github.com/repos/zakame/emacs-for-javascript/languages Accept: application/vnd.github.moondragon+json #+END_SRC

#+BEGIN_EXAMPLE #+RESULTS: : { : "Emacs Lisp": 14185 : } #+END_EXAMPLE

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

** org-present

Turn your Org outline into slides for meetups!

#+BEGIN_SRC emacs-lisp (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)))) #+END_SRC

  • Magit

The best porcelain for git! [[http://magit.vc]] :ok_hand:

#+BEGIN_SRC emacs-lisp (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))) #+END_SRC

  • Emacs + JS

** js2-mode

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

  • [[https://plus.google.com/u/0/112708775709583792684/posts/7pqnEkH6XYZ][Bin Chen from Google+]] says theres a =js2-print-json-path= command in the latest =js2-mode= for printing path of a an object under point, saving it also in the kill ring. Contrast with =json-snatcher= below.

#+BEGIN_SRC js 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 #+END_SRC

** js2-refactor

#+BEGIN_SRC emacs-lisp (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")) #+END_SRC

** auto-complete and ac-js2

#+BEGIN_SRC emacs-lisp (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 ""))

(use-package ac-js2 :defer t :ensure t :init (add-hook 'js2-mode-hook 'ac-js2-mode) (setq ac-js2-evaluate-calls t)) #+END_SRC

** json-snatcher

#+BEGIN_SRC emacs-lisp (use-package json-snatcher :ensure t :after js2-mode :config (bind-key "C-c C-g" 'jsons-print-path js2-mode-map)) #+END_SRC

  • works primarily in =JSON= buffers, contrast with =js2-print-json-path= in actual JavaScript code.

** web-beautify

#+BEGIN_SRC emacs-lisp ;; 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)) #+END_SRC

** tern (with auto-complete)

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

** skewer-mode

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

  • Other Emacs packages

** yasnippet

#+BEGIN_SRC emacs-lisp (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)))) #+END_SRC

** web-mode

#+BEGIN_SRC emacs-lisp (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))) #+END_SRC

** react-snippets, angular-mode + angular-snippets

#+BEGIN_SRC emacs-lisp (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))) #+END_SRC

** projectile

#+BEGIN_SRC emacs-lisp (use-package projectile :diminish projectile-mode :ensure t :config (setq projectile-switch-project-action 'projectile-dired) (projectile-global-mode)) #+END_SRC

** flycheck

#+BEGIN_SRC emacs-lisp (use-package flycheck :diminish flycheck-mode :ensure t :init (add-hook 'after-init-hook #'global-flycheck-mode)) #+END_SRC

** smartparens

#+BEGIN_SRC emacs-lisp (use-package smartparens :diminish smartparens-mode :ensure t :config (use-package smartparens-config) (smartparens-global-mode 1)) #+END_SRC

** emmet-mode (with auto-complete)

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

** jade-mode, scss-mode, sass-mode

#+BEGIN_SRC emacs-lisp (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)) #+END_SRC

** markdown-mode

#+BEGIN_SRC emacs-lisp (use-package markdown-mode :ensure t :mode "\.md\'") #+END_SRC

  • Even more Emacs goodness

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 :fire: and nyan-mode :cat:

TODO:

  • [[https://github.com/emacs-helm/helm][Helm]] (replacing Ido, basically a new Emacs UI)
  • [[https://github.com/swank-js/swank-js][Swank]] backend for Node.JS and in-browser JS (replacing skewer-mode)
  • Quick and Clean Emacs Setup
  • Use [[https://github.com/syl20bnr/spacemacs][spacemacs]]!

#+BEGIN_SRC sh git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d #+END_SRC

  • Install the [[https://github.com/syl20bnr/spacemacs/tree/master/layers/%252Blang/javascript][JavaScript configuration layer]]
  • For the Vimpostors (Like me)

Using [[https://github.com/junegunn/vim-plug][vim-plug]]:

#+BEGIN_EXAMPLE Plug 'pangloss/vim-javascript' Plug 'ternjs/tern_for_vim' Plug 'moll/vim-node' #+END_EXAMPLE

  • Add sensible.vim, UltiSnips, delimitMate, Unite (or fzf), etc.
  • And, because MS <3 JS

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

  • More information
  • Zakame's [[https://github.com/zakame/.emacs.d][~/.emacs.d]] and [[https://github.com/zakame/.vim][~/.vim]] configurations
  • [[https://github.com/azer/emacs][azer's JavaScript and Go setup for Emacs]]
  • [[https://truongtx.me/2014/02/23/set-up-javascript-development-environment-in-emacs][Trần Xuân Trường's blog on JS and Emacs]], plus [[https://truongtx.me/2014/03/10/emacs-setup-jsx-mode-and-jsx-syntax-checking][JSX setup with web-mode]]
  • Questions

U done yet?!? :cat:

  • Finis

Thanks! :kiss: