Commit 144225fc authored by Torsten Schönfeld's avatar Torsten Schönfeld

perli11ndoc: add support for links in the results display

Also, add a delay to the search function to make it stutter less.
parent 390b0f80
...@@ -381,7 +381,7 @@ sub format_namespace { ...@@ -381,7 +381,7 @@ sub format_namespace {
next unless @$entries; next unless @$entries;
$text .= "$heading\n\n"; $text .= "$heading\n\n";
foreach my $entry (@$entries) { foreach my $entry (@$entries) {
$text .= ' ' . $entry->{name} . "\n"; $text .= sprintf " [%s](%s)\n", $entry->{name}, $entry->{path};
} }
$text .= "\n"; $text .= "\n";
} }
...@@ -832,9 +832,10 @@ sub format_sub_constructors { ...@@ -832,9 +832,10 @@ sub format_sub_constructors {
$text .= "\nCONSTRUCTORS\n\n"; $text .= "\nCONSTRUCTORS\n\n";
foreach my $ctor ($ctor_list->get_nodelist) { foreach my $ctor ($ctor_list->get_nodelist) {
my $name = $self->find_attribute ($ctor, 'name'); my $name = $self->find_attribute ($ctor, 'name');
my $path = $ctor->nodePath;
my $flags = $self->format_callable_flags ($ctor, my $flags = $self->format_callable_flags ($ctor,
qw/introspectable version/); qw/introspectable version/);
$text .= " • $name$flags\n"; $text .= " • [$name]($path)$flags\n";
} }
} }
return $text; return $text;
...@@ -848,10 +849,11 @@ sub format_sub_fields { ...@@ -848,10 +849,11 @@ sub format_sub_fields {
$text .= "\nFIELDS\n\n"; $text .= "\nFIELDS\n\n";
foreach my $field ($field_list->get_nodelist) { foreach my $field ($field_list->get_nodelist) {
my $name = $self->find_attribute ($field, 'name'); my $name = $self->find_attribute ($field, 'name');
my $path = $field->nodePath;
my $type_name = $self->find_type_name ($field); my $type_name = $self->find_type_name ($field);
my $full_type_name = $self->format_full_type_name ($type_name); my $full_type_name = $self->format_full_type_name ($type_name);
my $flags = $self->format_field_flags ($field, qw/introspectable/); my $flags = $self->format_field_flags ($field, qw/introspectable/);
$text .= " • $name: $full_type_name$flags\n"; $text .= " • [$name]($path): $full_type_name$flags\n";
} }
} }
return $text; return $text;
...@@ -865,9 +867,10 @@ sub format_sub_functions { ...@@ -865,9 +867,10 @@ sub format_sub_functions {
$text .= "\n$heading\n\n"; $text .= "\n$heading\n\n";
foreach my $function ($function_list->get_nodelist) { foreach my $function ($function_list->get_nodelist) {
my $name = $self->find_attribute ($function, 'name'); my $name = $self->find_attribute ($function, 'name');
my $path = $function->nodePath;
my $flags = $self->format_callable_flags ($function, my $flags = $self->format_callable_flags ($function,
qw/introspectable version/); qw/introspectable version/);
$text .= " • $name$flags\n"; $text .= " • [$name]($path)$flags\n";
} }
} }
return $text; return $text;
...@@ -900,9 +903,10 @@ sub format_sub_methods { ...@@ -900,9 +903,10 @@ sub format_sub_methods {
$text .= "\nMETHODS\n\n"; $text .= "\nMETHODS\n\n";
foreach my $method ($method_list->get_nodelist) { foreach my $method ($method_list->get_nodelist) {
my $name = $self->find_attribute ($method, 'name'); my $name = $self->find_attribute ($method, 'name');
my $path = $method->nodePath;
my $flags = $self->format_callable_flags ($method, my $flags = $self->format_callable_flags ($method,
qw/introspectable version/); qw/introspectable version/);
$text .= " • $name$flags\n"; $text .= " • [$name]($path)$flags\n";
} }
} }
return $text; return $text;
...@@ -916,10 +920,11 @@ sub format_sub_properties { ...@@ -916,10 +920,11 @@ sub format_sub_properties {
$text .= "\nPROPERTIES\n\n"; $text .= "\nPROPERTIES\n\n";
foreach my $property ($property_list->get_nodelist) { foreach my $property ($property_list->get_nodelist) {
my $name = $self->find_attribute ($property, 'name'); my $name = $self->find_attribute ($property, 'name');
my $path = $property->nodePath;
my $type_name = $self->find_type_name ($property); my $type_name = $self->find_type_name ($property);
my $full_type_name = $self->format_full_type_name ($type_name); my $full_type_name = $self->format_full_type_name ($type_name);
my $flags = $self->format_property_flags ($property, qw/version/); my $flags = $self->format_property_flags ($property, qw/version/);
$text .= " • $name: $full_type_name$flags\n"; $text .= " • [$name]($path): $full_type_name$flags\n";
} }
} }
return $text; return $text;
...@@ -933,8 +938,9 @@ sub format_sub_signals { ...@@ -933,8 +938,9 @@ sub format_sub_signals {
$text .= "\nSIGNALS\n\n"; $text .= "\nSIGNALS\n\n";
foreach my $signal ($signal_list->get_nodelist) { foreach my $signal ($signal_list->get_nodelist) {
my $name = $self->find_attribute ($signal, 'name'); my $name = $self->find_attribute ($signal, 'name');
my $path = $signal->nodePath;
my $flags = $self->format_signal_flags ($signal, qw/version/); my $flags = $self->format_signal_flags ($signal, qw/version/);
$text .= " • $name$flags\n"; $text .= " • [$name]($path)$flags\n";
} }
} }
return $text; return $text;
...@@ -948,8 +954,9 @@ sub format_sub_virtual_methods { ...@@ -948,8 +954,9 @@ sub format_sub_virtual_methods {
$text .= "\nVIRTUAL METHODS\n\n"; $text .= "\nVIRTUAL METHODS\n\n";
foreach my $vfunc ($vfunc_list->get_nodelist) { foreach my $vfunc ($vfunc_list->get_nodelist) {
my $name = $self->find_attribute ($vfunc, 'name'); my $name = $self->find_attribute ($vfunc, 'name');
my $path = $vfunc->nodePath;
my $flags = $self->format_virtual_method_flags ($vfunc); my $flags = $self->format_virtual_method_flags ($vfunc);
$text .= " • $name$flags\n"; $text .= " • [$name]($path)$flags\n";
} }
} }
return $text; return $text;
...@@ -1314,7 +1321,35 @@ sub filter_gir_view { ...@@ -1314,7 +1321,35 @@ sub filter_gir_view {
sub display_results { sub display_results {
my ($self, $results) = @_; my ($self, $results) = @_;
$self->{result_buffer}->set_text ($results);
my $b = $self->{result_buffer};
$b->delete ($b->get_start_iter (), $b->get_end_iter ());
my $iter = $b->get_start_iter ();
my $insert_part = sub {
my ($start, $end) = @_;
$b->insert ($iter, substr ($results, $start, $end - $start));
};
my ($prev_match_start, $prev_match_end) = (0, 0);
while ($results =~ m/\[([^\n\]]+)\]\(([^\n\)]+)\)/g) {
my ($link_text, $link_target) = ($1, $2);
my ($match_start, $match_end) = ($-[0], $+[0]);
if ($match_start != $prev_match_end) {
$insert_part->($prev_match_end, $match_start);
}
my $tag = $b->create_tag (undef, foreground => 'blue');
$tag->{__target} = $link_target;
$b->insert_with_tags ($iter, $link_text, $tag);
($prev_match_start, $prev_match_end) = ($match_start, $match_end);
}
my $end_offset = length ($results);
if ($prev_match_end != $end_offset) {
$insert_part->($prev_match_end, $end_offset);
}
} }
sub run { sub run {
...@@ -1409,7 +1444,7 @@ sub setup_gir_view { ...@@ -1409,7 +1444,7 @@ sub setup_gir_view {
}); });
$gir_view->get_selection->signal_connect (changed => sub { $gir_view->get_selection->signal_connect (changed => sub {
$self->update_results_from_selection $self->go_to_selection
unless $self->{suppress_gir_view_selection_changes}; unless $self->{suppress_gir_view_selection_changes};
}); });
...@@ -1431,9 +1466,19 @@ sub setup_path_bar { ...@@ -1431,9 +1466,19 @@ sub setup_path_bar {
sub setup_search_entry { sub setup_search_entry {
my ($self) = @_; my ($self) = @_;
my $wait_time_ms = 500;
my $search_entry = Gtk3::SearchEntry->new; my $search_entry = Gtk3::SearchEntry->new;
$search_entry->signal_connect (search_changed => sub { $search_entry->signal_connect (search_changed => sub {
$self->filter_gir_view ($search_entry->get_text); # Use a timeout which is reset when the search text changes so that we do
# not filter the view too often.
if (defined $search_entry->{__timer_id}) {
Glib::Source->remove ($search_entry->{__timer_id});
}
$search_entry->{__timer_id} = Glib::Timeout->add ($wait_time_ms, sub {
$self->filter_gir_view ($search_entry->get_text);
$search_entry->{__timer_id} = undef;
return Glib::SOURCE_REMOVE ();
});
}); });
$self->{search_entry} = $search_entry; $self->{search_entry} = $search_entry;
...@@ -1443,9 +1488,66 @@ sub setup_result_view { ...@@ -1443,9 +1488,66 @@ sub setup_result_view {
my ($self) = @_; my ($self) = @_;
my $result_buffer = Gtk3::TextBuffer->new (undef); my $result_buffer = Gtk3::TextBuffer->new (undef);
my $result_view = Gtk3::TextView->new_with_buffer ($result_buffer); my $result_view = Gtk3::TextView->new_with_buffer ($result_buffer);
$result_view->set (editable => FALSE, margin => 2); $result_view->set (editable => FALSE, margin => 2);
my $display = $result_view->get_display ();
$result_view->{__hand_cursor} = Gtk3::Gdk::Cursor->new_from_name ($display, 'pointer');
$result_view->{__regular_cursor} = Gtk3::Gdk::Cursor->new_from_name ($display, 'text');
my $hovering_over_link = sub {
my ($event) = @_;
my ($x, $y) = $result_view->window_to_buffer_coords ('widget', $event->x, $event->y);
my $iter = $result_view->get_iter_at_location ($x, $y);
if (!$iter) {
return undef;
}
my $tags = $iter->get_tags ();
foreach my $tag (@$tags) {
if (defined $tag->{__target}) {
return $tag;
}
}
return undef;
};
$result_view->{__hovering} = FALSE;
$result_view->signal_connect (motion_notify_event => sub {
my ($result_view, $event) = @_;
my $hovering = defined $hovering_over_link->($event);
if ($result_view->{__hovering} != $hovering) {
$result_view->{__hovering} = $hovering;
$result_view->get_window ('text')->set_cursor (
$hovering ? $result_view->{__hand_cursor} : $result_view->{__regular_cursor});
}
return Gtk3::EVENT_PROPAGATE ();
});
my $handle_button = sub {
my ($event, $cb) = @_;
if ($event->button == Gtk3::Gdk::BUTTON_PRIMARY ()) {
my $tag = $hovering_over_link->($event);
if (defined $tag) {
if (defined $cb) {
$cb->($tag);
}
return Gtk3::EVENT_STOP ();
}
}
return Gtk3::EVENT_PROPAGATE ();
};
$result_view->signal_connect (button_press_event => sub {
my ($result_view, $event) = @_;
return $handle_button->($event);
});
$result_view->signal_connect (button_release_event => sub {
my ($result_view, $event) = @_;
return $handle_button->($event, sub {
$self->go_to_path ($_[0]->{__target});
});
});
$self->{result_buffer} = $result_buffer; $self->{result_buffer} = $result_buffer;
$self->{result_view} = $result_view; $self->{result_view} = $result_view;
} }
...@@ -1457,6 +1559,7 @@ sub update_gir_view { ...@@ -1457,6 +1559,7 @@ sub update_gir_view {
$self->{gir_model}->clear; $self->{gir_model}->clear;
$self->{search_entry}->set_text (''); $self->{search_entry}->set_text ('');
$self->{path_bar}->clear;
my $inserter = sub { my $inserter = sub {
my ($iter, $text, $path, $is_cat, $is_vis) = @_; my ($iter, $text, $path, $is_cat, $is_vis) = @_;
...@@ -1502,7 +1605,7 @@ sub update_gir_view { ...@@ -1502,7 +1605,7 @@ sub update_gir_view {
$self->display_results ($self->{parser}->format_namespace); $self->display_results ($self->{parser}->format_namespace);
} }
sub update_results_from_selection { sub go_to_selection {
my ($self) = @_; my ($self) = @_;
my $selection = $self->{gir_view}->get_selection; my $selection = $self->{gir_view}->get_selection;
my ($model, $iter) = $selection->get_selected; my ($model, $iter) = $selection->get_selected;
...@@ -1510,28 +1613,36 @@ sub update_results_from_selection { ...@@ -1510,28 +1613,36 @@ sub update_results_from_selection {
$self->display_results ($self->{parser}->format_namespace); $self->display_results ($self->{parser}->format_namespace);
} elsif (!$model->get ($iter, GIR_VIEW_COL_IS_CATEGORY)) { } elsif (!$model->get ($iter, GIR_VIEW_COL_IS_CATEGORY)) {
my $path = $model->get ($iter, GIR_VIEW_COL_PATH); my $path = $model->get ($iter, GIR_VIEW_COL_PATH);
my $name = $self->{parser}->format_node_name_by_path ($path); $self->go_to_path ($path);
$self->{path_bar}->append ($name, $path); # indirectly calls update_results
} }
} }
sub go_to_path {
my ($self, $path) = @_;
my $name = $self->{parser}->format_node_name_by_path ($path);
$self->{path_bar}->append ($name, $path); # indirectly calls update_results
}
sub update_results { sub update_results {
my ($self, $path) = @_; my ($self, $path) = @_;
$self->display_results ($self->{parser}->format_node_by_path ($path)); $self->display_results ($self->{parser}->format_node_by_path ($path));
# If display and selection are out-of-sync, clear the selection. # Show and select the correponding tree entry.
my $selection = $self->{gir_view}->get_selection; $self->{gir_model}->foreach (sub {
my ($model, $iter) = $selection->get_selected; my ($model, $tree_path, $iter) = @_;
if (defined $iter) { my $this_path = $model->get ($iter, GIR_VIEW_COL_PATH);
my $sel_path = $model->get ($iter, GIR_VIEW_COL_PATH); if (defined $this_path && $this_path eq $path) {
if ($sel_path ne $path) { $self->{gir_view}->expand_to_path ($tree_path);
$self->{gir_view}->scroll_to_cell ($tree_path, undef, FALSE, 0.0, 0.0);
$self->{suppress_gir_view_selection_changes} = TRUE; $self->{suppress_gir_view_selection_changes} = TRUE;
{ {
$selection->unselect_all; $self->{gir_view}->get_selection ()->select_path ($tree_path);
} }
$self->{suppress_gir_view_selection_changes} = FALSE; $self->{suppress_gir_view_selection_changes} = FALSE;
return TRUE; # stop
} }
} return FALSE; # continue
});
} }
sub quit { sub quit {
...@@ -1588,6 +1699,12 @@ sub INIT_INSTANCE { ...@@ -1588,6 +1699,12 @@ sub INIT_INSTANCE {
return $self; return $self;
} }
sub clear {
my ($self) = @_;
$self->{path_label}->clear ();
$self->update_buttons ();
}
sub append { sub append {
my ($self, $name, $path) = @_; my ($self, $name, $path) = @_;
$self->{path_label}->append ($name, $path); $self->{path_label}->append ($name, $path);
...@@ -1619,20 +1736,35 @@ sub INIT_INSTANCE { ...@@ -1619,20 +1736,35 @@ sub INIT_INSTANCE {
my (undef, $index) = @_; my (undef, $index) = @_;
$self->{current_child} = $index; $self->{current_child} = $index;
$self->update; $self->update;
return TRUE; # handled return Gtk3::EVENT_STOP ();
}); });
$self->set_track_visited_links (FALSE); $self->set_track_visited_links (FALSE);
$self->clear ();
}
sub clear {
my ($self) = @_;
$self->{children} = []; $self->{children} = [];
$self->{current_child} = undef; $self->{current_child} = undef;
$self->{natural_width} = 0; $self->{natural_width} = 0;
$self->update ();
} }
sub append { sub append {
my ($self, $name, $path) = @_; my ($self, $name, $path) = @_;
if (defined $self->{current_child} && my $cur = $self->{current_child};
$self->{current_child} < $#{$self->{children}}) { # If the new entry is equal to the current entry, do nothing.
splice @{$self->{children}}, $self->{current_child}+1; if (defined $cur) {
my $child = $self->{children}->[$cur];
if ($child->{name} eq $name && $child->{path} eq $path) {
return;
}
}
# If the current entry is not the last entry, remove all entries after the
# current one before appending the new entry.
if (defined $cur && $cur < $#{$self->{children}}) {
splice @{$self->{children}}, $cur+1;
} }
push @{$self->{children}}, {name => $name, path => $path}; push @{$self->{children}}, {name => $name, path => $path};
$self->{current_child} = $#{$self->{children}}; $self->{current_child} = $#{$self->{children}};
...@@ -1641,12 +1773,12 @@ sub append { ...@@ -1641,12 +1773,12 @@ sub append {
sub can_go_back { sub can_go_back {
my ($self) = @_; my ($self) = @_;
return $self->{current_child} > 0; return defined $self->{current_child} && $self->{current_child} > 0;
} }
sub can_go_forward { sub can_go_forward {
my ($self) = @_; my ($self) = @_;
return $self->{current_child} < $#{$self->{children}}; return defined $self->{current_child} && $self->{current_child} < $#{$self->{children}};
} }
sub go_back { sub go_back {
...@@ -1671,7 +1803,7 @@ sub set_update_func { ...@@ -1671,7 +1803,7 @@ sub set_update_func {
sub update { sub update {
my ($self) = @_; my ($self) = @_;
$self->set_markup ($self->_format_children); $self->set_markup ($self->_format_children);
if (defined $self->{update_func}) { if (defined $self->{current_child} && defined $self->{update_func}) {
my $child = $self->{children}->[$self->{current_child}]; my $child = $self->{children}->[$self->{current_child}];
$self->{update_func}->($child->{name}, $child->{path}); $self->{update_func}->($child->{name}, $child->{path});
} }
...@@ -1687,7 +1819,6 @@ sub GET_PREFERRED_WIDTH { ...@@ -1687,7 +1819,6 @@ sub GET_PREFERRED_WIDTH {
sub SIZE_ALLOCATE { sub SIZE_ALLOCATE {
#say 'SIZE_ALLOCATE'; #say 'SIZE_ALLOCATE';
my ($self, $allocation) = @_; my ($self, $allocation) = @_;
#print "$_ => $allocation->{$_}, " for sort keys %$allocation; print "\n";
if ($self->{natural_width} > $allocation->{width}) { if ($self->{natural_width} > $allocation->{width}) {
my @selected = ($self->{current_child}); my @selected = ($self->{current_child});
while (1) { while (1) {
...@@ -1715,6 +1846,9 @@ sub SIZE_ALLOCATE { ...@@ -1715,6 +1846,9 @@ sub SIZE_ALLOCATE {
# Use undef as an indicator for left-out children. # Use undef as an indicator for left-out children.
sub _add_omission_markers { sub _add_omission_markers {
my ($self, @indices) = @_; my ($self, @indices) = @_;
if (!@indices) {
return @indices;
}
if ($indices[0] > 0) { if ($indices[0] > 0) {
unshift @indices, undef; unshift @indices, undef;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment