Skip to content

Instantly share code, notes, and snippets.

@samizdatco
Last active June 8, 2020 18:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samizdatco/fcf12010013877d2c99956e5977971c7 to your computer and use it in GitHub Desktop.
Save samizdatco/fcf12010013877d2c99956e5977971c7 to your computer and use it in GitHub Desktop.
#!/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