Add visual indicators for undefined variables

This commit is contained in:
Pavel Baksy 2025-12-30 13:10:26 +01:00
parent 89f50d1304
commit 710997757e

View File

@ -41,6 +41,8 @@ class RequestTabWidget(Gtk.Box):
self.selected_environment_id = selected_environment_id self.selected_environment_id = selected_environment_id
self.project_manager = None # Will be injected from window self.project_manager = None # Will be injected from window
self.environment_dropdown = None # Will be created if project_id is set self.environment_dropdown = None # Will be created if project_id is set
self.undefined_variables = set() # Track undefined variables for visual feedback
self._update_indicators_timeout_id = None # Debounce timer for indicator updates
# Build the UI # Build the UI
self._build_ui() self._build_ui()
@ -374,6 +376,11 @@ class RequestTabWidget(Gtk.Box):
row.set_header(key, value) row.set_header(key, value)
row.connect('remove-requested', self._on_header_remove) row.connect('remove-requested', self._on_header_remove)
row.connect('changed', self._on_request_changed) row.connect('changed', self._on_request_changed)
# Connect to variable indicator updates (debounced)
if self.project_id:
row.connect('changed', lambda r: self._schedule_indicator_update())
self.headers_listbox.append(row) self.headers_listbox.append(row)
if key or value: if key or value:
@ -395,6 +402,11 @@ class RequestTabWidget(Gtk.Box):
body_buffer = self.body_sourceview.get_buffer() body_buffer = self.body_sourceview.get_buffer()
body_buffer.connect("changed", self._on_request_changed) body_buffer.connect("changed", self._on_request_changed)
# Setup variable indicator updates (debounced)
if self.project_id:
self.url_entry.connect("changed", lambda w: self._schedule_indicator_update())
body_buffer.connect("changed", lambda b: self._schedule_indicator_update())
def _on_request_changed(self, widget, *args): def _on_request_changed(self, widget, *args):
"""Mark this tab as modified.""" """Mark this tab as modified."""
if not self.original_request: if not self.original_request:
@ -644,6 +656,9 @@ class RequestTabWidget(Gtk.Box):
else: else:
self.environment_dropdown.set_selected(0) # Default to "None" self.environment_dropdown.set_selected(0) # Default to "None"
# Update indicators after environment is set
self._update_variable_indicators()
def _on_environment_changed(self, dropdown, _param): def _on_environment_changed(self, dropdown, _param):
"""Handle environment selection change.""" """Handle environment selection change."""
if not hasattr(self, 'environment_ids'): if not hasattr(self, 'environment_ids'):
@ -652,6 +667,8 @@ class RequestTabWidget(Gtk.Box):
selected_index = dropdown.get_selected() selected_index = dropdown.get_selected()
if selected_index < len(self.environment_ids): if selected_index < len(self.environment_ids):
self.selected_environment_id = self.environment_ids[selected_index] self.selected_environment_id = self.environment_ids[selected_index]
# Update visual indicators when environment changes
self._update_variable_indicators()
def get_selected_environment(self): def get_selected_environment(self):
"""Get the currently selected environment object.""" """Get the currently selected environment object."""
@ -675,3 +692,110 @@ class RequestTabWidget(Gtk.Box):
return env return env
return None return None
def _detect_undefined_variables(self):
"""Detect undefined variables in the current request. Returns set of undefined variable names."""
# Only detect if environment is selected
env = self.get_selected_environment()
if not env:
return set()
# Get current request from UI
request = self.get_request()
# Use VariableSubstitution to detect undefined variables
from .variable_substitution import VariableSubstitution
_, undefined = VariableSubstitution.substitute_request(request, env)
return undefined
def _schedule_indicator_update(self):
"""Schedule an indicator update with debouncing."""
# Cancel existing timeout
if self._update_indicators_timeout_id:
GLib.source_remove(self._update_indicators_timeout_id)
# Schedule new update after 500ms
self._update_indicators_timeout_id = GLib.timeout_add(500, self._update_variable_indicators_timeout)
def _update_variable_indicators_timeout(self):
"""Timeout callback for updating indicators."""
self._update_variable_indicators()
self._update_indicators_timeout_id = None
return False # Don't repeat
def _update_variable_indicators(self):
"""Update visual indicators for undefined variables."""
# Detect undefined variables
self.undefined_variables = self._detect_undefined_variables()
# Update URL entry
self._update_url_indicator()
# Update headers
self._update_header_indicators()
# Update body
self._update_body_indicators()
def _update_url_indicator(self):
"""Update warning indicator on URL entry."""
from .variable_substitution import VariableSubstitution
url_text = self.url_entry.get_text()
url_vars = set(VariableSubstitution.find_variables(url_text))
undefined_in_url = url_vars & self.undefined_variables
if undefined_in_url:
self.url_entry.add_css_class("warning")
tooltip = "Undefined variables: " + ", ".join(sorted(undefined_in_url))
self.url_entry.set_tooltip_text(tooltip)
else:
self.url_entry.remove_css_class("warning")
self.url_entry.set_tooltip_text("")
def _update_header_indicators(self):
"""Update warning indicators on header rows."""
from .variable_substitution import VariableSubstitution
# Iterate through all header rows
child = self.headers_listbox.get_first_child()
while child:
if hasattr(child, 'key_entry') and hasattr(child, 'value_entry'):
# Check key
key_text = child.key_entry.get_text()
key_vars = set(VariableSubstitution.find_variables(key_text))
undefined_in_key = key_vars & self.undefined_variables
if undefined_in_key:
child.key_entry.add_css_class("warning")
else:
child.key_entry.remove_css_class("warning")
# Check value
value_text = child.value_entry.get_text()
value_vars = set(VariableSubstitution.find_variables(value_text))
undefined_in_value = value_vars & self.undefined_variables
if undefined_in_value:
child.value_entry.add_css_class("warning")
else:
child.value_entry.remove_css_class("warning")
child = child.get_next_sibling()
def _update_body_indicators(self):
"""Update warning indicators in body text."""
# For body, we use a simpler approach: just set tooltip if there are undefined vars
from .variable_substitution import VariableSubstitution
buffer = self.body_sourceview.get_buffer()
body_text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
body_vars = set(VariableSubstitution.find_variables(body_text))
undefined_in_body = body_vars & self.undefined_variables
if undefined_in_body:
tooltip = "Undefined variables: " + ", ".join(sorted(undefined_in_body))
self.body_sourceview.set_tooltip_text(tooltip)
else:
self.body_sourceview.set_tooltip_text("")