├── .gitignore ├── CHANGELOG.md ├── Makefile ├── README.md ├── UNLICENSE ├── project.clj └── src └── mvxcvi └── edn └── main.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /target 3 | /classes 4 | /checkouts 5 | /.lein-* 6 | /.nrepl-port 7 | /edn 8 | profiles.clj 9 | build.xml 10 | pom.xml 11 | pom.xml.asc 12 | *.jar 13 | *.class 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | All notable changes to this project will be documented in this file, which 5 | follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 6 | This project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | 9 | ## [Unreleased] 10 | 11 | ... 12 | 13 | ## [0.2.0] - 2019-03-22 14 | 15 | ### Added 16 | - Allow printer options to be customized using a user-level config file. 17 | 18 | ### Changed 19 | - Upgraded `mvxcvi/puget` to 1.1.1. 20 | 21 | ## 0.1.0 - 2018-11-29 22 | 23 | Initial release! 24 | 25 | [Unreleased]: https://github.com/greglook/edn-tool/compare/0.2.0...HEAD 26 | [0.2.0]: https://github.com/greglook/edn-tool/compare/0.1.0...0.2.0 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Build file for edn-tool 2 | 3 | default: package 4 | 5 | .PHONY: clean test uberjar package 6 | 7 | ifndef GRAAL_PATH 8 | $(error GRAAL_PATH is not set) 9 | endif 10 | 11 | uberjar_path := target/uberjar/edn.jar 12 | version := $(shell grep defproject project.clj | cut -d ' ' -f 3 | tr -d \") 13 | platform := $(shell uname -s | tr '[:upper:]' '[:lower:]') 14 | release_name := edn_$(version)_$(platform) 15 | 16 | clean: 17 | rm -rf target dist edn 18 | 19 | test: 20 | lein test 21 | 22 | $(uberjar_path): src/**/* 23 | lein uberjar 24 | 25 | uberjar: $(uberjar_path) 26 | 27 | edn: $(uberjar_path) 28 | $(GRAAL_PATH)/bin/native-image \ 29 | --report-unsupported-elements-at-runtime \ 30 | -J-Xms3G -J-Xmx3G \ 31 | --no-server \ 32 | -jar $< 33 | 34 | dist/$(release_name).tar.gz: edn 35 | @mkdir -p dist 36 | tar -cvzf $@ $^ 37 | 38 | package: dist/$(release_name).tar.gz 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EDN Tool 2 | ======== 3 | 4 | This project is a small command-line tool for parsing and pretty-printing EDN 5 | data. 6 | 7 | 8 | ## Installation 9 | 10 | Releases are published on the [GitHub project](https://github.com/greglook/edn-tool/releases). 11 | The native binaries are self-contained, so to install them simply place them on 12 | your path. 13 | 14 | 15 | ## Usage 16 | 17 | The simplest way to use the tool is to pipe EDN to it on STDIN, which will 18 | pretty-print each form to STDOUT. 19 | 20 | ``` 21 | $ echo "{:foo 123, :bar true}" | edn --width 10 22 | {:bar true, 23 | :foo 123} 24 | ``` 25 | 26 | 27 | ## Configuration 28 | 29 | Under the hood, this tool uses [Puget](https://github.com/greglook/puget) to 30 | pretty-print the output. The printer options may be customized by specifying a 31 | configuration file with `--config` or dropping one in the default location in 32 | your home directory. This should be an EDN file giving a map of printer options; 33 | for example, to customize the coloring of `nil` values and enable namespaced 34 | maps: 35 | 36 | ```clojure 37 | {:namespace-maps true 38 | :color-scheme {:nil [:blue]}} 39 | ``` 40 | 41 | 42 | ## License 43 | 44 | This is free and unencumbered software released into the public domain. 45 | See the UNLICENSE file for more information. 46 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject mvxcvi/edn-tool "0.2.0" 2 | :description "Command-line EDN printing tool." 3 | :url "https://github.com/greglook/edn-tool" 4 | :license {:name "Public Domain" 5 | :url "http://unlicense.org/"} 6 | 7 | :pedantic? :warn 8 | 9 | :dependencies 10 | [[org.clojure/clojure "1.9.0"] 11 | [org.clojure/tools.cli "0.4.1"] 12 | [mvxcvi/puget "1.1.1" :exclusions [org.clojure/clojure]]] 13 | 14 | :main mvxcvi.edn.main 15 | 16 | :profiles 17 | {:uberjar 18 | {:target-path "target/uberjar" 19 | :uberjar-name "edn.jar" 20 | :aot :all}}) 21 | -------------------------------------------------------------------------------- /src/mvxcvi/edn/main.clj: -------------------------------------------------------------------------------- 1 | (ns mvxcvi.edn.main 2 | "Main tool entry namespace." 3 | (:gen-class) 4 | (:require 5 | [clojure.edn :as edn] 6 | [clojure.java.io :as io] 7 | [clojure.string :as str] 8 | [clojure.tools.cli :as cli] 9 | [puget.printer :as puget]) 10 | (:import 11 | (java.io 12 | File 13 | PushbackReader 14 | Writer))) 15 | 16 | 17 | (def default-config 18 | {:width 120 19 | :print-color true 20 | :sort-keys 100}) 21 | 22 | 23 | (def cli-options 24 | "Command-line option specs for the tool." 25 | [["-i" "--input FILE" "Read input from the given file instead of STDIN"] 26 | ["-o" "--output FILE" "Write output to the given file instead of STDOUT"] 27 | [nil "--no-color" "Don't output in color"] 28 | ["-w" "--width SIZE" "Column at which to wrap print output" 29 | :parse-fn #(Integer/parseInt %)] 30 | ["-c" "--config FILE" "Path to configuration file to use" 31 | :default (str (or (System/getenv "XDG_CONFIG_HOME") 32 | (str (System/getenv "HOME") "/.config")) 33 | "/mvxcvi/edn-tool.edn")] 34 | ["-h" "--help" "Show help"]]) 35 | 36 | 37 | (defn- load-config 38 | "Read the tool configuration using the given options and return a printer 39 | configuration map." 40 | [options] 41 | (let [config-file (io/file (:config options))] 42 | (merge 43 | default-config 44 | (when (.exists config-file) 45 | (try 46 | (edn/read-string (slurp config-file)) 47 | (catch Exception ex 48 | (binding [*out* *err*] 49 | (printf "WARNING: failed to load configuration from %s: %s\n" 50 | (:config options) 51 | (.getMessage ex)) 52 | (flush)) 53 | nil))) 54 | (when-let [width (:width options)] 55 | {:width width}) 56 | (when (:no-color options) 57 | {:print-color false})))) 58 | 59 | 60 | (defn- read-print-loop 61 | "Read EDN from the input reader until the end of the stream is reached, 62 | printing it to the output writer. Closes the output stream at the end of the 63 | loop." 64 | [input printer ^Writer output] 65 | (let [sentinel (Object.)] 66 | (try 67 | (binding [*out* output] 68 | (loop [] 69 | (let [value (edn/read {:eof sentinel 70 | :default tagged-literal} 71 | input)] 72 | (when-not (identical? sentinel value) 73 | (puget/render-out printer value) 74 | (flush) 75 | (recur))))) 76 | (finally 77 | (when-not (identical? output *out*) 78 | (.close output)))))) 79 | 80 | 81 | (defn -main 82 | "Main entry point for the EDN tool." 83 | [& args] 84 | (let [{:keys [options arguments summary errors]} (cli/parse-opts args cli-options)] 85 | (when errors 86 | (binding [*out* *err*] 87 | (doseq [err errors] 88 | (println errors))) 89 | (System/exit 1)) 90 | (when (:help options) 91 | (println "Usage: edn [options] < input.edn > output.edn") 92 | (newline) 93 | (println summary) 94 | (flush) 95 | (System/exit 0)) 96 | (let [printer (puget/pretty-printer (load-config options)) 97 | input (if-let [path (:input options)] 98 | (PushbackReader. (io/reader (io/file path))) 99 | *in*) 100 | output (if-let [path (:output options)] 101 | (io/writer (io/file path)) 102 | *out*)] 103 | (read-print-loop input printer output)))) 104 | --------------------------------------------------------------------------------