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
|
url: str
|
||||||
headers: Dict[str, str] # Key-value pairs
|
headers: Dict[str, str] # Key-value pairs
|
||||||
body: str # Raw text body
|
body: str # Raw text body
|
||||||
|
syntax: str = "RAW" # Syntax highlighting: "RAW", "JSON", or "XML"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
"""Convert to dictionary for JSON serialization."""
|
"""Convert to dictionary for JSON serialization."""
|
||||||
@ -36,6 +37,9 @@ class HttpRequest:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data):
|
def from_dict(cls, data):
|
||||||
"""Create instance from dictionary."""
|
"""Create instance from dictionary."""
|
||||||
|
# Provide default for syntax field for backward compatibility
|
||||||
|
if 'syntax' not in data:
|
||||||
|
data = {**data, 'syntax': 'RAW'}
|
||||||
return cls(**data)
|
return cls(**data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
133
src/window.py
133
src/window.py
@ -126,11 +126,41 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
"""Handle system theme changes."""
|
"""Handle system theme changes."""
|
||||||
is_dark = style_manager.get_dark()
|
is_dark = style_manager.get_dark()
|
||||||
style_scheme_manager = GtkSource.StyleSchemeManager.get_default()
|
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)
|
scheme = style_scheme_manager.get_scheme(scheme_name)
|
||||||
|
|
||||||
if scheme:
|
if scheme:
|
||||||
self.response_body_sourceview.get_buffer().set_style_scheme(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):
|
def _create_actions(self):
|
||||||
"""Create window-level actions."""
|
"""Create window-level actions."""
|
||||||
@ -181,18 +211,70 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
self.request_stack.add_titled(headers_box, "headers", "Headers")
|
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 = Gtk.ScrolledWindow()
|
||||||
body_scroll.set_vexpand(True)
|
body_scroll.set_vexpand(True)
|
||||||
self.body_textview = Gtk.TextView()
|
self.body_sourceview = GtkSource.View()
|
||||||
self.body_textview.set_monospace(True)
|
self.body_sourceview.set_editable(True)
|
||||||
self.body_textview.set_left_margin(12)
|
self.body_sourceview.set_show_line_numbers(True)
|
||||||
self.body_textview.set_right_margin(12)
|
self.body_sourceview.set_highlight_current_line(True)
|
||||||
self.body_textview.set_top_margin(12)
|
self.body_sourceview.set_left_margin(12)
|
||||||
self.body_textview.set_bottom_margin(12)
|
self.body_sourceview.set_right_margin(12)
|
||||||
body_scroll.set_child(self.body_textview)
|
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):
|
def _setup_response_tabs(self):
|
||||||
"""Create response tabs programmatically."""
|
"""Create response tabs programmatically."""
|
||||||
@ -247,7 +329,7 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
textview {
|
textview {
|
||||||
font-family: "Source Code Pro";
|
font-family: "Source Code Pro";
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
line-height: 1,2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
self.response_body_sourceview.get_style_context().add_provider(
|
self.response_body_sourceview.get_style_context().add_provider(
|
||||||
@ -334,10 +416,15 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
child = child.get_next_sibling()
|
child = child.get_next_sibling()
|
||||||
|
|
||||||
# Get body
|
# 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)
|
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):
|
def _display_response(self, response):
|
||||||
"""Display response in UI."""
|
"""Display response in UI."""
|
||||||
@ -522,9 +609,17 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
self._add_header_row()
|
self._add_header_row()
|
||||||
|
|
||||||
# Set body
|
# Set body
|
||||||
buffer = self.body_textview.get_buffer()
|
buffer = self.body_sourceview.get_buffer()
|
||||||
buffer.set_text(request.body)
|
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
|
# Switch to headers tab
|
||||||
self.request_stack.set_visible_child_name("headers")
|
self.request_stack.set_visible_child_name("headers")
|
||||||
|
|
||||||
@ -767,9 +862,17 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
self._add_header_row()
|
self._add_header_row()
|
||||||
|
|
||||||
# Set body
|
# Set body
|
||||||
buffer = self.body_textview.get_buffer()
|
buffer = self.body_sourceview.get_buffer()
|
||||||
buffer.set_text(req.body)
|
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
|
# Switch to headers tab
|
||||||
self.request_stack.set_visible_child_name("headers")
|
self.request_stack.set_visible_child_name("headers")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user