Skip to content

zakame/emacs-for-javascript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Ā 

History

56 Commits
Ā 
Ā 
Ā 
Ā 
Ā 
Ā 

Repository files navigation

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! šŸ’‹

About

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

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published