diff --git a/CHANGELOG.md b/CHANGELOG.md index 40b79391..a5182e2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how * Enter docker directly when no arguments (#191) * Add command to generate recipe (#192) * Add option to init from `Eldev`-file (#193) +* Add command `commnad` for custom commands (#195) ## 0.8.x > Released Mar 08, 2023 diff --git a/cmds/core/command.js b/cmds/core/command.js new file mode 100644 index 00000000..0fc46db6 --- /dev/null +++ b/cmds/core/command.js @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2023 Jen-Chieh Shen + * + * 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 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. + */ + +"use strict"; + +exports.command = ['command [names..]', 'cmd [names..]']; +exports.desc = 'Run custom command'; +exports.builder = yargs => yargs + .positional( + '[names..]', { + description: 'list of function commands to execute', + type: 'array', + }); + +exports.handler = async (argv) => { + await UTIL.e_call(argv, 'core/command' + , argv.names); +}; diff --git a/docs/content/en/Getting-Started/Advanced-Usage.md b/docs/content/en/Getting-Started/Advanced-Usage.md index c12d188e..b6225af1 100644 --- a/docs/content/en/Getting-Started/Advanced-Usage.md +++ b/docs/content/en/Getting-Started/Advanced-Usage.md @@ -3,6 +3,8 @@ title: 🔧 Advanced Usage weight: 400 --- +{{< toc >}} + `Eask` is just a regular Emacs Lisp file and should be read from Emacs itself! You can do: @@ -12,6 +14,8 @@ You can do: (setq byte-compile-error-on-warn t) ; Signal error if warning occurred ``` +# 🪝 Hooks + `eask` provides some hooks which enable you to execute code before and after each command. The hooks look like so: @@ -58,3 +62,13 @@ therefore, ;; do stuff before checkdoc linting... )) ``` + +# 📇 Adding your own command + +You can add your own command through our command interface: + +```elisp +(eask-defcommand my-test-command + "A test command that prints out useless message." + (message "This is a test command!")) +``` diff --git a/docs/content/en/Getting-Started/Basic-Usage/_index.md b/docs/content/en/Getting-Started/Basic-Usage/_index.md index a9d5e3e0..7c4b054d 100644 --- a/docs/content/en/Getting-Started/Basic-Usage/_index.md +++ b/docs/content/en/Getting-Started/Basic-Usage/_index.md @@ -34,6 +34,7 @@ Usage: eask [options..] Commands: archives List out all package archives [aliases: sources] clean Delete various files produced during building + command [names..] Run custom command [aliases: cmd] compile [names..] Byte compile all Emacs Lisp files in the package create Create a new elisp project docker [args..] Launch specified Emacs version in a Docker container diff --git a/docs/content/en/Getting-Started/Commands-and-options.md b/docs/content/en/Getting-Started/Commands-and-options.md index 6906926f..f7d86846 100644 --- a/docs/content/en/Getting-Started/Commands-and-options.md +++ b/docs/content/en/Getting-Started/Commands-and-options.md @@ -278,16 +278,6 @@ Concatenate all Emacs Lisp files into one file. $ eask [GLOBAL-OPTIONS] concate [FILES..] ``` -## 🔍 eask run - -Run the script. - -```sh -$ eask [GLOBAL-OPTIONS] run [FILES..] -``` - -Alias: `run-script` - # 🚩 Execution Commands allow you execute on top of Eask core. @@ -326,6 +316,26 @@ Evaluate `FORM` as a lisp form. $ eask [GLOBAL-OPTIONS] eval [FORM] ``` +## 🔍 eask run + +Run the script. + +```sh +$ eask [GLOBAL-OPTIONS] run [NAMES..] +``` + +Alias: `run-script` + +## 🔍 eask command + +Run the command. + +```sh +$ eask [GLOBAL-OPTIONS] command [NAMES..] +``` + +Alias: `cmd` + ## 🔍 eask docker Launch specified Emacs version in a Docker container. diff --git a/docs/content/zh-TW/Getting-Started/Advanced-Usage.md b/docs/content/zh-TW/Getting-Started/Advanced-Usage.md index ec45c2fd..8e599fe1 100644 --- a/docs/content/zh-TW/Getting-Started/Advanced-Usage.md +++ b/docs/content/zh-TW/Getting-Started/Advanced-Usage.md @@ -3,6 +3,8 @@ title: 🔧 進階用法 weight: 400 --- +{{< toc >}} + `Eask` 只是一個普通的 Emacs Lisp 文件,應該從 Emacs 本身讀取! 你可以做: ```elisp @@ -11,6 +13,8 @@ weight: 400 (setq byte-compile-error-on-warn t) ; 出現警告時信號錯誤 ``` +# 🪝 Hooks + `eask` 提供了一些 hooks,使您能夠在每個命令之前和之後執行代碼。 hook 看起來像這樣: - `eask-before-COMMAND-hook` @@ -55,3 +59,13 @@ $ eask generate license # generate/license ;; 在 checkdoc linting 之前做一些事情... )) ``` + +# 📇 加入你自己的指令 + +您可以透過我們的 command 介面添加自己的命令: + +```elisp +(eask-defcommand my-test-command + "測試指令印出無用的訊息。" + (message "這是一個測試指令!")) +``` diff --git a/docs/content/zh-TW/Getting-Started/Basic-Usage/_index.md b/docs/content/zh-TW/Getting-Started/Basic-Usage/_index.md index 284a5d97..0e561ba2 100644 --- a/docs/content/zh-TW/Getting-Started/Basic-Usage/_index.md +++ b/docs/content/zh-TW/Getting-Started/Basic-Usage/_index.md @@ -31,6 +31,7 @@ Usage: eask [options..] Commands: archives List out all package archives [aliases: sources] clean Delete various files produced during building + command [names..] Run custom command [aliases: cmd] compile [names..] Byte compile all Emacs Lisp files in the package create Create a new elisp project docker [args..] Launch specified Emacs version in a Docker container diff --git a/docs/content/zh-TW/Getting-Started/Commands-and-options.md b/docs/content/zh-TW/Getting-Started/Commands-and-options.md index fae437be..bbe91100 100644 --- a/docs/content/zh-TW/Getting-Started/Commands-and-options.md +++ b/docs/content/zh-TW/Getting-Started/Commands-and-options.md @@ -274,16 +274,6 @@ $ eask [GLOBAL-OPTIONS] cat [PATTERNS..] $ eask [GLOBAL-OPTIONS] concate [FILES..] ``` -## 🔍 eask run - -運行腳本。 - -```sh -$ eask [GLOBAL-OPTIONS] run [FILES..] -``` - -別名: `run-script` - # 🚩 執行 指令允許執行在 Eask 核心之上。 @@ -322,6 +312,26 @@ $ eask [GLOBAL-OPTIONS] emacs [ARGUMENTS ...] $ eask [GLOBAL-OPTIONS] eval [FORM] ``` +## 🔍 eask run + +運行腳本。 + +```sh +$ eask [GLOBAL-OPTIONS] run [NAMES..] +``` + +別名: `run-script` + +## 🔍 eask command + +運行指令。 + +```sh +$ eask [GLOBAL-OPTIONS] command [NAMES..] +``` + +別名: `cmd` + ## 🔍 eask docker 在 Docker 容器中啟動指定的 Emacs 版本 diff --git a/lisp/_prepare.el b/lisp/_prepare.el index 6db4c69b..b30d51b5 100644 --- a/lisp/_prepare.el +++ b/lisp/_prepare.el @@ -2,6 +2,15 @@ ;;; Commentary: Prepare to setup Eask environment for sandboxing ;;; Code: +;; +;;; Requirement + +(when (version< emacs-version "26.1") + (error "Eask requires Emacs 26.1 and above!")) + +;; +;;; Includes + (require 'ansi-color) (require 'package) (require 'project) @@ -1844,9 +1853,17 @@ variable we use to test validation." (eask-load "extern/package-build") ;; -;;; Requirement - -(when (version< emacs-version "26.1") - (eask-error "Eask requires Emacs 26.1 and above!")) +;;; API + +(defvar eask-commands nil + "List of defined commands.") + +(defmacro eask-defcommand (name &rest body) + "Define an Eask command." + (declare (doc-string 2) (indent 1)) + (or name (error "Cannot define '%s' as a command" name)) + (push name eask-commands) + (setq eask-commands (delete-dups eask-commands)) + `(defun ,name nil ,@body)) ;;; _prepare.el ends here diff --git a/lisp/core/command.el b/lisp/core/command.el new file mode 100644 index 00000000..6afaa79a --- /dev/null +++ b/lisp/core/command.el @@ -0,0 +1,72 @@ +;;; core/command.el --- Run custom command -*- lexical-binding: t; -*- + +;;; Commentary: +;; +;; Command use to run custom command +;; +;; $ eask command [names..] +;; +;; +;; Positionals: +;; +;; [names..] name of the function command +;; + +;;; 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)) + +(defun eask--command-desc (name) + "Return command's description by its command's NAME." + (car (split-string (documentation name) "\n"))) + +(defun eask--print-commands () + "Print all available commands." + (eask-msg "available via `eask command`") + (eask-msg "") + (let* ((keys (reverse eask-commands)) + (offset (eask-seq-str-max keys)) + (fmt (concat " %-" (eask-2str offset) "s %s"))) + (dolist (key keys) + (eask-msg fmt key (eask--command-desc key))) + (eask-msg "") + (eask-info "(Total of %s available script%s)" (length keys) + (eask--sinr keys "" "s")))) + +(defun eask--execute-command (name) + "Execute the command by NAME." + (eask-info "[RUN]: %s" name) + (funcall (eask-intern name))) + +(defun eask--unmatched-commands (commands) + "Return a list of COMMANDS that cannot be found in `eask-commands'." + (let (unmatched) + (dolist (command commands) + (unless (memq (eask-intern command) eask-commands) + (push command unmatched))) + unmatched)) + +(eask-start + (cond ((null eask-commands) + (eask-info "(No command specified)") + (eask-help "core/command")) + ((eask-all-p) + (dolist (name (reverse eask-commands)) + (eask--execute-command name))) + ((when-let ((commands (eask-args))) + (if-let ((unmatched (eask--unmatched-commands commands))) + (progn ; if there are unmatched commands, don't even try to execute + (eask-info "(Missing command%s: `%s`)" + (eask--sinr unmatched "" "s") + (mapconcat #'identity unmatched ", ")) + (eask-msg "") + (eask--print-commands)) + (dolist (command commands) + (eask--execute-command command)) + t))) + (t (eask--print-commands)))) + +;;; core/command.el ends here diff --git a/lisp/help/core/command b/lisp/help/core/command new file mode 100644 index 00000000..4e80b7c1 --- /dev/null +++ b/lisp/help/core/command @@ -0,0 +1,6 @@ + +💡 Make sure you have specify a (eask-defcommand ..) function inside your Eask file! + + [+] (eask-defcommand my-command + [+] "This is a test command." + [+] (message "My test commnad!"))