-
-
Save samizdatco/fcf12010013877d2c99956e5977971c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
""" | |
pbj | |
Pretty-print whatever JSON is currently in the pasteboard and view it in your pager of choice | |
USAGE | |
pbj [-c] [-m] | |
If the pasteboard contains a JSON object or a URL pointing to a JSON resource it will be formatted | |
and displayed in a pager. | |
pbj <FILE> [-c] [-m] | |
If a FILE is provided (as a local path or url), it will be read in rather than using the contents | |
of the pasteboard. | |
<cmd> | pbj [-c] [-m] | |
You can also pipe JSON output from other commands to pbj. | |
OPTIONS | |
-c copy the reformatted JSON to the pasteboard rather than displaying it | |
-m minify the JSON to a single line rather than pretty-printing it | |
ENVIRONMENT VARIABLES | |
PBJ_COLORS | |
If defined, pbj will use vim's 'less' emulation mode and display JSON using the color-scheme specified. | |
The default scheme names you can choose from include: | |
blue delek evening morning peachpuff slate | |
darkblue desert industry murphy ron torte | |
default elflord koehler pablo shine zellner | |
PBJ_PAGER | |
If PBJ_COLORS is not defined, you can use PBJ_PAGER to specify which command pbj will use to display JSON. | |
For instance, the following is equivalent to setting PBJ_COLORS to 'slate': | |
export PBJ_PAGER="vim --cmd 'let no_plugin_maps=1' -c 'runtime! macros/less.vim|set syntax=json|set ic|colorscheme slate' -" | |
PAGER | |
If neither PBJ_COLORS nor PBJ_PAGER is not defined, pbj will use the command in your PAGER environment | |
variable to display the JSON data | |
--- | |
Created by Christian Swinehart on 2020-05-27. | |
Copyright (c) 2020 Samizdat Drafting Co. All rights reserved. | |
""" | |
from __future__ import with_statement, division | |
import re | |
import os | |
import json | |
from sys import argv, stdin, stdout, exit | |
from urllib2 import urlopen | |
from subprocess import check_output, Popen, PIPE | |
from collections import OrderedDict as odict | |
VIM_CMD = "vim --cmd 'let no_plugin_maps=1' -c 'runtime! macros/less.vim|set syntax=json|set ic|colorscheme %s' -" | |
getenv = lambda *args: os.environ.get(*args) | |
def main(): | |
args = argv[1:] | |
opts = [s for s in args if s.startswith('-')] | |
fnames = [s for s in args if s not in opts] | |
# short circuit on printing documentation | |
if '-h' in opts or '--help' in opts: | |
print __doc__.split('---')[0] | |
exit(0) | |
# check options for indentation depth | |
indent = None if '-m' in opts else 2 | |
# get the JSON payload | |
try: | |
# read from file/url if one was passed as an argument | |
fn = fnames[0] | |
rsrc = urlopen(fn) if fn.startswith('http') else open(fn) | |
blob = rsrc.read() | |
except IndexError: | |
# otherwise read from pipe or pasteboard | |
if not stdin.isatty(): | |
blob = stdin.read() | |
else: | |
blob = check_output(['pbpaste']) | |
# if pasteboard contains a url rather than a JSON blob, fetch it | |
if re.match(r'https?://', blob): | |
print 'Fetching', blob | |
blob = urlopen(blob).read() | |
# reformat the JSON | |
try: | |
obj = json.loads(blob, object_pairs_hook=odict) | |
text = json.dumps(obj, indent=indent, separators=(',', ': '), ensure_ascii=False).encode('utf-8') | |
except ValueError, e: | |
if fnames: | |
print '%s:'%fnames[0], | |
print e | |
exit(1) | |
# pick the output channel (stdout, pager, or pasteboard) | |
if not stdout.isatty(): | |
stdout.write(text) | |
exit(0) | |
elif '-c' in opts: | |
pager = 'pbcopy' | |
print "Pasteboard JSON updated" | |
else: | |
scheme = getenv('PBJ_COLORS') | |
pager = VIM_CMD%scheme if scheme else getenv('PBJ_PAGER', getenv('PAGER', 'less')) | |
# output the text and wait for the process to exit | |
proc = Popen(pager, shell=True, stdin=PIPE) | |
try: | |
proc.stdin.write(text) | |
proc.stdin.write('\n') | |
proc.stdin.close() | |
except KeyboardInterrupt: | |
pass # let the pager catch ctrl-c | |
except IOError: | |
pass # ignore broken pipes caused by quitting the pager program. | |
while True: | |
try: | |
proc.wait() | |
break | |
except KeyboardInterrupt: | |
# Ignore ctl-c like the pager itself does. Otherwise the pager is | |
# left running and the terminal is in raw mode and unusable. | |
pass | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment