Modern Elisp package development system.
Keg is 100% Elisp project and it developed as alternative to Cask.
git clone https://github.com/conao3/keg.el.git .keg
PATH=$HOME/.keg/bin:$PATH
(leaf keg :ensure t)
(leaf keg-mode :ensure t)
This repository includes keg
executable, keg
Elisp package, keg-mode
Emacs major-mode.
And keg-setup for GitHub actions is available.
In order for Keg to recognize your project, you need to add the
name Keg
to the root of your project.
Keg is plain text in S-expression and there are major-mode for editing the file to get better indentation and font-lock.
M-x install-package keg-mode
The syntax is as follows.
KEG := (OP {OP}-ARGS...)
OP can be source
, package
, dev-dependency
.
The source
can be given in succession with the following
arguments The mapping between symbols and URLs is as follows.
(defvar keg-archives
'((gnu . "https://elpa.gnu.org/packages/")
(org . "https://orgmode.org/elpa/")
(melpa . "https://melpa.org/packages/")
(celpa . "https://celpa.conao3.com/packages/"))
"Alist for symbol to ELPA url.")
In addition, you can customize or add source URLs in Keg
file
by writing cons cell like element of keg-archives as source. String is also allowed as source.
“https://example.com/elpa” means (https://example\.com/elpa . "https://example.com/elpa")
.
(source (gnu . "http://elpa.zilongshanren.com/gnu/")
(melpa . "http://elpa.zilongshanren.com/melpa/"))
When sources should be customized only in your environoent, use environmental variable KEGPACKAGEARCHIVES
.
Its value should be string which is read
to list set to keg-archives
.
A package
can also contain more details about the package.
(The package
({package-symbol}
{package-args}...)
...)
With this specification, Keg is now correctly recognize multi package if you mixed multi package in one repository.
Inaddition, keg commands can be executed for specific packages.
For example,
keg build {package}
If you specify a package-symbol
, the file named
{package-symbol}.el
is needed and used only the header written
in the file to resolve dependency.
This is the same way as MELPA. package-symbol
corresponding to
the name of the MELPA recipe file.
package-args
could accept alist and currently only
recipe
is valid.
It accepts the same S-expression as the MELPA recipe file.
dev-dependency
is not a package dependency but you need for
package development like buttercup
or ert
.
(dev-dependency {package}...)
script
defines sexp evaluated by keg script [SCRIPT-NAME]
.
(script
({script-name}
{sexp}...)
...)
You can use function keg-shell
when you want to run shell command.
This function recieve any number of arguments, COMMAND
s.
Each argument is shell command string or list of strings whose car is command name
and whose cdr is list of string argument passed to command.
each COMMAND
run if previous COMMAND
returns 0, which means exiting normally.
In the other words, each COMMAND pretendto be connected with &&
.
If returned value is number, it is used as exit code status. Otherwise return 0.
(script
;; Pass shell command
(test
(keg-shell "keg exec emacs --batch -l keg-tests.el -f cort-test-run"))
;; Pass command and arguments (`test2' is same as `test')
(test2
(keg-shell '("keg" "exec" "emacs" "--batch" "-l" "keg-tests.el" "-f" "cort-test-run")))
;; Continuous multiple command
(test-all
(keg-shell "keg clean-elc"
"keg run test"
"keg build"
;; You can use different style COMMAND in one `keg-shell'
'("keg" "run" "test")
"keg-clean-elc"))
(build-keg-mode
(keg-shell "KEGINSTALLPACKAGES=\"keg-mode\" keg build keg-mode"))
(say-hello
(message "Hello!!!!")
(message "World!!!!")))
Some subcommands (listed below) have special script, which run before/after running the subcommand.
pre-SUBCOMMAND
or post-SUBCOMMAND
runs before or after SUBCOMMAND
running.
install
exec
emacs
eval
lint
build
clean-elc
clean
(script
(pre-install
(message "Let's Install!"))
(post-install
(message "Installation is successful!")))
So, for example, the following Keg file is valid.
;; Keg
(source gnu melpa)
(package
(keg
(recipe . (keg :fetcher github :repo "conao3/keg.el"
:files (:defaults (:exclude "keg-mode.el" "flycheck-keg.el")))))
(keg-mode
(recipe . (keg-mode :fetcher github :repo "conao3/keg.el" :files ("keg-mode.el"))))
(flycheck-keg
(recipe . (flycheck-keg :fetcher github :repo "conao3/keg.el" :files ("flycheck-keg.el")))))
(dev-dependency cort)
(script
(test
(keg-shell "keg exec emacs --batch -l keg-tests.el -f cort-test-run"))
(build-keg-mode
(keg-shell "KEGINSTALLPACKAGES=\"keg-mode\" keg build keg-mode"))
(say-hello
(message "Hello!!!!")
(message "World!!!!"))
(pre-install
(message "Let's Install!"))
(post-install
(message "Installation is successful!")))
This Keg file configured keg to use ELPA and MELPA as package-archives to resolve package dependencies.
There are three packages in this repository: keg
, keg-mode
, flycheck-keg
.
In addition, each recipe is specified.
Therefore, it works as follows.
$ keg build
Compiling /home/conao/dev/repos/keg.el/flycheck-keg.el...
Compiling /home/conao/dev/repos/keg.el/keg.el...
Compiling /home/conao/dev/repos/keg.el/keg-ansi.el...
Compiling /home/conao/dev/repos/keg.el/keg-cli.el...
Compiling /home/conao/dev/repos/keg.el/keg-mode.el...
$ keg build keg
Compiling /home/conao/dev/repos/keg.el/keg.el...
Compiling /home/conao/dev/repos/keg.el/keg-ansi.el...
Compiling /home/conao/dev/repos/keg.el/keg-cli.el...
$ keg build keg-mode
Compiling /home/conao/dev/repos/keg.el/keg-mode.el...
Since cort
is specified in dev-dependency
,
keg also install cort
in the .keg sandbox.
$ keg install
Install dependencies
Package: keg
Dependency: ((emacs 24.1) (cl-lib 0.6))
Package: keg-mode
Dependency: ((emacs 24.4))
Package: flycheck-keg
Dependency: ((emacs 24.3) (keg 0.1) (flycheck 0.1))
DevDependency: ((cort 0.0.1))
keg emacs [ARGS...]
Exec Emacs with given args, with the appropriate environment (see keg exec
).
keg exec [COMMAND] [ARGS...]
Exec command with given args, with the appropriate environment.
- Set
$EMACSLOADPATH
with$(keg load-path)
keg files [PACKAGE]
Show list of files to be packaged.
If package specified, show only list associated with it.
keg info [PACKAGE]
Show package info.
If package specified, show only info associated with it.
keg init
Create Keg
file in current directory.
keg install [PACKAGES...]
Install dependencies in .keg
sandbox.
If package specified, only install associated with it. You can also use environmental variables named KEGINSTALLPACKAGES
as PACKAGES
specification. It is also valid on the other subcommands which cause installation.
keg lint [PACKAGE]
Lint packages.
If package specified, only lint the specified package.
keg load-path
Show Emacs appropriate load-path
same format as PATH
.
This info is used keg exec
.
keg version
Show keg
and using Emacs
version info.
keg help
Show subcommand help.
keg debug
Show debug info.
keg run [SCRIPT]
Run script named SRCIPT
defined in Keg file.
See also script.
- keg-file-dir
- Get directory path which
Keg
located - keg-file-path
- Get file path to
Keg
file - keg-file-read
- Get parsed Sexp readed
Keg
file - keg-file-read-section
- Get parsed Sexp for specified section.
- keg-install-package
- Install package in
.keg
sandbox - keg-subcommands
- Get all
keg
subcommands list - keg-load-path
- Get
load-path
string same format as PATH - keg-process-environment
- Get appropriate environment value
- keg-mode
- Major-mode for
Keg
file
keg-ansi
is lightweight “face -> ANSI escape code” library.
There’re rejeep’s ansi library (and cask use it). But I rewrite whole code from scratch for more styles, more flexibility.
Here is constants. And these constants could used as DSL op code.
(defconst keg-ansi-codes
'((reset . 0)
(bold . 1)
(faint . 2)
(italic . 3)
(underline . 4)
(blink . 5)
(r-blink . 6) (rapid-blink . 6)
(invert . 7)
(conceal . 8)
(strike . 9)
;; ...
(black . 30)
(red . 31)
(green . 32)
(yellow . 33)
(blue . 34)
(magenta . 35)
(cyan . 36)
(white . 37)
;; ( . 38) ; 256 color / 24bit color
(default . 39)
(on-black . 40)
(red-bg . 41)
(green-bg . 42)
(yellow-bg . 43)
(blue-bg . 44)
(magenta-bg . 45)
(cyan-bg . 46)
(white-bg . 47)
;; ( . 48) ; 256 color / 24bit color
(default-bg . 49)
;; ...
(b-black . 90) (bright-black . 90)
(b-red . 91) (bright-red . 91)
(b-green . 92) (bright-green . 92)
(b-yellow . 93) (bright-yellow . 93)
(b-blue . 94) (bright-blue . 94)
(b-magenta . 95) (bright-magenta . 95)
(b-cyan . 96) (bright-cyan . 96)
(b-white . 97) (bright-white . 97)
;; ( . 98)
(b-default . 99) (bright-default . 97)
(b-black-bg . 100) (bright-black-bg . 100)
(b-red-bg . 101) (bright-red-bg . 101)
(b-green-bg . 102) (bright-green-bg . 102)
(b-yellow-bg . 103) (bright-yellow-bg . 103)
(b-blue-bg . 104) (bright-blue-bg . 104)
(b-magenta-bg . 105) (bright-magenta-bg . 105)
(b-cyan-bg . 106) (bright-cyan-bg . 106)
(b-white-bg . 107) (bright-white-bg . 107)
;; ( . 108)
(b-default-bg . 109) (bright-default-bg . 109))
"List of SGR (Select graphic rendition) codes.
See https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters")
(defconst keg-ansi-csis
'((up . "A")
(down . "B")
(forward . "C")
(backward . "D")
(ahead-down . "E") (beginning-of-line-down . "E")
(ahead-up . "F") (beginning-of-line-up . "F")
(column . "G") (move-at-column . "G")
(point . "H") (move-at-point . "H") ; require 2 arguments (x,y)
(clear . "J")
;; 0 (default): clear forward all
;; 1: clear behind all
;; 2: clear all
(clear-line . "K")
;; 0 (default): clear forward
;; 1: clear behind
;; 2: clear line
(scroll-next . "S")
(scroll-back . "T"))
"List of CSI (Control sequence introducer) codes.
See https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences")
(keg-ansi 'red "asdf") ; red foreground
;;=> "\e[38[31masdf\e[38[0m"
(keg-ansi 'bold
(keg-ansi 'red "asdf")) ; red foreground and bold style
;;=> "\e[38[1m\e[38[31masdf\e[38[0m\e[38[0m"
(keg-ansi-256 100 "asdf") ; number of 100 color
;;=> "\e[38[38;5;100masdf\e[38[0m"
(keg-ansi-rgb 50 80 100 "asdf") ; (RGB) = (50 80 100) color
;;=> "\e[38[38;2;50;80;100masdf\e[38[0m"
(keg-ansi-csi 'up) ; move cursor up
;;=> "\e[38[A"
(keg-ansi-csi 'down 5) ; move cursor down 5 times
;;=> "\e[38[5B"
(keg-ansi-csi 'point 10 5) ; move cursor (x,y) = (10,5)
;;=> "\e[38[10;5H"
And you can use with-keg-ansi
for using DSL.
(with-keg-ansi
(red "asdf"))
;;=> "\e[38[31masdf\e[38[0m"
(with-keg-ansi
(bold (red "asdf")))
;;=> "\e[38[1m\e[38[31masdf\e[38[0m\e[38[0m"
(with-keg-ansi
(256-color 100 "asdf"))
;;=> "\e[38[38;5;100masdf\e[38[0m"
(with-keg-ansi
(rgb-color 50 80 100 "asdf"))
;;=> "\e[38[38;2;50;80;100masdf\e[38[0m"
One-line example.
emacs --batch -l keg-ansi.el --eval="(princ (with-keg-ansi \"Keg-\" (cyan \"ansi\") \": \" (red \"ver\") (green \"sion\") \" \" (blink (green-bg (bold (yellow \"v0.0.1\")))) \"\\n\"))"
Complex, 256 colors example.
emacs --batch -l keg-ansi.el --eval="
(let ((fn (lambda (col i j offset)
(let ((code (+ (* col i) j offset)))
(princ (keg-ansi-256 code (format \"%02x \" code)))))))
(dotimes (j 16) (funcall fn 16 0 j 0)) (princ \"\\n\")
(dotimes (i 6) (dotimes (j 36) (funcall fn 36 i j 16)) (princ \"\\n\"))
(dotimes (j 24) (funcall fn 16 0 j 232)) (princ \"\\n\"))"
Complex, 24bit colors example.
emacs --batch -l keg-ansi.el --eval="
(dotimes (i 16)
(dotimes (j 32)
(princ (keg-ansi-rgb-bg (ash i 4) (ash j 3) 255 \" \")))
(princ \"\\n\"))"
All feedback and suggestions are welcome!
You can use github issues, but you can also use Slack if you want a more casual conversation.
We welcome PR!
- keg
cd ~/ hub clone conao3/keg .keg export PATH="$HOME/.keg/bin:$PATH"
Below operation flow is recommended.
make # Install git-hooks in local .git
git branch [feature-branch] # Create branch named [feature-branch]
git checkout [feature-branch] # Checkout branch named [feature-branch]
# <edit loop>
emacs keg.el # Edit something you want
make test # Test keg via multi version Emacs
git commit -am "brabra" # Commit (auto-run test before commit)
# </edit loop>
hub fork # Create fork at GitHub
git push [user] [feature-branch] # Push feature-branch to your fork
hub pull-request # Create pull-request
General Public License Version 3 (GPLv3) Copyright (c) Naoya Yamashita - https://conao3.com https://github.com/conao3/keg.el/blob/master/LICENSE
- Naoya Yamashita (conao3)