From 3e8d89f57d5172aaaab5c44d33ab468284663223 Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Mon, 4 Mar 2024 17:02:24 -0800 Subject: [PATCH] feat(fmt): Add formatters (#232) * feat(fmt): Add formatters * chore: Changelog * correct spelling * don't test foramt elisp-autofmt --- CHANGELOG.md | 1 + cmds/core/format.js | 38 +++++++++ cmds/core/lint.js | 2 +- cmds/core/test.js | 2 +- cmds/format/elfmt.js | 31 ++++++++ cmds/format/elisp-autofmt.js | 31 ++++++++ cmds/generate/autoloads.js | 2 +- .../Getting-Started/Basic-Usage/_index.en.md | 5 +- .../Basic-Usage/_index.zh-tw.md | 5 +- .../Commands-and-options/_index.en.md | 27 +++++++ .../Commands-and-options/_index.zh-tw.md | 27 +++++++ lisp/format/elfmt.el | 79 +++++++++++++++++++ lisp/format/elisp-autofmt.el | 79 +++++++++++++++++++ lisp/help/format/elfmt | 17 ++++ lisp/help/format/elisp-autofmt | 17 ++++ test/commands/local/run.sh | 4 + 16 files changed, 360 insertions(+), 7 deletions(-) create mode 100644 cmds/core/format.js create mode 100644 cmds/format/elfmt.js create mode 100644 cmds/format/elisp-autofmt.js create mode 100644 lisp/format/elfmt.el create mode 100644 lisp/format/elisp-autofmt.el create mode 100644 lisp/help/format/elfmt create mode 100644 lisp/help/format/elisp-autofmt diff --git a/CHANGELOG.md b/CHANGELOG.md index 60015890..088e9d71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how * feat: Add `loc` command (#227) * fix: Allow initialize in other scopes (#229) * feat: Rename command `check-eask` to `analyze` (#230) +* feat(fmt): Add formatters (#232) ## 0.9.x > Released Nov 17, 2023 diff --git a/cmds/core/format.js b/cmds/core/format.js new file mode 100644 index 00000000..7b8af27a --- /dev/null +++ b/cmds/core/format.js @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2024 the Eask authors. + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +"use strict"; + +exports.command = ['format ', 'fmt ']; +exports.desc = 'Run formatters'; +exports.builder = function (yargs) { + yargs.usage(`${exports.desc} + +Usage: eask format [options..]`) + .commandDir('../format/') + .demandCommand(); + + /* XXX: Configure only in the menu. */ + if (UTIL.cmd_count() == 1) { + yargs.positional( + '', { + description: 'type of the formatter', + }); + } +} + +exports.handler = async (argv) => { }; diff --git a/cmds/core/lint.js b/cmds/core/lint.js index b0766be2..b11e81b6 100644 --- a/cmds/core/lint.js +++ b/cmds/core/lint.js @@ -18,7 +18,7 @@ "use strict"; exports.command = ['lint ']; -exports.desc = 'Run linter'; +exports.desc = 'Run linters'; exports.builder = function (yargs) { yargs.usage(`${exports.desc} diff --git a/cmds/core/test.js b/cmds/core/test.js index 69f65107..fd1f2b1a 100644 --- a/cmds/core/test.js +++ b/cmds/core/test.js @@ -18,7 +18,7 @@ "use strict"; exports.command = ['test ']; -exports.desc = 'Run test'; +exports.desc = "Run regression/unit tests"; exports.builder = function (yargs) { yargs.usage(`${exports.desc} diff --git a/cmds/format/elfmt.js b/cmds/format/elfmt.js new file mode 100644 index 00000000..2276a39f --- /dev/null +++ b/cmds/format/elfmt.js @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2024 the Eask authors. + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +"use strict"; + +exports.command = ['elfmt [files..]']; +exports.desc = 'Reformat Elisp source with elfmt'; +exports.builder = yargs => yargs + .positional( + '[files..]', { + description: 'specify files to do elfmt', + type: 'array', + }); + +exports.handler = async (argv) => { + await UTIL.e_call(argv, 'format/elfmt', argv.files); +}; diff --git a/cmds/format/elisp-autofmt.js b/cmds/format/elisp-autofmt.js new file mode 100644 index 00000000..b6d30b67 --- /dev/null +++ b/cmds/format/elisp-autofmt.js @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2024 the Eask authors. + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +"use strict"; + +exports.command = ['elisp-autofmt [files..]']; +exports.desc = 'Reformat Elisp source with elisp-autofmt'; +exports.builder = yargs => yargs + .positional( + '[files..]', { + description: 'specify files to do elisp-autofmt', + type: 'array', + }); + +exports.handler = async (argv) => { + await UTIL.e_call(argv, 'format/elisp-autofmt', argv.files); +}; diff --git a/cmds/generate/autoloads.js b/cmds/generate/autoloads.js index 1eca263e..3fd22632 100644 --- a/cmds/generate/autoloads.js +++ b/cmds/generate/autoloads.js @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022-2023 the Eask authors. + * Copyright (C) 2022-2024 the Eask authors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/docs/content/Getting-Started/Basic-Usage/_index.en.md b/docs/content/Getting-Started/Basic-Usage/_index.en.md index 8d4e27fc..96bc13d9 100644 --- a/docs/content/Getting-Started/Basic-Usage/_index.en.md +++ b/docs/content/Getting-Started/Basic-Usage/_index.en.md @@ -43,6 +43,7 @@ Commands: path [patterns..] Print the PATH (exec-path) from workspace [aliases: exec-path] exec [args..] Execute command with correct environment PATH set up files [patterns..] Print all package files + format Run formatters [aliases: fmt] generate Generate files that are used for the development info Display information about the current package init [files..] Initialize project to use Eask @@ -50,7 +51,7 @@ Commands: install [names..] Install packages keywords List available keywords that can be used in the header section link Manage links - lint Run linter + lint Run linters list List packages load-path [patterns..] Print the load-path from workspace load [files..] Load elisp files @@ -63,7 +64,7 @@ Commands: run Run custom tasks search [queries..] Search packages status Display the state of the workspace - test Run test + test Run regression/unit tests uninstall [names..] Uninstall packages [aliases: delete] upgrade [names..] Upgrade packages locate Print out Eask installed location diff --git a/docs/content/Getting-Started/Basic-Usage/_index.zh-tw.md b/docs/content/Getting-Started/Basic-Usage/_index.zh-tw.md index be4e3762..d34564c5 100644 --- a/docs/content/Getting-Started/Basic-Usage/_index.zh-tw.md +++ b/docs/content/Getting-Started/Basic-Usage/_index.zh-tw.md @@ -40,6 +40,7 @@ Commands: path [patterns..] Print the PATH (exec-path) from workspace [aliases: exec-path] exec [args..] Execute command with correct environment PATH set up files [patterns..] Print all package files + format Run formatters [aliases: fmt] generate Generate files that are used for the development info Display information about the current package init [files..] Initialize project to use Eask @@ -47,7 +48,7 @@ Commands: install [names..] Install packages keywords List available keywords that can be used in the header section link Manage links - lint Run linter + lint Run linters list List packages load-path [patterns..] Print the load-path from workspace load [files..] Load elisp files @@ -60,7 +61,7 @@ Commands: run Run custom tasks search [queries..] Search packages status Display the state of the workspace - test Run test + test Run regression/unit tests uninstall [names..] Uninstall packages [aliases: delete] upgrade [names..] Upgrade packages locate Print out Eask installed location diff --git a/docs/content/Getting-Started/Commands-and-options/_index.en.md b/docs/content/Getting-Started/Commands-and-options/_index.en.md index 66cff800..67e715de 100644 --- a/docs/content/Getting-Started/Commands-and-options/_index.en.md +++ b/docs/content/Getting-Started/Commands-and-options/_index.en.md @@ -588,6 +588,8 @@ $ eask [GLOBAL-OPTIONS] link list # 🚩 Cleaning +Delete various files produced during building. + ## 🔍 eask clean workspace Delete `.eask` from the current workspace. @@ -753,6 +755,8 @@ $ eask [GLOBAL-OPTIONS] lint regexps [FILES..] # 🚩 Testing +Run regression/unit tests. + ## 🔍 eask test activate Activate package; use to test the package activation @@ -803,6 +807,26 @@ $ eask [GLOBAL-OPTIONS] test melpazoid [DIRECTORIES..] 💡 If **[DIRECTORIES..]** is not passed in; it will use the current workspace instead. {{< /hint >}} +# 🚩 Formatting + +Commands that formats your Emacs source files. + +## 🔍 eask format elisp-autofmt + +Run [elisp-autofmt][] formatter. + +```sh +$ eask [GLOBAL-OPTIONS] format elisp-autofmt [FILES..] +``` + +## 🔍 eask format elfmt + +Run [elfmt][] formatter. + +```sh +$ eask [GLOBAL-OPTIONS] format elfmt [FILES..] +``` + # 🚩 Control DSL List of commands that control DSL. @@ -1040,3 +1064,6 @@ Do not use a proxy for any URL matching pattern. [ert-runner]: https://github.com/rejeep/ert-runner.el [buttercup]: https://github.com/jorgenschaefer/emacs-buttercup [melpazoid]: https://github.com/riscy/melpazoid + +[elisp-autofmt]: https://codeberg.org/ideasman42/emacs-elisp-autofmt +[elfmt]: https://github.com/riscy/elfmt diff --git a/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md b/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md index 4c79855e..69c995f1 100644 --- a/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md +++ b/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md @@ -575,6 +575,8 @@ $ eask [GLOBAL-OPTIONS] link list # 🚩 清理 +刪除建置過程中產生的各種檔案。 + ## 🔍 eask clean workspace 從當前工作區中刪除 `.eask` 。 @@ -740,6 +742,8 @@ $ eask [GLOBAL-OPTIONS] lint regexps [FILES..] # 🚩 測試框架 +運行回歸/單元測試。 + ## 🔍 eask test activate 激活包; 用於測試包激活 @@ -790,6 +794,26 @@ $ eask [GLOBAL-OPTIONS] test melpazoid [DIRECTORIES..] 💡 如果未傳入 **[DIRECTORIES..]**,它將使用目前工作空間。 {{< /hint >}} +# 🚩 格式化 + +格式化 Emacs 源文件的命令。 + +## 🔍 eask format elisp-autofmt + +運行 [elisp-autofmt][] 格式器. + +```sh +$ eask [GLOBAL-OPTIONS] format elisp-autofmt [FILES..] +``` + +## 🔍 eask format elfmt + +運行 [elfmt][] 格式器. + +```sh +$ eask [GLOBAL-OPTIONS] format elfmt [FILES..] +``` + # 🚩 控制 DSL 控制 DSL 的指令列表。 @@ -1026,3 +1050,6 @@ $ eask --proxy "localhost:8888" [COMMAND] [ert-runner]: https://github.com/rejeep/ert-runner.el [buttercup]: https://github.com/jorgenschaefer/emacs-buttercup [melpazoid]: https://github.com/riscy/melpazoid + +[elisp-autofmt]: https://codeberg.org/ideasman42/emacs-elisp-autofmt +[elfmt]: https://github.com/riscy/elfmt diff --git a/lisp/format/elfmt.el b/lisp/format/elfmt.el new file mode 100644 index 00000000..234de463 --- /dev/null +++ b/lisp/format/elfmt.el @@ -0,0 +1,79 @@ +;;; format/elfmt.el --- Run elfmt -*- lexical-binding: t; -*- + +;;; Commentary: +;; +;; Commmand use to run `elfmt' for all files +;; +;; $ eask format elfmt [files..] +;; +;; +;; Positionals: +;; +;; [files..] files you want elfmt to run on +;; + +;;; Code: + +(let ((dir (file-name-directory (nth 1 (member "-scriptload" command-line-args))))) + (load (expand-file-name "_prepare.el" + (locate-dominating-file dir "_prepare.el")) + nil t)) + +;; +;;; Externals + +(declare-function elfmt-buffer "ext:elisp-autofmt.el") + +;; +;;; Flags + +(advice-add #'eask-allow-error-p :override #'always) + +;; +;;; Core + +(defconst eask-format-elfmt--version nil + "`elfmt' version.") + +(defun eask-format-elfmt--file (filename) + "Run elfmt on FILENAME." + (let* ((filename (expand-file-name filename)) + (file (eask-root-del filename))) + (with-current-buffer (find-file filename) + (elfmt-buffer) + (save-buffer) + (kill-buffer)))) + +(eask-start + ;; Preparation + (eask-with-archives '("gnu" "melpa" "jcs-elpa") + (eask-package-install 'elfmt)) + (setq eask-format-elfmt--version (eask-package--version-string 'elfmt)) + + ;; Start formatting + (require 'elfmt) + (let* ((patterns (eask-args)) + (files (if patterns + (eask-expand-file-specs patterns) + (eask-package-el-files)))) + (cond + ;; Files found, do the action! + (files + (eask-msg "") + (eask-msg "Running `%s` formatter (%s)" + (ansi-green "elfmt") (ansi-yellow eask-format-elfmt--version)) + (eask-progress-seq " - Formatting" files "done! ✓" #'eask-format-elfmt--file) + (eask-msg "") + (eask-info "(Total of %s file%s %s formatted)" (length files) + (eask--sinr files "" "s") + (eask--sinr files "has" "have"))) + ;; Pattern defined, but no file found! + (patterns + (eask-info "(No files match wildcard: %s)" + (mapconcat #'identity patterns " "))) + ;; Default, print help! + (t + (eask-info "(No files have been formatted)") + (eask-help "format/elfmt"))))) + +;;; format/elfmt.el ends here diff --git a/lisp/format/elisp-autofmt.el b/lisp/format/elisp-autofmt.el new file mode 100644 index 00000000..eedb2332 --- /dev/null +++ b/lisp/format/elisp-autofmt.el @@ -0,0 +1,79 @@ +;;; format/elisp-autofmt.el --- Run elisp-autofmt -*- lexical-binding: t; -*- + +;;; Commentary: +;; +;; Commmand use to run `elisp-autofmt' for all files +;; +;; $ eask format elisp-autofmt [files..] +;; +;; +;; Positionals: +;; +;; [files..] files you want elisp-autofmt to run on +;; + +;;; Code: + +(let ((dir (file-name-directory (nth 1 (member "-scriptload" command-line-args))))) + (load (expand-file-name "_prepare.el" + (locate-dominating-file dir "_prepare.el")) + nil t)) + +;; +;;; Externals + +(declare-function elisp-autofmt-buffer "ext:elisp-autofmt.el") + +;; +;;; Flags + +(advice-add #'eask-allow-error-p :override #'always) + +;; +;;; Core + +(defconst eask-format-elisp-autofmt--version nil + "`elisp-autofmt' version.") + +(defun eask-format-elisp-autofmt--file (filename) + "Run elisp-autofmt on FILENAME." + (let* ((filename (expand-file-name filename)) + (file (eask-root-del filename))) + (with-current-buffer (find-file filename) + (elisp-autofmt-buffer) + (save-buffer) + (kill-buffer)))) + +(eask-start + ;; Preparation + (eask-with-archives '("gnu" "melpa") + (eask-package-install 'elisp-autofmt)) + (setq eask-format-elisp-autofmt--version (eask-package--version-string 'elisp-autofmt)) + + ;; Start formatting + (require 'elisp-autofmt) + (let* ((patterns (eask-args)) + (files (if patterns + (eask-expand-file-specs patterns) + (eask-package-el-files)))) + (cond + ;; Files found, do the action! + (files + (eask-msg "") + (eask-msg "Running `%s` formatter (%s)" + (ansi-green "elisp-autofmt") (ansi-yellow eask-format-elisp-autofmt--version)) + (eask-progress-seq " - Formatting" files "done! ✓" #'eask-format-elisp-autofmt--file) + (eask-msg "") + (eask-info "(Total of %s file%s %s formatted)" (length files) + (eask--sinr files "" "s") + (eask--sinr files "has" "have"))) + ;; Pattern defined, but no file found! + (patterns + (eask-info "(No files match wildcard: %s)" + (mapconcat #'identity patterns " "))) + ;; Default, print help! + (t + (eask-info "(No files have been formatted)") + (eask-help "format/elisp-autofmt"))))) + +;;; format/elisp-autofmt.el ends here diff --git a/lisp/help/format/elfmt b/lisp/help/format/elfmt new file mode 100644 index 00000000..b905269a --- /dev/null +++ b/lisp/help/format/elfmt @@ -0,0 +1,17 @@ + +💡 You need to specify file(s) you want the elfmt to run + + $ eask format elfmt FILE-1 FILE-2 + +💡 Or edit Eask file with [package-file] or [files] specifier + + [+] (package-file "ENTRY") ; One argument with a string + [+] (files "FILE-1" "FILE-2" ...) ; All arguments are wildcard patterns + +For example, + + [+] (files "*.el") + +💡 Tip: You can use the command [files] to show all selected files + + $ eask files diff --git a/lisp/help/format/elisp-autofmt b/lisp/help/format/elisp-autofmt new file mode 100644 index 00000000..dd9d9061 --- /dev/null +++ b/lisp/help/format/elisp-autofmt @@ -0,0 +1,17 @@ + +💡 You need to specify file(s) you want the elisp-autofmt to run + + $ eask format elisp-autofmt FILE-1 FILE-2 + +💡 Or edit Eask file with [package-file] or [files] specifier + + [+] (package-file "ENTRY") ; One argument with a string + [+] (files "FILE-1" "FILE-2" ...) ; All arguments are wildcard patterns + +For example, + + [+] (files "*.el") + +💡 Tip: You can use the command [files] to show all selected files + + $ eask files diff --git a/test/commands/local/run.sh b/test/commands/local/run.sh index 485a4b25..57ddc9bf 100644 --- a/test/commands/local/run.sh +++ b/test/commands/local/run.sh @@ -91,6 +91,10 @@ eask lint regexps # Testing eask test activate +# Formatting +#eask format elisp-autofmt # Only 29.1+ +eask format elfmt + # Cleaning eask clean .eask eask clean elc