Add syntax highlighting and formatting for request/response bodies
- Add automatic JSON and XML formatting for response bodies - Replace TextView with GtkSourceView for syntax highlighting - Add syntax selector dropdown (RAW/JSON/XML) for request body - Use Source Code Pro font (12pt) for better readability - Integrate with GNOME theme (Adwaita light/dark) - Add line numbers and current line highlighting - Persist syntax selection when saving/loading requests - Maintain backward compatibility with existing saved requests
This commit is contained in:
parent
9806333aa6
commit
c76d574832
@ -28,6 +28,7 @@ class HttpRequest:
|
||||
url: str
|
||||
headers: Dict[str, str] # Key-value pairs
|
||||
body: str # Raw text body
|
||||
syntax: str = "RAW" # Syntax highlighting: "RAW", "JSON", or "XML"
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary for JSON serialization."""
|
||||
@ -36,6 +37,9 @@ class HttpRequest:
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
"""Create instance from dictionary."""
|
||||
# Provide default for syntax field for backward compatibility
|
||||
if 'syntax' not in data:
|
||||
data = {**data, 'syntax': 'RAW'}
|
||||
return cls(**data)
|
||||
|
||||
|
||||
|
||||
133
src/window.py
133
src/window.py
@ -126,11 +126,41 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
"""Handle system theme changes."""
|
||||
is_dark = style_manager.get_dark()
|
||||
style_scheme_manager = GtkSource.StyleSchemeManager.get_default()
|
||||
scheme_name = 'classic-dark' if is_dark else 'classic'
|
||||
scheme_name = 'Adwaita-dark' if is_dark else 'Adwaita'
|
||||
scheme = style_scheme_manager.get_scheme(scheme_name)
|
||||
|
||||
if scheme:
|
||||
self.response_body_sourceview.get_buffer().set_style_scheme(scheme)
|
||||
# Also update request body theme
|
||||
self.body_sourceview.get_buffer().set_style_scheme(scheme)
|
||||
|
||||
def _setup_request_body_theme(self):
|
||||
"""Set up GtkSourceView theme for request body."""
|
||||
style_manager = Adw.StyleManager.get_default()
|
||||
is_dark = style_manager.get_dark()
|
||||
|
||||
style_scheme_manager = GtkSource.StyleSchemeManager.get_default()
|
||||
scheme_name = 'Adwaita-dark' if is_dark else 'Adwaita'
|
||||
scheme = style_scheme_manager.get_scheme(scheme_name)
|
||||
|
||||
if scheme:
|
||||
self.body_sourceview.get_buffer().set_style_scheme(scheme)
|
||||
|
||||
def _on_request_body_language_changed(self, dropdown, param):
|
||||
"""Handle request body language selection change."""
|
||||
selected = dropdown.get_selected()
|
||||
language_manager = GtkSource.LanguageManager.get_default()
|
||||
|
||||
buffer = self.body_sourceview.get_buffer()
|
||||
|
||||
if selected == 0: # RAW
|
||||
buffer.set_language(None)
|
||||
elif selected == 1: # JSON
|
||||
language = language_manager.get_language('json')
|
||||
buffer.set_language(language)
|
||||
elif selected == 2: # XML
|
||||
language = language_manager.get_language('xml')
|
||||
buffer.set_language(language)
|
||||
|
||||
def _create_actions(self):
|
||||
"""Create window-level actions."""
|
||||
@ -181,18 +211,70 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
|
||||
self.request_stack.add_titled(headers_box, "headers", "Headers")
|
||||
|
||||
# Body tab
|
||||
# Body tab with syntax highlighting
|
||||
body_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
||||
|
||||
# SourceView for request body
|
||||
body_scroll = Gtk.ScrolledWindow()
|
||||
body_scroll.set_vexpand(True)
|
||||
self.body_textview = Gtk.TextView()
|
||||
self.body_textview.set_monospace(True)
|
||||
self.body_textview.set_left_margin(12)
|
||||
self.body_textview.set_right_margin(12)
|
||||
self.body_textview.set_top_margin(12)
|
||||
self.body_textview.set_bottom_margin(12)
|
||||
body_scroll.set_child(self.body_textview)
|
||||
self.body_sourceview = GtkSource.View()
|
||||
self.body_sourceview.set_editable(True)
|
||||
self.body_sourceview.set_show_line_numbers(True)
|
||||
self.body_sourceview.set_highlight_current_line(True)
|
||||
self.body_sourceview.set_left_margin(12)
|
||||
self.body_sourceview.set_right_margin(12)
|
||||
self.body_sourceview.set_top_margin(12)
|
||||
self.body_sourceview.set_bottom_margin(12)
|
||||
|
||||
self.request_stack.add_titled(body_scroll, "body", "Body")
|
||||
# Apply same font styling as response body
|
||||
css_provider = Gtk.CssProvider()
|
||||
css_provider.load_from_data(b"""
|
||||
textview {
|
||||
font-family: "Source Code Pro";
|
||||
font-size: 12pt;
|
||||
line-height: 1.2;
|
||||
}
|
||||
""")
|
||||
self.body_sourceview.get_style_context().add_provider(
|
||||
css_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
)
|
||||
|
||||
# Set up theme for request body
|
||||
self._setup_request_body_theme()
|
||||
|
||||
body_scroll.set_child(self.body_sourceview)
|
||||
body_box.append(body_scroll)
|
||||
|
||||
# Bottom toolbar with language selector
|
||||
toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||
toolbar.set_margin_start(12)
|
||||
toolbar.set_margin_end(12)
|
||||
toolbar.set_margin_top(6)
|
||||
toolbar.set_margin_bottom(6)
|
||||
|
||||
# Spacer to push dropdown to the right
|
||||
spacer = Gtk.Box()
|
||||
spacer.set_hexpand(True)
|
||||
toolbar.append(spacer)
|
||||
|
||||
# Language selector label and dropdown
|
||||
lang_label = Gtk.Label(label="Syntax:")
|
||||
toolbar.append(lang_label)
|
||||
|
||||
lang_list = Gtk.StringList()
|
||||
lang_list.append("RAW")
|
||||
lang_list.append("JSON")
|
||||
lang_list.append("XML")
|
||||
|
||||
self.body_language_dropdown = Gtk.DropDown(model=lang_list)
|
||||
self.body_language_dropdown.set_selected(0) # Default to RAW
|
||||
self.body_language_dropdown.connect("notify::selected", self._on_request_body_language_changed)
|
||||
toolbar.append(self.body_language_dropdown)
|
||||
|
||||
body_box.append(toolbar)
|
||||
|
||||
self.request_stack.add_titled(body_box, "body", "Body")
|
||||
|
||||
def _setup_response_tabs(self):
|
||||
"""Create response tabs programmatically."""
|
||||
@ -247,7 +329,7 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
textview {
|
||||
font-family: "Source Code Pro";
|
||||
font-size: 12pt;
|
||||
line-height: 1,2;
|
||||
line-height: 1.2;
|
||||
}
|
||||
""")
|
||||
self.response_body_sourceview.get_style_context().add_provider(
|
||||
@ -334,10 +416,15 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
child = child.get_next_sibling()
|
||||
|
||||
# Get body
|
||||
buffer = self.body_textview.get_buffer()
|
||||
buffer = self.body_sourceview.get_buffer()
|
||||
body = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
|
||||
|
||||
return HttpRequest(method=method, url=url, headers=headers, body=body)
|
||||
# Get syntax selection
|
||||
syntax_index = self.body_language_dropdown.get_selected()
|
||||
syntax_options = ["RAW", "JSON", "XML"]
|
||||
syntax = syntax_options[syntax_index]
|
||||
|
||||
return HttpRequest(method=method, url=url, headers=headers, body=body, syntax=syntax)
|
||||
|
||||
def _display_response(self, response):
|
||||
"""Display response in UI."""
|
||||
@ -522,9 +609,17 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
self._add_header_row()
|
||||
|
||||
# Set body
|
||||
buffer = self.body_textview.get_buffer()
|
||||
buffer = self.body_sourceview.get_buffer()
|
||||
buffer.set_text(request.body)
|
||||
|
||||
# Restore syntax selection
|
||||
syntax_options = ["RAW", "JSON", "XML"]
|
||||
syntax = getattr(request, 'syntax', 'RAW') # Default to RAW for old requests
|
||||
if syntax in syntax_options:
|
||||
self.body_language_dropdown.set_selected(syntax_options.index(syntax))
|
||||
else:
|
||||
self.body_language_dropdown.set_selected(0) # Default to RAW
|
||||
|
||||
# Switch to headers tab
|
||||
self.request_stack.set_visible_child_name("headers")
|
||||
|
||||
@ -767,9 +862,17 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
self._add_header_row()
|
||||
|
||||
# Set body
|
||||
buffer = self.body_textview.get_buffer()
|
||||
buffer = self.body_sourceview.get_buffer()
|
||||
buffer.set_text(req.body)
|
||||
|
||||
# Restore syntax selection
|
||||
syntax_options = ["RAW", "JSON", "XML"]
|
||||
syntax = getattr(req, 'syntax', 'RAW') # Default to RAW for old requests
|
||||
if syntax in syntax_options:
|
||||
self.body_language_dropdown.set_selected(syntax_options.index(syntax))
|
||||
else:
|
||||
self.body_language_dropdown.set_selected(0) # Default to RAW
|
||||
|
||||
# Switch to headers tab
|
||||
self.request_stack.set_visible_child_name("headers")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user