diff --git a/cmake/FindQuickLintJSEmacs.cmake b/cmake/FindQuickLintJSEmacs.cmake new file mode 100644 index 0000000000..181c47e8fa --- /dev/null +++ b/cmake/FindQuickLintJSEmacs.cmake @@ -0,0 +1,49 @@ +# Copyright (C) 2020 Matthew "strager" Glazar +# See end of file for extended copyright information. + +find_program(QUICK_LINT_JS_EMACS "emacs") + +if (NOT QUICK_LINT_JS_EMACS) + return () +endif () + +execute_process( + COMMAND + ${QUICK_LINT_JS_EMACS} + -Q -batch + --eval "(princ (format \"%s.%s\" emacs-major-version emacs-minor-version))" + RESULT_VARIABLE EMACS_EXIT_CODE + OUTPUT_VARIABLE EMACS_VERSION) + +if (NOT EMACS_EXIT_CODE EQUAL 0) + message(WARNING "Emacs (${QUICK_LINT_JS_EMACS}) found but can't get its version. Skipping...") + return () +endif() + +if (NOT EMACS_VERSION GREATER_EQUAL 24.5) + message(WARNING "Emacs found (${QUICK_LINT_JS_EMACS}), but version ${EMACS_VERSION} is not supported. Skipping...") + return () +endif () + +set(QUICK_LINT_JS_EMACS_FOUND TRUE) +message(STATUS "Found Emacs ${QUICK_LINT_JS_EMACS} (found suitable version \"${EMACS_VERSION}\" minimum required is \"24.5\")") + +mark_as_advanced(QUICK_LINT_JS_EMACS) + +# quick-lint-js finds bugs in JavaScript programs. +# Copyright (C) 2020 Matthew "strager" Glazar +# +# This file is part of quick-lint-js. +# +# quick-lint-js 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 of the License, or +# (at your option) any later version. +# +# quick-lint-js 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 quick-lint-js. If not, see . diff --git a/plugin/emacs/CMakeLists.txt b/plugin/emacs/CMakeLists.txt index 6ff75d213a..3955c6ef2d 100644 --- a/plugin/emacs/CMakeLists.txt +++ b/plugin/emacs/CMakeLists.txt @@ -4,13 +4,82 @@ cmake_minimum_required(VERSION 3.10) include(GNUInstallDirs) -install( - FILES flycheck-quicklintjs.el - FILES lsp-quicklintjs.el - FILES eglot-quicklintjs.el - FILES flymake-quicklintjs.el - DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/emacs/site-lisp" -) +find_package(QuickLintJSEmacs) + +macro(emacs_pkg_target NAME FILE) + cmake_parse_arguments( + "" + "" + "OUTPUT" + "" + ${ARGN}) + + add_custom_command( + OUTPUT ${_OUTPUT} + COMMAND + ${QUICK_LINT_JS_EMACS} + -Q -batch + -l package --eval "(package-initialize)" + --eval "(add-to-list 'package-directory-list \"${CMAKE_CURRENT_BINARY_DIR}\")" + -l ${CMAKE_CURRENT_LIST_DIR}/quicklintjs-make-package.el + -f quicklintjs-batch-make-pkg + ${FILE} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS + ${QUICK_LINT_JS_EMACS} + ${CMAKE_CURRENT_LIST_DIR}/quicklintjs-make-package.el + ${FILE} + VERBATIM) + + add_custom_target(${NAME} ALL DEPENDS ${_OUTPUT}) +endmacro () + +if (QUICK_LINT_JS_EMACS_FOUND) + emacs_pkg_target(emacs-plugin-quicklintjs + ${CMAKE_CURRENT_LIST_DIR}/quicklintjs.el 0.0.1 + OUTPUT quicklintjs-0.0.1) + + emacs_pkg_target(emacs-plugin-flycheck-quicklintjs + ${CMAKE_CURRENT_LIST_DIR}/flycheck-quicklintjs.el 0.0.1 + OUTPUT flycheck-quicklintjs-0.0.1) + + emacs_pkg_target(emacs-plugin-flymake-quicklintjs + ${CMAKE_CURRENT_LIST_DIR}/flymake-quicklintjs.el 0.0.1 + OUTPUT flymake-quicklintjs-0.0.1) + + emacs_pkg_target(emacs-plugin-eglot-quicklintjs + ${CMAKE_CURRENT_LIST_DIR}/eglot-quicklintjs.el 0.0.1 + OUTPUT eglot-quicklintjs-0.0.1) + + emacs_pkg_target(emacs-plugin-lsp-quicklintjs + ${CMAKE_CURRENT_LIST_DIR}/lsp-quicklintjs.el 0.0.1 + OUTPUT lsp-quicklintjs-0.0.1) + + add_dependencies(emacs-plugin-flycheck-quicklintjs + emacs-plugin-quicklintjs) + add_dependencies(emacs-plugin-flymake-quicklintjs + emacs-plugin-quicklintjs) + add_dependencies(emacs-plugin-eglot-quicklintjs + emacs-plugin-quicklintjs) + add_dependencies(emacs-plugin-lsp-quicklintjs + emacs-plugin-quicklintjs) + + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/quicklintjs-0.0.1 + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/emacs/site-lisp/elpa) + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/flycheck-quicklintjs-0.0.1 + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/emacs/site-lisp/elpa) + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/flymake-quicklintjs-0.0.1 + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/emacs/site-lisp/elpa) + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/eglot-quicklintjs-0.0.1 + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/emacs/site-lisp/elpa) + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lsp-quicklintjs-0.0.1 + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/emacs/site-lisp/elpa) +endif () # quick-lint-js finds bugs in JavaScript programs. # Copyright (C) 2020 Matthew "strager" Glazar diff --git a/plugin/emacs/eglot-quicklintjs.el b/plugin/emacs/eglot-quicklintjs.el index fbc7249a16..25dec1d245 100644 --- a/plugin/emacs/eglot-quicklintjs.el +++ b/plugin/emacs/eglot-quicklintjs.el @@ -1,5 +1,28 @@ ;;; eglot-quicklintjs.el --- Eglot support for quick-lint-js -*- lexical-binding: t; -*- +;; Copyright (C) 2020 Matthew "strager" Glazar + +;; Version: 0.0.1 +;; Author: Wagner Riffel +;; URL: https://quick-lint-js.com +;; Keywords: languages, tools +;; Package-Requires: ((quicklintjs "0.0.1") (eglot "1.7") (emacs "26.1")) + +;; This file is part of quick-lint-js. +;; +;; quick-lint-js 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 of the License, or +;; (at your option) any later version. +;; +;; quick-lint-js 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 quick-lint-js. If not, see . + ;;; Commentary: ;; Eglot support for quick-lint-js. @@ -19,44 +42,13 @@ ;;; Code: (require 'eglot) +(require 'quicklintjs) -(defgroup eglot-quicklintjs nil - "quick-lint-js Eglot integration." - :group 'eglot-quicklintjs - :link '(url-link :tag "Website" "https://quick-lint-js.com")) - -(defcustom eglot-quicklintjs-program "quick-lint-js" - "Path to quick-lint-js program to run." - :group 'eglot-quicklintjs - :type 'stringp) - -(defcustom eglot-quicklintjs-args nil - "Arguments to quick-lint-js." - :group 'eglot-quicklintjs - :type '(repeat string)) - -(add-to-list 'eglot-server-programs `(js-mode . (,eglot-quicklintjs-program - "--lsp-server" - ,@eglot-quicklintjs-args))) +;;;###autoload +(with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs `(js-mode . ,(quicklintjs-find-program + "--lsp-server")))) (provide 'eglot-quicklintjs) -;; quick-lint-js finds bugs in JavaScript programs. -;; Copyright (C) 2020 Matthew Glazar -;; -;; This file is part of quick-lint-js. -;; -;; quick-lint-js 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 of the License, or -;; (at your option) any later version. -;; -;; quick-lint-js 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 quick-lint-js. If not, see . - ;;; eglot-quicklintjs.el ends here diff --git a/plugin/emacs/flycheck-quicklintjs.el b/plugin/emacs/flycheck-quicklintjs.el index 37b2081b63..fa33ebe669 100644 --- a/plugin/emacs/flycheck-quicklintjs.el +++ b/plugin/emacs/flycheck-quicklintjs.el @@ -1,4 +1,27 @@ -;;; flycheck-quicklintjs --- quick-lint-js Flycheck support -*- lexical-binding: t; -*- +;;; flycheck-quicklintjs.el --- quick-lint-js Flycheck support -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Matthew "strager" Glazar + +;; Version: 0.0.1 +;; Author: Wagner Riffel +;; URL: https://quick-lint-js.com +;; Keywords: languages, tools +;; Package-Requires: ((quicklintjs "0.0.1") (flycheck "32-cvs") (emacs "24.5")) + +;; This file is part of quick-lint-js. +;; +;; quick-lint-js 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 of the License, or +;; (at your option) any later version. +;; +;; quick-lint-js 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 quick-lint-js. If not, see . ;;; Commentary: @@ -35,19 +58,10 @@ ;;; Code: (require 'flycheck) - -(defgroup flycheck-quicklintjs nil - "quick-lint-js Flycheck integration." - :prefix "flycheck-" - :group 'flycheck - :group 'quicklintjs - :link '(url-link :tag "Website" "https://quick-lint-js.com")) - -(flycheck-def-args-var flycheck-quicklintjs-args javascript-quicklintjs) -(flycheck-def-executable-var javascript-quicklintjs "quick-lint-js") +(require 'quicklintjs) (defun flycheck-quicklintjs-parse-errors (output checker buffer) - "Parse quick-lint-js alist output format from OUTPUT" + "Parse CHECKER quick-lint-js alist output format from OUTPUT." (mapcar (lambda (l) (let ((region (nth 0 l)) (sev (nth 1 l)) @@ -60,48 +74,31 @@ :id code :buffer buffer :checker checker - :end-pos (cdr region)))) (car (read-from-string output)))) + :end-pos (cdr region)))) + (car (read-from-string output)))) -(flycheck-define-checker javascript-quicklintjs +;;;###autoload +(flycheck-define-command-checker 'javascript-quicklintjs "quick-lint-js finds bugs in JavaScript programs. https://quick-lint-js.com" - :command ("quick-lint-js" - "--output-format=emacs-lisp" - (eval (let ((file (buffer-file-name))) - (if file - `("--path-for-config-search" ,file) - ()))) - "--stdin" - (eval flycheck-quicklintjs-args)) - :standard-input t - :error-parser flycheck-quicklintjs-parse-errors + :command (quicklintjs-find-program + "--output-format=emacs-lisp" + (let ((file (buffer-file-name))) + (when file (concat "--path-for-config-search=" file))) + "--stdin") + :standard-input 't + :error-parser 'flycheck-quicklintjs-parse-errors :error-explainer (lambda (err) (let ((error-code (flycheck-error-id err)) (url "https://quick-lint-js.com/errors/#%s")) (and error-code `(url . ,(format url error-code))))) - :modes js-mode) + :modes 'js-mode) -(add-to-list 'flycheck-checkers 'javascript-quicklintjs t) +;;;###autoload +(with-eval-after-load 'flycheck + (add-to-list 'flycheck-checkers 'javascript-quicklintjs t)) (provide 'flycheck-quicklintjs) -;; quick-lint-js finds bugs in JavaScript programs. -;; Copyright (C) 2020 Matthew "strager" Glazar -;; -;; This file is part of quick-lint-js. -;; -;; quick-lint-js 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 of the License, or -;; (at your option) any later version. -;; -;; quick-lint-js 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 quick-lint-js. If not, see . - ;;; flycheck-quicklintjs.el ends here diff --git a/plugin/emacs/flymake-quicklintjs.el b/plugin/emacs/flymake-quicklintjs.el index 24cc227380..219cf0d11b 100644 --- a/plugin/emacs/flymake-quicklintjs.el +++ b/plugin/emacs/flymake-quicklintjs.el @@ -1,5 +1,28 @@ ;;; flymake-quicklintjs.el --- Flymake support for quick-lint-js -*- lexical-binding: t; -*- +;; Copyright (C) 2020 Matthew "strager" Glazar + +;; Version: 0.0.1 +;; Author: Wagner Riffel +;; URL: https://quick-lint-js.com +;; Keywords: languages, tools +;; Package-Requires: ((quicklintjs "0.0.1") (flymake "1.0.9") (emacs "26.1")) + +;; This file is part of quick-lint-js. +;; +;; quick-lint-js 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 of the License, or +;; (at your option) any later version. +;; +;; quick-lint-js 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 quick-lint-js. If not, see . + ;;; Commentary: ;; Flymake support for quick-lint-js. @@ -14,7 +37,6 @@ ;; ;; Enable Flymake ;; (unless (bound-and-true-p flymake-mode) ;; (flymake-mode)) -;; (add-hook 'flymake-diagnostic-functions #'flymake-quicklintjs nil t) ;; ;; ;; Remove the time to wait after last change before automatically checking ;; ;; buffer. The default is 0.5 (500ms) @@ -24,20 +46,7 @@ ;;; Code: (require 'flymake) - -(defgroup flymake-quicklintjs nil - "Flymake backend for quick-lint-js" - :link '(url-link :tag "Website" "https://quick-lint-js.com")) - -(defcustom flymake-quicklintjs-program "quick-lint-js" - "Path to quick-lint-js program to run." - :group 'flymake-quicklintjs - :type 'stringp) - -(defcustom flymake-quicklintjs-args nil - "Arguments to quick-lint-js." - :group 'flymake-quicklintjs - :type '(repeat 'string)) +(require 'quicklintjs) (defvar-local flymake-quicklintjs--proc nil "Internal variable for `flymake-quicklintjs'") @@ -53,70 +62,95 @@ Return a list of Flymake diagnostic objects in source buffer SRC-BUF." (if (= sev 0) :error :warning) msg))) quicklintjs-output-alist)) +(defun flymake-quicklintjs--report-with-crash (qljs-stdout-buf + qljs-stderr-buf + src-buf report-fn) + "Similar to `flymake-quicklintjs--report' but try to recover errors in\ +SRC-BUF when quick-lint-js crashes by inspecting QLJS-STDOUT-BUF. +Whatever is in QLJS-STDERR-BUF is also logged as warning using `flymake-log'." + (flymake-log :warning + "quick-lint-js exited with a deadly signal.\n\ +Please consider filing a bug at\ + https://github.com/quick-lint/quick-lint-js/issues/new\n\ +qjls-stderr-buf:\n\ +%s\n" + (with-current-buffer qljs-stderr-buf + (buffer-substring-no-properties (point-min) (point-max)))) + (with-current-buffer qljs-stdout-buf + (save-excursion + ;; a crash without any previous issue, try to fix an empty buffer + (when (zerop (buffer-size)) + (goto-char (point-min)) + (insert-char ?\()) + ;; the above left a '(' dangling or quick-lint-js crashed and + ;; emacs_lisp_error_reporter::finish() haven't been called yet + (goto-char (point-min)) + (when (eq (char-after 1) ?\() + (goto-char (point-max)) + (insert-char ?\))))) + (condition-case nil + (flymake-quicklintjs--report qljs-stdout-buf src-buf report-fn) + (funcall report-fn '()))) + +(defun flymake-quicklintjs--report (qljs-stdout-buf src-buf report-fn) + "Call REPORT-FN to highlight reports in SRC-BUF reported in QLJS-STDOUT-BUF. +QLJS-STDOUT-BUF is entirely read and it's expected to be in +QUICKLINTJS-OUTPUT-ALIST format." + (with-current-buffer qljs-stdout-buf + (funcall report-fn + (flymake-quicklintjs--make-diagnostics + src-buf + (car (read-from-string + (buffer-substring-no-properties (point-min) + (point-max)))))))) + ;;;###autoload (defun flymake-quicklintjs (report-fn &rest _args) "Flymake backend for quick-lint-js linter. -This backend uses `flymake-quicklintjs-program' (which see) to launch a -quick-lint-js process that is passed the current buffer's contents via stdin. +This backend uses `quicklintjs-find-program' to find and launch a quick-lint-js +process that is passed the current buffer's contents via stdin. REPORT-FN is Flymake's callback." (when (process-live-p flymake-quicklintjs--proc) (kill-process flymake-quicklintjs--proc)) - (let ((src-buf (current-buffer))) - (setq flymake-quicklintjs--proc - (make-process - :name "flymake-quicklintjs" - :connection-type 'pipe - :noquery t - :buffer (get-buffer-create " *flymake-quicklintjs*") - :command `(,flymake-quicklintjs-program - ,@(let ((file (buffer-file-name))) - (if file - `("--path-for-config-search" ,file) - ())) - "--stdin" "--output-format=emacs-lisp" - ,@flymake-quicklintjs-args) - :sentinel - (lambda (p _ev) - (unwind-protect - (when (and (eq 'exit (process-status p)) - (eq p flymake-quicklintjs--proc)) - (with-current-buffer (process-buffer p) - (let ((diags (flymake-quicklintjs--make-diagnostics - src-buf - (car (read-from-string - (buffer-substring-no-properties - (point-min) (point-max))))))) - (if (or diags (zerop (process-exit-status p))) - (funcall report-fn diags - :region (cons (point-min) (point-max))) - (funcall report-fn - :panic :explanation - (buffer-substring - (point-min) (progn (goto-char (point-min)) - (line-end-position)))))))) - (unless (process-live-p p) - (kill-buffer (process-buffer p))))))) - (process-send-region flymake-quicklintjs--proc (point-min) (point-max)) - (process-send-eof flymake-quicklintjs--proc))) + (let ((src-buf (current-buffer)) + (stdout-buf (generate-new-buffer " *flymake-quicklintjs-stdout*")) + (stderr-buf (generate-new-buffer " *flymake-quicklintjs-stderr*"))) + (save-restriction + (widen) + (setq flymake-quicklintjs--proc + (make-process + :name "flymake-quicklintjs" + :connection-type 'pipe + :noquery t + :buffer stdout-buf + :stderr stderr-buf + :command (quicklintjs-find-program + (let ((file (buffer-file-name))) + (when file (concat "--path-for-config-search=" file))) + "--stdin" "--output-format=emacs-lisp") + :sentinel + (lambda (p _ev) + (let ((proc-status (process-status p))) + (unwind-protect + (when (and (or (eq proc-status 'exit) + (eq proc-status 'signal)) + (with-current-buffer src-buf + (eq p flymake-quicklintjs--proc))) + (if (zerop (process-exit-status p)) + (flymake-quicklintjs--report stdout-buf + src-buf + report-fn) + (flymake-quicklintjs--report-with-crash + stdout-buf stderr-buf src-buf report-fn))) + (progn (kill-buffer stdout-buf) + (kill-buffer stderr-buf))))))) + (process-send-region flymake-quicklintjs--proc (point-min) (point-max)) + (process-send-eof flymake-quicklintjs--proc)))) -(provide 'flymake-quicklintjs) +;;;###autoload +(with-eval-after-load 'flymake + (add-hook 'flymake-diagnostic-functions #'flymake-quicklintjs nil t)) -;; quick-lint-js finds bugs in JavaScript programs. -;; Copyright (C) 2020 Matthew Glazar -;; -;; This file is part of quick-lint-js. -;; -;; quick-lint-js 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 of the License, or -;; (at your option) any later version. -;; -;; quick-lint-js 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 quick-lint-js. If not, see . +(provide 'flymake-quicklintjs) ;;; flymake-quicklintjs.el ends here diff --git a/plugin/emacs/lsp-quicklintjs.el b/plugin/emacs/lsp-quicklintjs.el index 48a28b0268..b8ed0fef8e 100644 --- a/plugin/emacs/lsp-quicklintjs.el +++ b/plugin/emacs/lsp-quicklintjs.el @@ -1,4 +1,27 @@ -;;; lsp-quicklintjs --- LSP support for quick-lint-js -*- lexical-binding: t; -*- +;;; lsp-quicklintjs.el --- LSP support for quick-lint-js -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Matthew "strager" Glazar + +;; Version: 0.0.1 +;; Author: Wagner Riffel +;; URL: https://quick-lint-js.com +;; Keywords: languages, tools +;; Package-Requires: ((quicklintjs "0.0.1") (lsp-mode "7.0.1") (emacs "26.1")) + +;; This file is part of quick-lint-js. +;; +;; quick-lint-js 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 of the License, or +;; (at your option) any later version. +;; +;; quick-lint-js 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 quick-lint-js. If not, see . ;;; Commentary: @@ -18,46 +41,32 @@ ;;; Code: (require 'lsp-mode) +(require 'quicklintjs) -(defgroup lsp-quicklintjs nil - "quick-lint-js LSP Mode integration." - :link '(url-link :tag "Website" "https://quick-lint-js.com")) - -(defcustom lsp-quicklintjs-program "quick-lint-js" - "Path to quick-lint-js program to run." - :group 'lsp-quicklintjs - :type 'stringp) +;;;###autoload +(defun lsp-quicklintjs () + "Like `lsp', but set root folder to `default-directory' to avoid project root\ +prompts." + (interactive) + ;; Don't mess with user's session state file + (set (make-local-variable 'lsp-session-file) + (expand-file-name (locate-user-emacs-file + ".lsp-quicklintjs-session-v1"))) + (let* ((session (lsp-session))) + (cl-pushnew (expand-file-name default-directory) + (lsp-session-folders session) :test 'equal) + (lsp--persist-session session)) + (lsp)) -(defcustom lsp-quicklintjs-args nil - "Arguments to quick-lint-js." - :group 'lsp-quicklintjs - :type '(repeat string)) - -(lsp-register-client - (make-lsp-client - :new-connection (lsp-stdio-connection `(,lsp-quicklintjs-program "--lsp-server" - ,@lsp-quicklintjs-args)) - :major-modes '(js-mode) - :server-id 'quick-lint-js)) +;;;###autoload +(with-eval-after-load 'lsp-mode + (lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection `,(quicklintjs-find-program + "--lsp-server")) + :major-modes '(js-mode) + :server-id 'quick-lint-js))) (provide 'lsp-quicklintjs) -;; quick-lint-js finds bugs in JavaScript programs. -;; Copyright (C) 2020 Matthew Glazar -;; -;; This file is part of quick-lint-js. -;; -;; quick-lint-js 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 of the License, or -;; (at your option) any later version. -;; -;; quick-lint-js 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 quick-lint-js. If not, see . - ;;; lsp-quicklintjs.el ends here diff --git a/plugin/emacs/quicklintjs-make-package.el b/plugin/emacs/quicklintjs-make-package.el new file mode 100644 index 0000000000..d4966ab08a --- /dev/null +++ b/plugin/emacs/quicklintjs-make-package.el @@ -0,0 +1,47 @@ +;;; quicklintjs-pkg.el --- Build quick-lint-js Emacs plugins packages -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Matthew "strager" Glazar + +;; Version: 0.0.1 +;; Author: Wagner Riffel +;; URL: https://quick-lint-js.com +;; Keywords: languages, tools +;; Package-Requires: ((emacs "24.5")) + +;; This file is part of quick-lint-js. +;; +;; quick-lint-js 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 of the License, or +;; (at your option) any later version. +;; +;; quick-lint-js 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 quick-lint-js. If not, see . + +;;; Commentary: + +;;; Code: + +(defun quicklintjs-batch-make-pkg () + (setq package-user-dir nil) + (cl-assert (= (length command-line-args-left) 1)) + + (let ((file (car command-line-args-left)) + (inhibit-message 't)) + (with-temp-buffer + (insert-file-contents-literally file) + (let* ((pkg-desc (package-buffer-info)) + (pkg-ver (package-desc-version pkg-desc)) + (pkg-dir (format "%s-%s.%s" + (file-name-sans-extension file) + (car pkg-ver) + (car (cdr pkg-ver))))) + (add-to-list 'package-directory-list pkg-dir) + (package-unpack pkg-desc))))) + +;;; quicklintjs-pkg.el ends here diff --git a/plugin/emacs/quicklintjs.el b/plugin/emacs/quicklintjs.el new file mode 100644 index 0000000000..e7a54d7109 --- /dev/null +++ b/plugin/emacs/quicklintjs.el @@ -0,0 +1,77 @@ +;;; quicklintjs.el --- Helper functions for quicklintjs Emacs plugins -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Matthew "strager" Glazar + +;; Version: 0.0.1 +;; Author: Wagner Riffel +;; URL: https://quick-lint-js.com +;; Keywords: languages, tools +;; Package-Requires: ((emacs "24.5")) + +;; This file is part of quick-lint-js. +;; +;; quick-lint-js 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 of the License, or +;; (at your option) any later version. +;; +;; quick-lint-js 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 quick-lint-js. If not, see . + +;;; Commentary: + +;; Shared parts of configuration and code among others Emacs plugins. + +;;; Code: + +(defgroup quicklintjs nil + "quick-lint-js finds bugs in JavaScript programs." + :prefix "quicklintjs-" + :group 'tools + :group 'processes + :link '(url-link :tag "Website" "https://quick-lint-js.com")) + +(defcustom quicklintjs-program-name "quick-lint-js" + "Quick-lint-js executable name to search." + :group 'quicklintjs + :type 'string + :safe 'stringp) + +(defcustom quicklintjs-program-args nil + "Arguments to `quicklintjs-program-name'." + :group 'quicklintjs + :type '(repeat 'string)) + +(defcustom quicklintjs-find-program-function #'quicklintjs-executable-find + "Function to find quick-lint-js." + :group 'quicklintjs + :type '(choice (const :tag "Search quick-lint-js in `exec-path'" + quicklintjs-executable-find) + (const :tag "Search quick-lint-js in node-modules" + quicklintjs-node-modules-executable-find) + (function :tag "Function to get quick-lint-js path"))) + +;;;###autoload +(defun quicklintjs-executable-find () + "Search `quicklintjs-program-name' in variable `exec-path'." + (executable-find quicklintjs-program-name)) + +;;;###autoload +(defun quicklintjs-find-program (&rest argv) + "Make a list of strings by calling `quicklintjs-find-program-function',\ +appending `quicklintjs-program-args' and ARGV. +Empty strings and nil are ignored." + (cl-remove-if-not (lambda (a) (and (stringp a) + (> (length a) 0))) + (append (list (funcall + quicklintjs-find-program-function)) + quicklintjs-program-args argv))) + +(provide 'quicklintjs) + +;;; quicklintjs.el ends here diff --git a/plugin/emacs/test/quicklintjs-test.el b/plugin/emacs/test/quicklintjs-test.el index d2ba5ae04d..36a40f77db 100644 --- a/plugin/emacs/test/quicklintjs-test.el +++ b/plugin/emacs/test/quicklintjs-test.el @@ -2,8 +2,10 @@ ;;; Commentary: ;;; Code: +(require 'cl-lib) (require 'ert) (require 'package) +(require 'quicklintjs) (defconst cache-dir-name (concat (expand-file-name default-directory) @@ -28,10 +30,13 @@ (quicklintjs-install-deps (if (>= emacs-major-version 26) '(flycheck eglot lsp-mode) '(flycheck))) + + (set 'quicklintjs-find-program-function (lambda () "quick-lint-js")) (def-flycheck-tests) (def-eglot-tests) (def-lsp-tests) (def-flymake-tests) + (def-quicklintjs-tests) (ert-run-tests-batch-and-exit)) (defun def-flymake-tests () @@ -73,7 +78,7 @@ foobar\")((16 . 22) 2 \"E057\" \"use of undeclared variable: foobar\")(\ (with-current-buffer js-buf (insert "foobar") (should (equal (call-process-region (point-min) (point-max) - flymake-quicklintjs-program nil + quicklintjs-program-name nil out-buf nil "--stdin" "--output-format=emacs-lisp") 0))))) @@ -84,7 +89,7 @@ foobar\")((16 . 22) 2 \"E057\" \"use of undeclared variable: foobar\")(\ (insert "function") (should (equal (call-process-region (point-min) (point-max) - flymake-quicklintjs-program nil + quicklintjs-program-name nil out-buf nil "--stdin" "--output-format=emacs-lisp") 0)))))) @@ -136,6 +141,20 @@ foobar\")((16 . 22) 2 \"E057\" \"use of undeclared variable: foobar\")(\ :id "E059" :checker javascript-quicklintjs :end-line 1 :end-column 2))))) +(defun def-quicklintjs-tests () + (ert-deftest quicklintjs-find-program-argv () + (should (cl-every (lambda (a b) (string= a b)) + (quicklintjs-find-program "foo" "baz") + '("quick-lint-js" "foo" "baz")))) + (ert-deftest quicklintjs-find-program-removes-nil () + (should (cl-every (lambda (a b) (string= a b)) + (quicklintjs-find-program "foo" nil "baz") + '("quick-lint-js" "foo" "baz")))) + (ert-deftest quicklintjs-find-program-removes-empty () + (should (cl-every (lambda (a b) (string= a b)) + (quicklintjs-find-program "foo" "" "baz") + '("quick-lint-js" "foo" "baz"))))) + ;; quick-lint-js finds bugs in JavaScript programs. ;; Copyright (C) 2020 Matthew "strager" Glazar ;; diff --git a/src/emacs-lisp-error-reporter.cpp b/src/emacs-lisp-error-reporter.cpp index a0eb7b7562..1f99b845a4 100644 --- a/src/emacs-lisp-error-reporter.cpp +++ b/src/emacs-lisp-error-reporter.cpp @@ -82,6 +82,7 @@ void emacs_lisp_error_formatter::write_after_message(severity sev, return; } this->output_ << "\")"; + this->output_.flush(); } }