From 31c28807c932cb3de2923bd45d5e6b13732b4e94 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 13 Mar 2012 21:42:18 +0100 Subject: [PATCH] Added better JSON highlighting A JSON-specific lexer for Pygments by Norman Richards (@orb) has been added. It attempts to provide more interesting syntax highlighting which correctly distinguishes between attribute names and values. Closes #25. --- httpie/pretty.py | 78 +++++------------------------------------------- httpie/pygson.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 71 deletions(-) create mode 100644 httpie/pygson.py diff --git a/httpie/pretty.py b/httpie/pretty.py index 1a108d39..68e846e0 100644 --- a/httpie/pretty.py +++ b/httpie/pretty.py @@ -1,20 +1,19 @@ import os import json import pygments -import re from pygments import token from pygments.util import ClassNotFound from pygments.lexers import get_lexer_for_mimetype from pygments.formatters.terminal256 import Terminal256Formatter from pygments.formatters.terminal import TerminalFormatter -from pygments.lexer import include, RegexLexer, bygroups +from pygments.lexer import RegexLexer, bygroups from pygments.styles import get_style_by_name, STYLE_MAP from . import solarized +from .pygson import JSONLexer DEFAULT_STYLE = 'solarized' AVAILABLE_STYLES = [DEFAULT_STYLE] + STYLE_MAP.keys() -TYPE_JS = 'application/javascript' FORMATTER = (Terminal256Formatter if '256color' in os.environ.get('TERM', '') else TerminalFormatter) @@ -32,68 +31,6 @@ class HTTPLexer(RegexLexer): (r'(.*?:)(.+)', bygroups(token.Name, token.String)) ]} -# Stolen from https://github.com/orb/pygments-json -class JSONLexer(RegexLexer): - name = 'JSON Lexer' - aliases = ['json'] - filenames = ['*.json'] - mimetypes = [] - - - flags = re.DOTALL - tokens = { - 'whitespace': [ - (r'\s+', token.Text), - ], - - # represents a simple terminal value - 'simplevalue':[ - (r'(true|false|null)\b', token.Keyword.Constant), - (r'-?[0-9]+', token.Number.Integer), - (r'"(\\\\|\\"|[^"])*"', token.String.Double), - ], - - - # the right hand side of an object, after the attribute name - 'objectattribute': [ - include('value'), - (r':', token.Punctuation), - # comma terminates the attribute but expects more - (r',', token.Punctuation, '#pop'), - # a closing bracket terminates the entire object, so pop twice - (r'}', token.Punctuation, ('#pop', '#pop')), - ], - - # a json object - { attr, attr, ... } - 'objectvalue': [ - include('whitespace'), - (r'"(\\\\|\\"|[^"])*"', token.Name.Tag, 'objectattribute'), - (r'}', token.Punctuation, '#pop'), - ], - - # json array - [ value, value, ... } - 'arrayvalue': [ - include('whitespace'), - include('value'), - (r',', token.Punctuation), - (r']', token.Punctuation, '#pop'), - ], - - # a json value - either a simple value or a complex value (object or array) - 'value': [ - include('whitespace'), - include('simplevalue'), - (r'{', token.Punctuation, 'objectvalue'), - (r'\[', token.Punctuation, 'arrayvalue'), - ], - - - # the root of a json document would be a value - 'root': [ - include('value'), - ], - - } class PrettyHttp(object): @@ -108,20 +45,19 @@ class PrettyHttp(object): return pygments.highlight(content, HTTPLexer(), self.formatter) def body(self, content, content_type): + lexer = None content_type = content_type.split(';')[0] if 'json' in content_type: - content_type = TYPE_JS + lexer = JSONLexer() try: - # Indent JSON + # Indent the JSON data. content = json.dumps(json.loads(content), sort_keys=True, indent=4) - lexer = JSONLexer() except Exception: pass - else: + if not lexer: try: lexer = get_lexer_for_mimetype(content_type) except ClassNotFound: return content - content = pygments.highlight(content, lexer, self.formatter) - return content + return pygments.highlight(content, lexer, self.formatter) diff --git a/httpie/pygson.py b/httpie/pygson.py new file mode 100644 index 00000000..be0492b3 --- /dev/null +++ b/httpie/pygson.py @@ -0,0 +1,77 @@ +""" +JSON lexer by Norman Richards + +It's already been merged into Pygments but not released yet, +so we are temporarily bundling it with HTTPie. + +It can be removed once Pygments > 1.4 has been released. + +See for more details. + +""" +import re +from pygments import token +from pygments.lexer import RegexLexer, include + + +class JSONLexer(RegexLexer): + name = 'JSON Lexer' + aliases = ['json'] + filenames = ['*.json'] + mimetypes = [] + + + flags = re.DOTALL + tokens = { + 'whitespace': [ + (r'\s+', token.Text), + ], + + # represents a simple terminal value + 'simplevalue':[ + (r'(true|false|null)\b', token.Keyword.Constant), + (r'-?[0-9]+', token.Number.Integer), + (r'"(\\\\|\\"|[^"])*"', token.String.Double), + ], + + + # the right hand side of an object, after the attribute name + 'objectattribute': [ + include('value'), + (r':', token.Punctuation), + # comma terminates the attribute but expects more + (r',', token.Punctuation, '#pop'), + # a closing bracket terminates the entire object, so pop twice + (r'}', token.Punctuation, ('#pop', '#pop')), + ], + + # a json object - { attr, attr, ... } + 'objectvalue': [ + include('whitespace'), + (r'"(\\\\|\\"|[^"])*"', token.Name.Tag, 'objectattribute'), + (r'}', token.Punctuation, '#pop'), + ], + + # json array - [ value, value, ... } + 'arrayvalue': [ + include('whitespace'), + include('value'), + (r',', token.Punctuation), + (r']', token.Punctuation, '#pop'), + ], + + # a json value - either a simple value or a complex value (object or array) + 'value': [ + include('whitespace'), + include('simplevalue'), + (r'{', token.Punctuation, 'objectvalue'), + (r'\[', token.Punctuation, 'arrayvalue'), + ], + + + # the root of a json document would be a value + 'root': [ + include('value'), + ], + + }