javascript stuff

This commit is contained in:
John Doty 2018-03-21 06:18:07 -07:00
parent c4e74d2121
commit 351d0dbc69
8 changed files with 1277 additions and 19 deletions

View file

@ -255,6 +255,9 @@
(when (memq window-system '(mac ns))
(exec-path-from-shell-initialize))
;; Company mode everywhere. What could go wrong?
(global-company-mode)
;; =================================================================
;; Text mode configuration.
;; =================================================================
@ -514,9 +517,6 @@
(add-to-list 'auto-mode-alist '("\\.cool$" . csharp-mode))
(add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode))
(eval-after-load
'company
'(add-to-list 'company-backends 'company-omnisharp))
;; =================================================================
;; "XML" Support
@ -579,13 +579,6 @@
;; Flycheck
;; =================================================================
(require 'flycheck)
;; disable jshint since we prefer eslint checking
(setq-default flycheck-disabled-checkers
(append flycheck-disabled-checkers
'(javascript-jshint)))
;; use eslint with web-mode for jsx files
(flycheck-add-mode 'javascript-eslint 'web-mode)
;; customize flycheck temp file prefix
(setq-default flycheck-temp-prefix ".flycheck")
@ -625,17 +618,34 @@
;; =================================================================
(autoload 'python-mode "python-mode" "Python editing mode." t)
(setq auto-mode-alist
(cons '("\\.py$" . python-mode) auto-mode-alist))
(setq interpreter-mode-alist
(cons '("python" . python-mode) interpreter-mode-alist))
(add-to-list 'auto-mode-alist '("\\.py$" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
;; =================================================================
;; JavaScript Support
;; =================================================================
(autoload 'js2-mode "js2-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
(add-to-list 'auto-mode-alist '("\\.jsx$" . web-mode))
(require 'rjsx-mode)
(require 'prettier-js)
(require 'flycheck-flow)
(require 'flow-minor-mode)
;; disable jshint since we prefer eslint checking
(setq-default flycheck-disabled-checkers
(append flycheck-disabled-checkers
'(javascript-jshint)))
(flycheck-add-next-checker 'javascript-eslint 'javascript-flow)
(add-to-list 'auto-mode-alist '("\\.js$" . rjsx-mode))
(add-to-list 'auto-mode-alist '("\\.jsx$" . rjsx-mode))
(defun my-js-mode-hook ()
"My custom javascript mode hook."
(add-node-modules-path)
(flow-minor-enable-automatically)
(prettier-js-mode))
(add-hook 'rjsx-mode-hook #'my-js-mode-hook)
;; =================================================================
;; Ruby Mode

View file

@ -14,6 +14,11 @@
'(comint-input-ignoredups t)
'(comint-prompt-read-only t)
'(comint-scroll-to-bottom-on-input t)
'(company-backends
(quote
(company-bbdb company-nxml company-css company-eclim company-semantic company-clang company-xcode company-cmake company-capf company-files
(company-dabbrev-code company-gtags company-etags company-keywords)
company-oddmuse company-dabbrev company-flow)))
'(css-indent-offset 2)
'(debug-on-error nil)
'(fast-lock-cache-directories (quote ("~/flc-cache")))
@ -46,7 +51,7 @@
((sequence "TODO" "|" "DONE" "ABANDONED" "DEFERRED"))))
'(package-selected-packages
(quote
(company omnisharp geiser cider clojure-mode graphviz-dot-mode multi-term xterm-color thrift markdown-mode tuareg merlin ag use-package flycheck dockerfile-mode js2-mode web-mode zencoding-mode tss switch-window python-mode paredit magit lua-mode go-mode go-autocomplete exec-path-from-shell csharp-mode color-theme-solarized color-theme-monokai auto-complete auto-complete-nxml flymake flyspell json-mode popup ruby-mode)))
(mocha add-node-modules-path rjsx-mode xref-js2 js2-refactor company omnisharp geiser cider clojure-mode graphviz-dot-mode multi-term xterm-color thrift markdown-mode tuareg merlin ag use-package flycheck dockerfile-mode js2-mode web-mode zencoding-mode tss switch-window python-mode paredit magit lua-mode go-mode go-autocomplete exec-path-from-shell csharp-mode color-theme-solarized color-theme-monokai auto-complete auto-complete-nxml flymake flyspell json-mode popup ruby-mode)))
'(reb-re-syntax (quote string))
'(rmail-mail-new-frame t)
'(safe-local-variable-values

View file

@ -1,6 +1,6 @@
(
(:id "sha1:24c7a1e6369fef1e50de1deb1a9e5bbc68f80c8b" :fingerprint "sha1:26:26:88:6a:58:94:85:2f:98:ce:97:a0:0d:93:75:63:0a:9e:44:b5" :host "orgmode.org:443" :conditions (:insecure :unknown-ca :invalid))
(:id "sha1:60f141fb7e2767fbc9d5f309850c9db8bfaadb86" :fingerprint "sha1:f3:eb:c5:20:3c:f3:c8:79:46:3b:2d:d4:b7:c2:12:09:54:0e:d9:3b" :host "github-production-release-asset-2e65be.s3.amazonaws.com:443" :conditions (:insecure :unknown-ca :invalid))
(:id "sha1:379522f41fcdf5d279b33c30780e7512c9348430" :fingerprint "sha1:d4:ee:9d:2a:67:12:b3:61:4c:27:2d:15:8b:04:fc:c8:ca:08:a0:b6" :host "github.com:443" :conditions (:insecure :unknown-ca :invalid))
(:id "sha1:24c7a1e6369fef1e50de1deb1a9e5bbc68f80c8b" :fingerprint "sha1:fe:3b:22:d5:9b:33:20:74:3c:0d:7e:d2:7d:71:41:5d:84:e7:ca:82" :host "orgmode.org:443" :conditions (:insecure :unknown-ca :invalid))
(:id "sha1:85457c729378cc93c732b6a3941c8e4f9c2e60f3" :fingerprint "sha1:ab:a6:d7:6a:b3:d3:63:fa:19:0d:65:41:60:23:6e:ef:d3:2a:46:dc" :host "marmalade-repo.org:443" :conditions (:unknown-ca :invalid))
)

208
site-lisp/company-flow.el Normal file
View file

@ -0,0 +1,208 @@
;;; company-flow.el --- Flow backend for company-mode -*- lexical-binding: t -*-
;; Copyright (C) 2016 by Aaron Jensen
;; Author: Aaron Jensen <aaronjensen@gmail.com>
;; URL: https://github.com/aaronjensen/company-flow
;; Version: 0.1.0
;; Package-Requires: ((company "0.8.0") (dash "2.13.0"))
;;; Commentary:
;; This package adds support for flow to company. It requires
;; flow to be in your path.
;; To use it, add to your company-backends:
;; (eval-after-load 'company
;; '(add-to-list 'company-backends 'company-flow))
;;; License:
;; This file is not part of GNU Emacs.
;; However, it is distributed under the same license.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
(require 'company)
(require 'dash)
(defgroup company-flow ()
"Flow company backend."
:group 'company
:prefix "company-flow-")
(defcustom company-flow-executable "flow"
"Flow executable to run."
:group 'company-flow
:type 'string)
(make-variable-buffer-local 'company-flow-executable)
(defcustom company-flow-modes '(
js-mode
js-jsx-mode
js2-mode
js2-jsx-mode
rjsx-mode
web-mode
)
"List of major modes where company-flow will be providing completions."
:type '(choice (const :tag "All" nil)
(repeat (symbol :tag "Major mode")))
:group 'company-flow)
(defun company-flow--handle-signal (process _event)
(when (memq (process-status process) '(signal exit))
(let ((callback (process-get process 'company-flow-callback))
(prefix (process-get process 'company-flow-prefix)))
(if (and (eq (process-status process) 'exit)
(eq (process-exit-status process) 0))
(funcall callback (->> process
company-flow--get-output
company-flow--parse-output
;; Remove nils
(--filter it)))
(funcall callback nil)))))
(defun company-flow--make-candidate (line)
"Creates a candidate with a meta property from LINE.
LINE is expected to look like:
registrationSuccess () => {type: 'REGISTRATION_SUCCESS'}"
(let ((first-space (string-match " " line)))
(when first-space
(let ((text (substring line 0 first-space))
(meta (substring line (+ 1 first-space))))
(propertize text 'meta meta)))))
(defun company-flow--parse-output (output)
(when (not (equal output "Error: not enough type information to autocomplete\n"))
(mapcar 'company-flow--make-candidate
(split-string output "\n"))))
(defun company-flow--get-output (process)
"Get the complete output of PROCESS."
(with-demoted-errors "Error while retrieving process output: %S"
(let ((pending-output (process-get process 'company-flow-pending-output)))
(apply #'concat (nreverse pending-output)))))
(defun company-flow--receive-checker-output (process output)
"Receive a syntax checking PROCESS OUTPUT."
(push output (process-get process 'company-flow-pending-output)))
(defun company-flow--process-send-buffer (process)
"Send all contents of current buffer to PROCESS.
Sends all contents of the current buffer to the standard input of
PROCESS, and terminates standard input with EOF."
(save-restriction
(widen)
(process-send-region process (point-min) (point-max)))
;; flow requires EOF be on its own line
(process-send-string process "\n")
(process-send-eof process))
(defun company-flow--candidates-query (prefix callback)
(let* ((line (line-number-at-pos (point)))
(col (+ 1 (current-column)))
(command (list (executable-find company-flow-executable)
"autocomplete"
"--quiet"
buffer-file-name
(number-to-string line)
(number-to-string col)))
(process-connection-type nil)
(process (apply 'start-process "company-flow" nil command)))
(set-process-sentinel process #'company-flow--handle-signal)
(set-process-filter process #'company-flow--receive-checker-output)
(process-put process 'company-flow-callback callback)
(process-put process 'company-flow-prefix prefix)
(company-flow--process-send-buffer process)))
(defun company-flow--prefix ()
"Grab prefix for flow."
(and (or (null company-flow-modes)
(-contains? company-flow-modes major-mode))
company-flow-executable
(executable-find company-flow-executable)
buffer-file-name
(file-exists-p buffer-file-name)
(not (company-in-string-or-comment))
(locate-dominating-file buffer-file-name ".flowconfig")
(or (company-grab-symbol-cons "\\." 1)
'stop)))
(defun company-flow--annotation (candidate)
(format " %s" (get-text-property 0 'meta candidate)))
(defun company-flow--meta (candidate)
(format "%s: %s" candidate (get-text-property 0 'meta candidate)))
(defvar-local company-flow--debounce-state nil)
(defun company-flow--debounce-callback (prefix callback)
(lambda (candidates)
(let ((current-prefix (car company-flow--debounce-state))
(current-callback (cdr company-flow--debounce-state)))
(when (and current-prefix
(company-flow--string-prefix-p prefix current-prefix))
(setq company-flow--debounce-state nil)
(funcall current-callback (all-completions current-prefix candidates))))))
(defun company-flow--prefix-to-string (prefix)
"Return a string or nil from a prefix.
`company-grab-symbol-cons' can return (\"prefix\" . t) or just
\"prefix\", but we only care about the string."
(if (consp prefix)
(car prefix)
prefix))
(defun company-flow--string-prefix-p (a b)
(string-prefix-p (company-flow--prefix-to-string a) (company-flow--prefix-to-string b)))
(defun company-flow--debounce-async (prefix candidate-fn)
"Return a function that will properly debounce candidate queries by comparing the
in-flight query's prefix to PREFIX. CANDIDATE-FN should take two arguments, PREFIX
and the typical async callback.
Note that the candidate list provided to the callback by CANDIDATE-FN will be
filtered via `all-completions' with the most current prefix, so it is not necessary
to do this filtering in CANDIDATE-FN.
Use like:
(cons :async (company-flow--debounce-async arg 'your-query-fn))"
(lambda (callback)
(let ((current-prefix (car company-flow--debounce-state)))
(unless (and current-prefix
(company-flow--string-prefix-p prefix current-prefix))
(funcall candidate-fn prefix (company-flow--debounce-callback prefix callback)))
(setq company-flow--debounce-state (cons (company-flow--prefix-to-string prefix) callback)))))
;;;###autoload
(defun company-flow (command &optional arg &rest _args)
(interactive (list 'interactive))
(pcase command
(`interactive (company-begin-backend 'company-flow))
(`prefix (company-flow--prefix))
(`annotation (company-flow--annotation arg))
(`meta (company-flow--meta arg))
(`sorted t)
(`candidates (cons :async (company-flow--debounce-async arg 'company-flow--candidates-query)))))
(provide 'company-flow)
;;; company-flow.el ends here

View file

@ -0,0 +1,322 @@
;;; flow-minor-mode.el --- Flow type mode based on web-mode. -*- lexical-binding: t -*-
;; This source code is licensed under the BSD-style license found in
;; the LICENSE file in the root directory of this source tree.
;; Version: 0.3
;; URL: https://github.com/an-sh/flow-minor-mode
;; Package-Requires: ((emacs "25.1"))
;;; Commentary:
;; Minor mode for flowtype.org, derived from web-mode. Essentially a
;; rewrite of an official flow-for-emacs snippet into a standalone
;; mode with an improved usability.
;;
;; To enable this mode, enable it in your preferred javascript mode's
;; hooks:
;;
;; (add-hook 'js2-mode-hook 'flow-minor-enable-automatically)
;;
;; This will enable flow-minor-mode for a file only when there is a
;; "// @flow" declaration at the first line and a `.flowconfig` file
;; is present in the project. If you wish to enable flow-minor-mode
;; for all javascript files, use this instead:
;;
;; (add-hook 'js2-mode-hook 'flow-minor-mode)
;;
;;; Code:
(require 'xref)
(require 'json)
(require 'compile)
(defconst flow-minor-buffer "*Flow Output*")
(defcustom flow-minor-default-binary "flow"
"Flow executable to use when no project-specific binary is found."
:group 'flow-minor-mode
:type 'string)
(defcustom flow-minor-jump-other-window nil
"Jump to definitions in other window."
:group 'flow-minor-mode
:type 'boolean)
(defcustom flow-minor-stop-server-on-exit t
"Stop flow server when Emacs exits."
:group 'flow-minor-mode
:type 'boolean)
(defun flow-minor-column-at-pos (position)
"Column number at position.
POSITION point"
(save-excursion (goto-char position) (current-column)))
(defun flow-minor-region ()
"Format region data."
(if (use-region-p)
(let ((begin (region-beginning))
(end (region-end)))
(format ":%d:%d,%d:%d"
(line-number-at-pos begin)
(flow-minor-column-at-pos begin)
(line-number-at-pos end)
(flow-minor-column-at-pos end)))
""))
(defun flow-minor-binary ()
"Search for a local or global flow binary."
(let* ((root (locate-dominating-file
(or (buffer-file-name) default-directory)
"node_modules"))
(flow (and root
(expand-file-name "node_modules/.bin/flow"
root))))
(if (and flow (file-executable-p flow))
flow
flow-minor-default-binary)))
(defun flow-minor-cmd (&rest args)
"Run flow with arguments, outputs to flow buffer.
ARGS"
(apply #'call-process (flow-minor-binary) nil flow-minor-buffer t args))
(defun flow-minor-cmd-ignore-output (&rest args)
"Run flow with arguments, ignore output.
ARGS"
(apply #'call-process (flow-minor-binary) nil nil nil args))
(defun flow-minor-cmd-to-string (&rest args)
"Run flow with arguments, outputs to string.
ARGS"
(with-temp-buffer
(apply #'call-process (flow-minor-binary) nil t nil args)
(buffer-string)))
(defmacro flow-minor-with-flow (&rest body)
"With flow.
BODY progn"
`(progn
(flow-minor-cmd-ignore-output "start")
,@body))
(defmacro flow-minor-region-command (region-sym &rest body)
"Flow command on a region.
REGION-SYM symbol
BODY progn"
(declare (indent defun))
`(flow-minor-with-flow
(let ((,region-sym (concat (buffer-file-name) (flow-minor-region))))
(switch-to-buffer-other-window flow-minor-buffer)
(setf buffer-read-only nil)
(erase-buffer)
,@body)))
(defun flow-minor-status ()
"Show errors."
(interactive)
(flow-minor-region-command region
(flow-minor-cmd "status" "--from" "emacs")
(compilation-mode)
(setf buffer-read-only t)))
(defun flow-minor-suggest ()
"Fill types."
(interactive)
(flow-minor-region-command region
(flow-minor-cmd "suggest" region)
(diff-mode)
(setf buffer-read-only t)))
(defun flow-minor-coverage ()
"Show coverage."
(interactive)
(flow-minor-region-command region
(message "%s" region)
(flow-minor-cmd "coverage" region)
(compilation-mode)
(setf buffer-read-only t)))
(defvar flow-type-font-lock-highlight
'(
("\\([-_[:alnum:]]+\\)\\??:" . font-lock-variable-name-face)
("\\_<\\(true\\|false\\|null\\|undefined\\|void\\)\\_>" . font-lock-constant-face)
("<\\([-_[:alnum:]]+\\)>" . font-lock-type-face)
))
(defun flow-minor-colorize-buffer ()
(setq font-lock-defaults '(flow-type-font-lock-highlight))
(font-lock-fontify-buffer))
(defun flow-minor-colorize-type (text)
(with-temp-buffer
(insert text)
(flow-minor-colorize-buffer)
(buffer-string)))
(defun flow-minor-type-at-pos ()
"Show type at position."
(interactive)
(flow-minor-with-flow
(let* ((file (buffer-file-name))
(line (number-to-string (line-number-at-pos)))
(col (number-to-string (1+ (current-column))))
(type (flow-minor-cmd-to-string "type-at-pos" file line col)))
(message "%s" (flow-minor-colorize-type (car (split-string type "\n")))))))
(defun flow-minor-jump-to-definition ()
"Jump to definition."
(interactive)
(flow-minor-with-flow
(let* ((file (buffer-file-name))
(line (number-to-string (line-number-at-pos)))
(col (number-to-string (1+ (current-column))))
(location (json-read-from-string
(flow-minor-cmd-to-string "get-def" "--json" file line col)))
(path (alist-get 'path location))
(line (alist-get 'line location))
(offset-in-line (alist-get 'start location)))
(if (> (length path) 0)
(progn
(xref-push-marker-stack)
(funcall (if flow-minor-jump-other-window #'find-file-other-window #'find-file) path)
(goto-line line)
(when (> offset-in-line 0)
(forward-char (1- offset-in-line))))
(message "Not found")))))
(defvar flow-minor-mode-map (make-sparse-keymap)
"Keymap for flow-minor-mode.")
(define-key flow-minor-mode-map (kbd "M-.") 'flow-minor-jump-to-definition)
(define-key flow-minor-mode-map (kbd "M-,") 'xref-pop-marker-stack)
(define-key flow-minor-mode-map (kbd "C-c C-c s") 'flow-minor-status)
(define-key flow-minor-mode-map (kbd "C-c C-c c") 'flow-minor-coverage)
(define-key flow-minor-mode-map (kbd "C-c C-c t") 'flow-minor-type-at-pos)
(define-key flow-minor-mode-map (kbd "C-c C-c f") 'flow-minor-suggest)
(define-key flow-minor-mode-map [menu-bar flow-minor-mode]
(cons "Flow" flow-minor-mode-map))
(define-key flow-minor-mode-map [menu-bar flow-minor-mode flow-minor-mode-s]
'(menu-item "Flow status" flow-minor-status))
(define-key flow-minor-mode-map [menu-bar flow-minor-mode flow-minor-mode-c]
'(menu-item "Flow coverage" flow-minor-coverage))
(define-key flow-minor-mode-map [menu-bar flow-minor-mode flow-minor-mode-t]
'(menu-item "Type at point" flow-minor-type-at-pos))
(define-key flow-minor-mode-map [menu-bar flow-minor-mode flow-minor-mode-f]
'(menu-item "Type suggestions" flow-minor-suggest))
(defun flow-minor-stop-flow-server ()
"Stop flow hook."
(if flow-minor-stop-server-on-exit (ignore-errors (flow-minor-cmd-ignore-output "stop"))))
(add-hook 'kill-emacs-hook 'flow-minor-stop-flow-server t)
(defun flow-minor-maybe-delete-process (name)
(when (get-process name)
(delete-process name)))
(defun flow-minor-eldoc-sentinel (process _event)
(when (eq (process-status process) 'exit)
(if (eq (process-exit-status process) 0)
(with-current-buffer "*Flow Eldoc*"
(goto-char (point-min))
(forward-line 1)
(delete-region (point) (point-max))
(flow-minor-colorize-buffer)
(eldoc-message (car (split-string (buffer-substring (point-min) (point-max)) "\n")))))))
(defun flow-minor-eldoc-documentation-function ()
"Display type at point with eldoc."
(flow-minor-maybe-delete-process "flow-minor-eldoc")
(let* ((line (line-number-at-pos (point)))
(col (+ 1 (current-column)))
(buffer (get-buffer-create "*Flow Eldoc*"))
(errorbuffer (get-buffer-create "*Flow Eldoc Error*"))
(command (list (flow-minor-binary)
"type-at-pos"
"--path" buffer-file-name
(number-to-string line)
(number-to-string col)))
(process (make-process :name "flow-minor-eldoc"
:buffer buffer
:command command
:connection-type 'pipe
:sentinel 'flow-minor-eldoc-sentinel
:stderr errorbuffer)))
(with-current-buffer buffer
(erase-buffer))
(with-current-buffer errorbuffer
(erase-buffer))
(save-restriction
(widen)
(process-send-region process (point-min) (point-max)))
(process-send-string process "\n")
(process-send-eof process))
nil)
;;;###autoload
(define-minor-mode flow-minor-mode
"Flow mode"
nil " Flow" flow-minor-mode-map
(if flow-minor-mode
(progn
(setq-local eldoc-documentation-function 'flow-minor-eldoc-documentation-function)
(eldoc-mode))))
(defun flow-minor-tag-present-p ()
"Return true if the '// @flow' tag is present in the current buffer."
(save-excursion
(goto-char (point-min))
(let (stop found)
(while (not stop)
(when (not (re-search-forward "[^\n[:space:]]" nil t))
(setq stop t))
(if (equal (point) (point-min))
(setq stop t)
(backward-char))
(cond ((or (looking-at "//+[ ]*@flow")
(looking-at "/\\**[ ]*@flow"))
(setq found t)
(setq stop t))
((looking-at "//")
(forward-line))
((looking-at "/\\*")
(when (not (re-search-forward "*/" nil t))
(setq stop t)))
(t (setq stop t))))
found)))
(defun flow-minor-configured-p ()
"Predicate to check configuration."
(locate-dominating-file
(or (buffer-file-name) default-directory)
".flowconfig"))
;;;###autoload
(defun flow-minor-enable-automatically ()
"Search for a flow marker and enable flow-minor-mode."
(when (and (flow-minor-configured-p)
(flow-minor-tag-present-p))
(flow-minor-mode +1)))
(defun flow-status ()
"Invoke flow to check types"
(interactive)
(let ((cmd "flow status")
(regexp '(flow "^\\(Error:\\)[ \t]+\\(\\(.+\\):\\([[:digit:]]+\\)\\)"
3 4 nil (1) 2 (1 compilation-error-face))))
(add-to-list 'compilation-error-regexp-alist 'flow)
(add-to-list 'compilation-error-regexp-alist-alist regexp)
(compile cmd)))
(provide 'flow-minor-mode)
;;; flow-minor-mode.el ends here

173
site-lisp/flycheck-flow.el Normal file
View file

@ -0,0 +1,173 @@
;;; flycheck-flow.el --- Support Flow in flycheck
;; Copyright (C) 2015 Lorenzo Bolla <lbolla@gmail.com>
;;
;; Author: Lorenzo Bolla <lbolla@gmail.com>
;; Created: 16 Septermber 2015
;; Version: 1.1
;; Package-Requires: ((flycheck "0.18") (json "1.4"))
;;; Commentary:
;; This package adds support for flow to flycheck. It requires
;; flow>=0.20.0.
;; To use it, add to your init.el:
;; (require 'flycheck-flow)
;; (add-hook 'javascript-mode-hook 'flycheck-mode)
;; You want to use flow in conjunction with other JS checkers.
;; E.g. to use with gjslint, add this to your init.el
;; (flycheck-add-next-checker 'javascript-gjslint 'javascript-flow)
;; For coverage warnings add this to your init.el
;; (flycheck-add-next-checker 'javascript-flow 'javascript-flow-coverage)
;;; License:
;; This file is not part of GNU Emacs.
;; However, it is distributed under the same license.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
(require 'flycheck)
(require 'json)
(flycheck-def-args-var flycheck-javascript-flow-args javascript-flow)
(customize-set-variable 'flycheck-javascript-flow-args '())
(defun flycheck-flow--parse-json (output checker buffer)
"Parse flycheck json OUTPUT generated by CHECKER on BUFFER."
(let* ((json-object-type 'alist)
(json-array-type 'list)
(flow-json-output (json-read-from-string output))
(flow-errors-list (cdr (assq 'errors flow-json-output)))
message-kind
message-level
message-code-reason
message-filename
message-line
message-column
message-descr
errors)
(dolist (error-message flow-errors-list)
;; The structure for each `error-message' in `flow-errors-list' is like this:
;; ((kind . `message-kind')
;; (level . `message-level')
;; (message ((descr . `message-code-reason')
;; (loc (source . `message-filename')
;; (start (line . `message-line') (column . `message-column'))))
;; ((descr . `message-descr'))))
(let-alist error-message
(setq message-kind .kind)
(setq message-level (intern .level))
(let-alist (car .message)
(setq message-code-reason .descr
message-filename .loc.source
message-line .loc.start.line
message-descr .descr
message-column .loc.start.column))
(let-alist (car (cdr .message))
(when (string= .type "Comment")
(setq message-descr .descr))))
(when (string= message-kind "parse")
(setq message-descr message-kind))
(push (flycheck-error-new-at
message-line
message-column
message-level
message-descr
:id message-code-reason
:checker checker
:buffer buffer
:filename message-filename)
errors))
(nreverse errors)))
(defun flycheck-flow--predicate ()
"Shall we run the checker?"
(and
buffer-file-name
(file-exists-p buffer-file-name)
(locate-dominating-file buffer-file-name ".flowconfig")))
(flycheck-define-checker javascript-flow
"A JavaScript syntax and style checker using Flow.
See URL `http://flowtype.org/'."
:command (
"flow"
"check-contents"
(eval flycheck-javascript-flow-args)
"--json"
"--from" "emacs"
"--color=never"
source-original)
:standard-input t
:predicate flycheck-flow--predicate
:error-parser flycheck-flow--parse-json
;; js3-mode doesn't support jsx
:modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode web-mode rjsx-mode))
(flycheck-define-checker javascript-flow-coverage
"A coverage checker for Flow.
See URL `http://flowtype.org/'."
:command (
"flow"
"coverage"
(eval flycheck-javascript-flow-args)
"--json"
"--from" "emacs"
"--path" source-original)
:standard-input t
:predicate flycheck-flow--predicate
:error-parser
(lambda (output checker buffer)
(let* ((json-array-type 'list)
(json-object-type 'alist)
(locs (condition-case nil
(let ((report (json-read-from-string output)))
(alist-get 'uncovered_locs (alist-get 'expressions report)))
(error nil))))
(mapcar (lambda (loc)
(let ((start (alist-get 'start loc))
(end (alist-get 'end loc)))
(flycheck-error-new
:buffer buffer
:checker 'javascript-flow-coverage
:filename buffer-file-name
:line (alist-get 'line start)
:column (alist-get 'column start)
:message (format "no-coverage-to (%s . %s)"
(alist-get 'line end)
(alist-get 'column end))
:level 'warning)))
locs)))
;; js3-mode doesn't support jsx
:modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode))
(add-to-list 'flycheck-checkers 'javascript-flow)
(add-to-list 'flycheck-checkers 'javascript-flow-coverage t)
(provide 'flycheck-flow)
;;; flycheck-flow.el ends here

327
site-lisp/glsl-mode.el Normal file
View file

@ -0,0 +1,327 @@
;;; glsl-mode.el --- major mode for Open GLSL shader files
;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
;; Copyright (C) 2011, 2014 Jim Hourihan
;;
;; Authors: Xavier.Decoret@imag.fr,
;; Jim Hourihan <jimhourihan ~at~ gmail.com> (updated for 4.5, etc)
;; Keywords: languages
;; Version: 2.0
;; X-URL: http://artis.inrialpes.fr/~Xavier.Decoret/resources/glsl-mode/
;;
;; This software is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Commentary:
;; Major mode for editing OpenGLSL grammar files, usually files ending with
;; `.vert', `.frag', `.glsl', `.geom'. Is is based on c-mode plus some
;; features and pre-specified fontifications.
;;
;; Modifications from the 1.0 version of glsl-mode (jimhourihan):
;; * Removed original optimized regexps for font-lock-keywords and
;; replaced with keyword lists for easier maintenance
;; * Added customization group and faces
;; * Preprocessor faces
;; * Updated to GLSL 4.5
;; * Separate deprecated symbols
;; * Made _ part of a word
;; * man page lookup at opengl.org
;; This package provides the following features:
;; * Syntax coloring (via font-lock) for grammar symbols and
;; builtin functions and variables for up to GLSL version 4.5
;; * Indentation for the current line (TAB) and selected region (C-M-\).
;; * Switching between file.vert and file.frag
;; with S-lefttab (via ff-find-other-file)
;; * interactive function glsl-find-man-page prompts for glsl built
;; in function, formats opengl.org url and passes to w3m
;;; Installation:
;; This file requires Emacs-20.3 or higher and package cc-mode.
;; If glsl-mode is not part of your distribution, put this file into your
;; load-path and the following into your ~/.emacs:
;; (autoload 'glsl-mode "glsl-mode" nil t)
;; (add-to-list 'auto-mode-alist '("\\.glsl\\'" . glsl-mode))
;; (add-to-list 'auto-mode-alist '("\\.vert\\'" . glsl-mode))
;; (add-to-list 'auto-mode-alist '("\\.frag\\'" . glsl-mode))
;; (add-to-list 'auto-mode-alist '("\\.geom\\'" . glsl-mode))
;;; Code:
(provide 'glsl-mode)
(eval-when-compile ; required and optional libraries
(require 'cc-mode)
(require 'find-file))
(require 'align)
(defgroup glsl nil
"OpenGL Shading Language Major Mode"
:group 'languages)
(defconst glsl-language-version "4.5"
"GLSL language version number.")
(defconst gl-version "4.5"
"OpenGL major mode version number.")
(defvar glsl-type-face 'glsl-type-face)
(defface glsl-type-face
'((t (:inherit font-lock-type-face))) "glsl: type face"
:group 'glsl)
(defvar glsl-builtin-face 'glsl-builtin-face)
(defface glsl-builtin-face
'((t (:inherit font-lock-builtin-face))) "glsl: builtin face"
:group 'glsl)
(defvar glsl-deprecated-builtin-face 'glsl-deprecated-builtin-face)
(defface glsl-deprecated-builtin-face
'((t (:inherit glsl-builtin-face))) "glsl: deprecated builtin face"
:group 'glsl)
(defvar glsl-keyword-face 'glsl-keyword-face)
(defface glsl-keyword-face
'((t (:inherit font-lock-keyword-face))) "glsl: keyword face"
:group 'glsl)
(defvar glsl-deprecated-keyword-face 'glsl-deprecated-keyword-face)
(defface glsl-deprecated-keyword-face
'((t (:inherit glsl-keyword-face))) "glsl: deprecated keyword face"
:group 'glsl)
(defvar glsl-variable-name-face 'glsl-variable-name-face)
(defface glsl-variable-name-face
'((t (:inherit font-lock-variable-name-face))) "glsl: variable face"
:group 'glsl)
(defvar glsl-deprecated-variable-name-face 'glsl-deprecated-variable-name-face)
(defface glsl-deprecated-variable-name-face
'((t (:inherit glsl-variable-name-face))) "glsl: deprecated variable face"
:group 'glsl)
(defvar glsl-preprocessor-face 'glsl-preprocessor-face)
(defface glsl-preprocessor-face
'((t (:inherit font-lock-preprocessor-face))) "glsl: preprocessor face"
:group 'glsl)
(defvar glsl-mode-hook nil)
(defvar glsl-mode-map
(let ((glsl-mode-map (make-sparse-keymap)))
(define-key glsl-mode-map [S-iso-lefttab] 'ff-find-other-file)
glsl-mode-map)
"Keymap for GLSL major mode")
(defcustom glsl-man-pages-base-url "http://www.opengl.org/sdk/docs/man/html/"
"Location of GL man pages"
:group 'glsl)
;;;###autoload
(progn
(add-to-list 'auto-mode-alist '("\\.vert\\'" . glsl-mode))
(add-to-list 'auto-mode-alist '("\\.frag\\'" . glsl-mode))
(add-to-list 'auto-mode-alist '("\\.geom\\'" . glsl-mode))
(add-to-list 'auto-mode-alist '("\\.glsl\\'" . glsl-mode)))
(eval-and-compile
;;
;; These vars are useful for completion so keep them around after
;; compile as well. The goal here is to have the byte compiled code
;; have optimized regexps so its not done at eval time.
;;
(defvar glsl-type-list
'("float" "double" "int" "void" "bool" "true" "false" "mat2" "mat3"
"mat4" "dmat2" "dmat3" "dmat4" "mat2x2" "mat2x3" "mat2x4" "dmat2x2"
"dmat2x3" "dmat2x4" "mat3x2" "mat3x3" "mat3x4" "dmat3x2" "dmat3x3"
"dmat3x4" "mat4x2" "mat4x3" "mat4x4" "dmat4x2" "dmat4x3" "dmat4x4" "vec2"
"vec3" "vec4" "ivec2" "ivec3" "ivec4" "bvec2" "bvec3" "bvec4" "dvec2"
"dvec3" "dvec4" "uint" "uvec2" "uvec3" "uvec4" "sampler1D" "sampler2D"
"sampler3D" "samplerCube" "sampler1DShadow" "sampler2DShadow"
"samplerCubeShadow" "sampler1DArray" "sampler2DArray"
"sampler1DArrayShadow" "sampler2DArrayShadow" "isampler1D" "isampler2D"
"isampler3D" "isamplerCube" "isampler1DArray" "isampler2DArray"
"usampler1D" "usampler2D" "usampler3D" "usamplerCube" "usampler1DArray"
"usampler2DArray" "sampler2DRect" "sampler2DRectShadow" "isampler2DRect"
"usampler2DRect" "samplerBuffer" "isamplerBuffer" "usamplerBuffer"
"sampler2DMS" "isampler2DMS" "usampler2DMS" "sampler2DMSArray"
"isampler2DMSArray" "usampler2DMSArray" "samplerCubeArray"
"samplerCubeArrayShadow" "isamplerCubeArray" "usamplerCubeArray"
"image1D" "iimage1D" "uimage1D" "image2D" "iimage2D" "uimage2D" "image3D"
"iimage3D" "uimage3D" "image2DRect" "iimage2DRect" "uimage2DRect"
"imageCube" "iimageCube" "uimageCube" "imageBuffer" "iimageBuffer"
"uimageBuffer" "image1DArray" "iimage1DArray" "uimage1DArray"
"image2DArray" "iimage2DArray" "uimage2DArray" "imageCubeArray"
"iimageCubeArray" "uimageCubeArray" "image2DMS" "iimage2DMS" "uimage2DMS"
"image2DMSArray" "iimage2DMSArray" "uimage2DMSArray" "long" "short"
"half" "fixed" "unsigned" "hvec2" "hvec3" "hvec4" "fvec2" "fvec3" "fvec4"
"sampler3DRect"))
(defvar glsl-modifier-list
'("attribute" "const" "uniform" "varying" "buffer" "shared" "coherent" "volatile" "restrict"
"readonly" "writeonly" "atomic_uint" "layout" "centroid" "flat" "smooth"
"noperspective" "patch" "sample" "break" "continue" "do" "for" "while"
"switch" "case" "default" "if" "else" "subroutine" "in" "out" "inout"
"invariant" "discard" "return" "lowp" "mediump" "highp" "precision"
"struct" "common" "partition" "active" "asm" "class" "union" "enum"
"typedef" "template" "this" "packed" "resource" "goto" "inline" "noinline"
"public" "static" "extern" "external" "interface" "superp" "input" "output"
"filter" "sizeof" "cast" "namespace" "using" "row_major"
"early_fragment_tests"))
(defvar glsl-deprecated-modifier-list
'("varying" "attribute")) ; centroid is deprecated when used with varying
(defvar glsl-builtin-list
'("abs" "acos" "acosh" "all" "any" "asin" "asinh" "atan" "atanh"
"atomicCounter" "atomicCounterDecrement" "atomicCounterIncrement"
"barrier" "bitCount" "bitfieldExtract" "bitfieldInsert" "bitfieldReverse"
"ceil" "clamp" "cos" "cosh" "cross" "degrees" "determinant" "dFdx" "dFdy"
"dFdyFine" "dFdxFine" "dFdyCoarse" "dFdxCourse"
"fwidthFine" "fwidthCoarse"
"distance" "dot" "EmitStreamVertex" "EmitVertex" "EndPrimitive"
"EndStreamPrimitive" "equal" "exp" "exp2" "faceforward" "findLSB"
"findMSB" "floatBitsToInt" "floatBitsToUint" "floor" "fma" "fract"
"frexp" "fwidth" "greaterThan" "greaterThanEqual" "imageAtomicAdd"
"imageAtomicAnd" "imageAtomicCompSwap" "imageAtomicExchange"
"imageAtomicMax" "imageAtomicMin" "imageAtomicOr" "imageAtomicXor"
"imageLoad" "imageSize" "imageStore" "imulExtended" "intBitsToFloat"
"imageSamples"
"interpolateAtCentroid" "interpolateAtOffset" "interpolateAtSample"
"inverse" "inversesqrt" "isinf" "isnan" "ldexp" "length" "lessThan"
"lessThanEqual" "log" "log2" "matrixCompMult" "max" "memoryBarrier" "min"
"mix" "mod" "modf" "noise" "normalize" "not" "notEqual" "outerProduct"
"packDouble2x32" "packHalf2x16" "packSnorm2x16" "packSnorm4x8"
"packUnorm2x16" "packUnorm4x8" "pow" "radians" "reflect" "refract"
"round" "roundEven" "sign" "sin" "sinh" "smoothstep" "sqrt" "step" "tan"
"tanh" "texelFetch" "texelFetchOffset" "texture" "textureGather"
"textureGatherOffset" "textureGatherOffsets" "textureGrad"
"textureGradOffset" "textureLod" "textureLodOffset" "textureOffset"
"textureProj" "textureProjGrad" "textureProjGradOffset" "textureProjLod"
"textureProjLodOffset" "textureProjOffset" "textureQueryLevels" "textureQueryLod"
"textureSize" "transpose" "trunc" "uaddCarry" "uintBitsToFloat"
"umulExtended" "unpackDouble2x32" "unpackHalf2x16" "unpackSnorm2x16"
"unpackSnorm4x8" "unpackUnorm2x16" "unpackUnorm4x8" "usubBorrow"))
(defvar glsl-deprecated-builtin-list
'("texture1D" "texture1DProj" "texture1DLod" "texture1DProjLod"
"texture2D" "texture2DProj" "texture2DLod" "texture2DProjLod"
"texture2DRect" "texture2DRectProj"
"texture3D" "texture3DProj" "texture3DLod" "texture3DProjLod"
"shadow1D" "shadow1DProj" "shadow1DLod" "shadow1DProjLod"
"shadow2D" "shadow2DProj" "shadow2DLod" "shadow2DProjLod"
"textureCube" "textureCubeLod"))
(defvar glsl-deprecated-variables-list
'("gl_FragColor" "gl_FragData" "gl_MaxVarying" "gl_MaxVaryingFloats"
"gl_MaxVaryingComponents"))
(defvar glsl-preprocessor-directive-list
'("define" "undef" "if" "ifdef" "ifndef" "else" "elif" "endif"
"error" "pragma" "extension" "version" "line"))
(defvar glsl-preprocessor-expr-list
'("defined" "##"))
(defvar glsl-preprocessor-builtin-list
'("__LINE__" "__FILE__" "__VERSION__"))
(autoload 'w3m-browse-url "w3m" "View URL using w3m")
) ; eval-and-compile
(eval-when-compile
(defun glsl-ppre (re)
(format "\\<\\(%s\\)\\>" (regexp-opt re))))
(defvar glsl-font-lock-keywords-1
(list
(cons (eval-when-compile
(format "^[ \t]*#[ \t]*\\<\\(%s\\)\\>"
(regexp-opt glsl-preprocessor-directive-list)))
glsl-preprocessor-face)
(cons (eval-when-compile
(glsl-ppre glsl-type-list))
glsl-type-face)
(cons (eval-when-compile
(glsl-ppre glsl-deprecated-modifier-list))
glsl-deprecated-keyword-face)
(cons (eval-when-compile
(glsl-ppre glsl-modifier-list))
glsl-keyword-face)
(cons (eval-when-compile
(glsl-ppre glsl-preprocessor-builtin-list))
glsl-keyword-face)
(cons (eval-when-compile
(glsl-ppre glsl-deprecated-builtin-list))
glsl-deprecated-builtin-face)
(cons (eval-when-compile
(glsl-ppre glsl-builtin-list))
glsl-builtin-face)
(cons (eval-when-compile
(glsl-ppre glsl-deprecated-variables-list))
glsl-deprecated-variable-name-face)
(cons "gl_[A-Z][A-Za-z_]+" glsl-variable-name-face)
)
"Minimal highlighting expressions for GLSL mode")
(defvar glsl-font-lock-keywords glsl-font-lock-keywords-1
"Default highlighting expressions for GLSL mode")
(defvar glsl-mode-syntax-table
(let ((glsl-mode-syntax-table (make-syntax-table)))
(modify-syntax-entry ?/ ". 124b" glsl-mode-syntax-table)
(modify-syntax-entry ?* ". 23" glsl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" glsl-mode-syntax-table)
(modify-syntax-entry ?_ "w" glsl-mode-syntax-table)
glsl-mode-syntax-table)
"Syntax table for glsl-mode")
(defvar glsl-other-file-alist
'(("\\.frag$" (".vert"))
("\\.vert$" (".frag"))
)
"Alist of extensions to find given the current file's extension")
(defun glsl-man-completion-list ()
(append glsl-builtin-list glsl-deprecated-builtin-list))
(defun glsl-find-man-page (thing)
(interactive
(let ((word (current-word nil t)))
(list
(completing-read
(concat "OpenGL.org GLSL man page: (" word "): ")
(glsl-man-completion-list)
nil nil nil nil word))))
(save-excursion
(browse-url
(concat glsl-man-pages-base-url thing ".xhtml"))))
;;;###autoload
(define-derived-mode glsl-mode c-mode "GLSL"
"Major mode for editing OpenGLSL shader files."
(set (make-local-variable 'font-lock-defaults) '(glsl-font-lock-keywords))
(set (make-local-variable 'ff-other-file-alist) 'glsl-other-file-alist)
(set (make-local-variable 'comment-start) "// ")
(set (make-local-variable 'comment-end) "")
(set (make-local-variable 'comment-padding) "")
(add-to-list 'align-c++-modes 'glsl-mode)
)
;(easy-menu-define c-glsl-menu glsl-mode-map "GLSL Mode Commands"
; (cons "GLSL" (c-lang-const c-mode-menu glsl)))
;;; glsl-mode.el ends here

213
site-lisp/prettier-js.el Normal file
View file

@ -0,0 +1,213 @@
;;; prettier-js.el --- Minor mode to format JS code on file save
;; Version: 0.1.0
;; Copyright (c) 2014 The go-mode Authors. All rights reserved.
;; Portions Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are
;; met:
;; * Redistributions of source code must retain the above copyright
;; notice, this list of conditions and the following disclaimer.
;; * Redistributions in binary form must reproduce the above
;; copyright notice, this list of conditions and the following disclaimer
;; in the documentation and/or other materials provided with the
;; distribution.
;; * Neither the name of the copyright holder nor the names of its
;; contributors may be used to endorse or promote products derived from
;; this software without specific prior written permission.
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.)
;; Author: James Long and contributors
;; Created: 10 January 2017
;; Url: https://github.com/prettier/prettier-emacs
;; Keywords: convenience wp edit js
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Formats your JavaScript code using 'prettier' on file save.
;;; Code:
(defgroup prettier-js nil
"Minor mode to format JS code on file save"
:group 'languages
:prefix "prettier-js"
:link '(url-link :tag "Repository" "https://github.com/prettier/prettier"))
(defcustom prettier-js-command "prettier"
"The 'prettier' command."
:type 'string
:group 'prettier-js)
(defcustom prettier-js-args '()
"List of args to send to prettier command."
:type '(repeat string)
:group 'prettier-js)
(defcustom prettier-js-show-errors 'buffer
"Where to display prettier error output.
It can either be displayed in its own buffer, in the echo area, or not at all.
Please note that Emacs outputs to the echo area when writing
files and will overwrite prettier's echo output if used from inside
a `before-save-hook'."
:type '(choice
(const :tag "Own buffer" buffer)
(const :tag "Echo area" echo)
(const :tag "None" nil))
:group 'prettier-js)
(defcustom prettier-js-width-mode nil
"Specify width when formatting buffer contents."
:type '(choice
(const :tag "Window width" window)
(const :tag "Fill column" fill)
(const :tag "None" nil))
:group 'prettier-js)
(defun prettier-js--goto-line (line)
"Move cursor to line LINE."
(goto-char (point-min))
(forward-line (1- line)))
(defun prettier-js--apply-rcs-patch (patch-buffer)
"Apply an RCS-formatted diff from PATCH-BUFFER to the current buffer."
(let ((target-buffer (current-buffer))
;; Relative offset between buffer line numbers and line numbers
;; in patch.
;;
;; Line numbers in the patch are based on the source file, so
;; we have to keep an offset when making changes to the
;; buffer.
;;
;; Appending lines decrements the offset (possibly making it
;; negative), deleting lines increments it. This order
;; simplifies the forward-line invocations.
(line-offset 0))
(save-excursion
(with-current-buffer patch-buffer
(goto-char (point-min))
(while (not (eobp))
(unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)")
(error "Invalid rcs patch or internal error in prettier-js--apply-rcs-patch"))
(forward-line)
(let ((action (match-string 1))
(from (string-to-number (match-string 2)))
(len (string-to-number (match-string 3))))
(cond
((equal action "a")
(let ((start (point)))
(forward-line len)
(let ((text (buffer-substring start (point))))
(with-current-buffer target-buffer
(setq line-offset (- line-offset len))
(goto-char (point-min))
(forward-line (- from len line-offset))
(insert text)))))
((equal action "d")
(with-current-buffer target-buffer
(prettier-js--goto-line (- from line-offset))
(setq line-offset (+ line-offset len))
(let ((beg (point)))
(forward-line len)
(delete-region (point) beg))))
(t
(error "Invalid rcs patch or internal error in prettier-js--apply-rcs-patch")))))))))
(defun prettier-js--process-errors (filename errorfile errbuf)
"Process errors for FILENAME, using an ERRORFILE and display the output in ERRBUF."
(with-current-buffer errbuf
(if (eq prettier-js-show-errors 'echo)
(progn
(message "%s" (buffer-string))
(prettier-js--kill-error-buffer errbuf))
(insert-file-contents errorfile nil nil nil)
;; Convert the prettier stderr to something understood by the compilation mode.
(goto-char (point-min))
(insert "prettier errors:\n")
(while (search-forward-regexp "^stdin" nil t)
(replace-match (file-name-nondirectory filename)))
(compilation-mode)
(display-buffer errbuf))))
(defun prettier-js--kill-error-buffer (errbuf)
"Kill buffer ERRBUF."
(let ((win (get-buffer-window errbuf)))
(if win
(quit-window t win)
(with-current-buffer errbuf
(erase-buffer))
(kill-buffer errbuf))))
(defun prettier-js ()
"Format the current buffer according to the prettier tool."
(interactive)
(let* ((ext (file-name-extension buffer-file-name t))
(bufferfile (make-temp-file "prettier" nil ext))
(outputfile (make-temp-file "prettier" nil ext))
(errorfile (make-temp-file "prettier" nil ext))
(errbuf (if prettier-js-show-errors (get-buffer-create "*prettier errors*")))
(patchbuf (get-buffer-create "*prettier patch*"))
(coding-system-for-read 'utf-8)
(coding-system-for-write 'utf-8)
(width-args
(cond
((equal prettier-js-width-mode 'window)
(list "--print-width" (number-to-string (window-body-width))))
((equal prettier-js-width-mode 'fill)
(list "--print-width" (number-to-string fill-column)))
(t
'()))))
(unwind-protect
(save-restriction
(widen)
(write-region nil nil bufferfile)
(if errbuf
(with-current-buffer errbuf
(setq buffer-read-only nil)
(erase-buffer)))
(with-current-buffer patchbuf
(erase-buffer))
(if (zerop (apply 'call-process
prettier-js-command bufferfile (list (list :file outputfile) errorfile)
nil (append prettier-js-args width-args (list "--stdin" "--stdin-filepath" buffer-file-name))))
(progn
(call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "--strip-trailing-cr" "-"
outputfile)
(prettier-js--apply-rcs-patch patchbuf)
(message "Applied prettier with args `%s'" prettier-js-args)
(if errbuf (prettier-js--kill-error-buffer errbuf)))
(message "Could not apply prettier")
(if errbuf
(prettier-js--process-errors (buffer-file-name) errorfile errbuf))
))
(kill-buffer patchbuf)
(delete-file errorfile)
(delete-file bufferfile)
(delete-file outputfile))))
;;;###autoload
(define-minor-mode prettier-js-mode
"Runs prettier on file save when this mode is turned on"
:lighter " Prettier"
:global nil
(if prettier-js-mode
(add-hook 'before-save-hook 'prettier-js nil 'local)
(remove-hook 'before-save-hook 'prettier-js 'local)))
(provide 'prettier-js)
;;; prettier-js.el ends here