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.
This commit is contained in:
Jakub Roztocil 2012-03-13 21:42:18 +01:00
parent 78e20c6e85
commit 31c28807c9
2 changed files with 84 additions and 71 deletions

View File

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

77
httpie/pygson.py Normal file
View File

@ -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 <https://github.com/jkbr/httpie/pull/25> 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'),
],
}