Improved highlighting of HTTP headers.

Closes #60.
This commit is contained in:
Jakub Roztocil 2012-07-20 21:54:41 +02:00
parent ab7915d9e0
commit 16f23d8147
2 changed files with 80 additions and 20 deletions

View File

@ -280,6 +280,7 @@ Changelog
--------- ---------
* `0.2.6dev <https://github.com/jkbr/httpie/compare/0.2.5...master>`_ * `0.2.6dev <https://github.com/jkbr/httpie/compare/0.2.5...master>`_
* Improved highlighing of HTTP headers.
* Added query string parameters (param=:value). * Added query string parameters (param=:value).
* Added support for terminal colors under Windows. * Added support for terminal colors under Windows.
* `0.2.5 <https://github.com/jkbr/httpie/compare/0.2.2...0.2.5>`_ (2012-07-17) * `0.2.5 <https://github.com/jkbr/httpie/compare/0.2.2...0.2.5>`_ (2012-07-17)

View File

@ -1,52 +1,110 @@
"""
Colorizing of HTTP messages and content processing.
"""
import os import os
import re import re
import json import json
import pygments import pygments
from pygments import token, lexer
from pygments.util import ClassNotFound
from pygments.styles import get_style_by_name, STYLE_MAP from pygments.styles import get_style_by_name, STYLE_MAP
from pygments.lexers import get_lexer_for_mimetype, HttpLexer from pygments.lexers import get_lexer_for_mimetype
from pygments.formatters.terminal256 import Terminal256Formatter
from pygments.formatters.terminal import TerminalFormatter from pygments.formatters.terminal import TerminalFormatter
from pygments.formatters.terminal256 import Terminal256Formatter
from pygments.util import ClassNotFound
from requests.compat import is_windows from requests.compat import is_windows
from . import solarized from . import solarized
DEFAULT_STYLE = 'solarized'
AVAILABLE_STYLES = [DEFAULT_STYLE] + list(STYLE_MAP.keys())
if is_windows: if is_windows:
import colorama import colorama
colorama.init() colorama.init()
# 256 looks better on Windows # 256 looks better on Windows
FORMATTER = Terminal256Formatter formatter_class = Terminal256Formatter
else: else:
FORMATTER = ( formatter_class = (
Terminal256Formatter Terminal256Formatter
if '256color' in os.environ.get('TERM', '') if '256color' in os.environ.get('TERM', '')
else TerminalFormatter else TerminalFormatter
) )
DEFAULT_STYLE = 'solarized' class HTTPLexer(lexer.RegexLexer):
AVAILABLE_STYLES = [DEFAULT_STYLE] + list(STYLE_MAP.keys()) """
Simplified HTTP lexer for Pygments.
application_content_type_re = re.compile(r'application/(.+\+)(json|xml)$') It only operates on headers and provides a stronger contrast between
their names and values than the original one bundled with Pygments
(`pygments.lexers.text import HttpLexer`), especially when
Solarized color scheme is used.
"""
name = 'HTTP'
aliases = ['http']
filenames = ['*.http']
tokens = {
'root': [
# Request-Line
(r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)',
lexer.bygroups(
token.Name.Function,
token.Text,
token.Name.Namespace,
token.Text,
token.Keyword.Reserved,
token.Operator,
token.Number
)),
# Response Status-Line
(r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)',
lexer.bygroups(
token.Keyword.Reserved, # 'HTTP'
token.Operator, # '/'
token.Number, # Version
token.Text,
token.Number, # Status code
token.Text,
token.Name.Exception, # Reason
)),
# Header
(r'(.*?)( *)(:)( *)(.+)', lexer.bygroups(
token.Name.Attribute, # Name
token.Text,
token.Operator, # Colon
token.Text,
token.String # Value
))
]}
class PrettyHttp(object): class PrettyHttp(object):
"""HTTP headers & body prettyfier."""
def __init__(self, style_name): def __init__(self, style_name):
if style_name == 'solarized': try:
style = solarized.SolarizedStyle
else:
style = get_style_by_name(style_name) style = get_style_by_name(style_name)
self.formatter = FORMATTER(style=style) except ClassNotFound:
style = solarized.SolarizedStyle
self.formatter = formatter_class(style=style)
def headers(self, content): def headers(self, content):
return pygments.highlight(content, HttpLexer(), self.formatter) """Pygmentize HTTP headers."""
return pygments.highlight(content, HTTPLexer(), self.formatter)
def body(self, content, content_type): def body(self, content, content_type):
"""Pygmentize `content` based on `content_type`."""
content_type = content_type.split(';')[0] content_type = content_type.split(';')[0]
application_match = re.match(application_content_type_re,
content_type) application_match = re.match(
r'application/(.+\+)(json|xml)$',
content_type
)
if application_match: if application_match:
# Strip vendor and extensions from Content-Type # Strip vendor and extensions from Content-Type
vendor, extension = application_match.groups() vendor, extension = application_match.groups()
@ -57,13 +115,14 @@ class PrettyHttp(object):
except ClassNotFound: except ClassNotFound:
return content return content
if content_type == "application/json": if content_type == 'application/json':
try: try:
# Indent and sort the JSON data. # Indent and sort the JSON data.
content = json.dumps(json.loads(content), content = json.dumps(json.loads(content),
sort_keys=True, indent=4, sort_keys=True, indent=4,
ensure_ascii=False) ensure_ascii=False)
except: except ValueError:
# Invalid JSON - we don't care.
pass pass
return pygments.highlight(content, lexer, self.formatter) return pygments.highlight(content, lexer, self.formatter)