Quick talk+demo+live coding for Manila JavaScript meetup #5
Emacs Lisp
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.emacs.d
.gitignore
README.org

README.org

Emacs for JavaScript

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 KnockoutJS with One-Punch Man 👊

What’s this for?

Blame this post in Facebook:

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

Javascript and Emacs.

So, I’ll be showing off a setup for writing JS with Emacs 📓

I’ll try to cover Vim though 👍

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 👍

# 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

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 Secret Alien Technology (plus a bit of Human C)
  • So very functional!

Org Mode

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());

org core

(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))

org-bullets

Fancy list bullets instead of asterisks

(use-package org-bullets
  :ensure t
  :config
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

ob-http

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))

org-present

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))))

Magit

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)))

Emacs + JS

js2-mode

(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 latest js2-mode for printing path of a an object under point, saving it also in the kill ring. Contrast with json-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

js2-refactor

(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"))

auto-complete and ac-js2

(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))

json-snatcher

(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 with js2-print-json-path in actual JavaScript code.

web-beautify

;; 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))

tern (with auto-complete)

(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))

skewer-mode

(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))

Other Emacs packages

yasnippet

(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))))

web-mode

(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)))

react-snippets, angular-mode + angular-snippets

(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)))

projectile

(use-package projectile
  :diminish projectile-mode
  :ensure t
  :config
  (setq projectile-switch-project-action 'projectile-dired)
  (projectile-global-mode))

flycheck

(use-package flycheck
  :diminish flycheck-mode
  :ensure t
  :init
  (add-hook 'after-init-hook #'global-flycheck-mode))

smartparens

(use-package smartparens
  :diminish smartparens-mode
  :ensure t
  :config
  (use-package smartparens-config)
  (smartparens-global-mode 1))

emmet-mode (with auto-complete)

(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))

jade-mode, scss-mode, sass-mode

(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))

markdown-mode

(use-package markdown-mode
  :ensure t
  :mode "\\.md\\'")

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 🔥 and nyan-mode 🐱

TODO:

  • Helm (replacing Ido, basically a new Emacs UI)
  • Swank backend for Node.JS and in-browser JS (replacing skewer-mode)

Quick and Clean Emacs Setup

git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d

For the Vimpostors (Like me)

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.

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

Questions

U done yet?!? 🐱

Finis

Thanks! 💋