/keg.el

Modern Elisp package development system

Primary LanguageEmacs LispGNU General Public License v3.0GPL-3.0

https://raw.githubusercontent.com/conao3/files/master/blob/headers/png/keg.el.png https://img.shields.io/github/license/conao3/keg.el.svg?style=flat-square https://img.shields.io/github/tag/conao3/keg.el.svg?style=flat-square https://github.com/conao3/keg.el/workflows/Main%20workflow/badge.svg https://img.shields.io/codacy/grade/62a36f4f04524d5e8c758440e8071c45.svg?logo=codacy&style=flat-square https://img.shields.io/badge/patreon-become%20a%20patron-orange.svg?logo=patreon&style=flat-square https://img.shields.io/badge/twitter-@conao__3-blue.svg?logo=twitter&style=flat-square https://img.shields.io/badge/chat-on_slack-blue.svg?logo=slack&style=flat-square

Table of Contents

Description

Modern Elisp package development system.

Keg is 100% Elisp project and it developed as alternative to Cask.

Install

git clone https://github.com/conao3/keg.el.git .keg
PATH=$HOME/.keg/bin:$PATH
(leaf keg :ensure t)
(leaf keg-mode :ensure t)

Usage

This repository includes keg executable, keg Elisp package, keg-mode Emacs major-mode.

And keg-setup for GitHub actions is available.

Keg file

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.

source

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.

package

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/recipe

package-args could accept alist and currently only recipe is valid.

It accepts the same S-expression as the MELPA recipe file.

dev-dependency

dev-dependency is not a package dependency but you need for package development like buttercup or ert.

(dev-dependency {package}...)

script

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!")))

Keg file Example

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 executable

emacs

keg emacs [ARGS...]

Exec Emacs with given args, with the appropriate environment (see keg exec).

exec

keg exec [COMMAND] [ARGS...]

Exec command with given args, with the appropriate environment.

files

keg files [PACKAGE]

Show list of files to be packaged.

If package specified, show only list associated with it.

info

keg info [PACKAGE]

Show package info.

If package specified, show only info associated with it.

init

keg init

Create Keg file in current directory.

install

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.

lint

keg lint [PACKAGE]

Lint packages.

If package specified, only lint the specified package.

load-path

keg load-path

Show Emacs appropriate load-path same format as PATH. This info is used keg exec.

version

keg version

Show keg and using Emacs version info.

help

keg help

Show subcommand help.

debug

keg debug

Show debug info.

run

keg run [SCRIPT]

Run script named SRCIPT defined in Keg file. See also script.

keg Elisp package

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 Emacs major mode

keg-mode
Major-mode for Keg file

keg-ansi library

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")

Examples of keg-ansi

low level API

(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"

with-keg-ansi macro

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"

Interactive examples

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\"))"

https://raw.githubusercontent.com/conao3/files/master/blob/keg.el/keg-ansi-simple.png

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\"))"

https://raw.githubusercontent.com/conao3/files/master/blob/keg.el/keg-ansi-complex.png

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\"))"

https://raw.githubusercontent.com/conao3/files/master/blob/keg.el/keg-ansi-hue.png

Customize

Information

Community

All feedback and suggestions are welcome!

You can use github issues, but you can also use Slack if you want a more casual conversation.

Contribution

We welcome PR!

Require tools for testing

  • keg
    cd ~/
    hub clone conao3/keg .keg
    export PATH="$HOME/.keg/bin:$PATH"
        

Running test

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

Migration

License

General Public License Version 3 (GPLv3)
Copyright (c) Naoya Yamashita - https://conao3.com
https://github.com/conao3/keg.el/blob/master/LICENSE

Author

Contributors