[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[6491] Info sub-tree search
From: |
Gavin D. Smith |
Subject: |
[6491] Info sub-tree search |
Date: |
Sun, 02 Aug 2015 22:49:54 +0000 |
Revision: 6491
http://svn.sv.gnu.org/viewvc/?view=rev&root=texinfo&revision=6491
Author: gavin
Date: 2015-08-02 22:49:53 +0000 (Sun, 02 Aug 2015)
Log Message:
-----------
Info sub-tree search
Modified Paths:
--------------
trunk/ChangeLog
trunk/info/display.c
trunk/info/display.h
trunk/info/infomap.c
trunk/info/nodes.c
trunk/info/nodes.h
trunk/info/session.c
trunk/info/session.h
trunk/info/window.c
trunk/info/window.h
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/ChangeLog 2015-08-02 22:49:53 UTC (rev 6491)
@@ -1,3 +1,29 @@
+2015-08-02 Gavin Smith <address@hidden>
+
+ * info/nodes.h (NODE): New field 'active_menu'.
+ (N_SeenBySearch): New flag.
+
+ * info/session.c (tree_search_check_node)
+ (tree_search_check_node_backwards): New functions.
+ (info_tree_search, info_tree_search_next, info_tree_search_prev): New
+ user commmands (experimental).
+
+ * info/session.c (put_node_in_window, forget_node_fast)
+ (wipe_seen_flags, info_set_node_of_window_fast)
+ (tag_of_reference): New utility functions.
+
+ * info/nodes.c (find_node_from_tag): Preserve active_menu field
+ for nodes in window histories.
+ * info/infomap.c (default_emacs_like_info_keys): Add bindings
+ for new commands.
+ * info/window.c (window_line_of_point),
+ * info/display.c (display_update_one_window): Calculate line
+ starts if needed.
+ (calculate_line_starts): No longer static.
+ * info/nodes.c (info_load_file): Store filename without file
+ extension.
+ * info/window.h (WINDOW): Update a comment.
+
2015-08-01 Karl Berry <address@hidden>
* doc/texinfo.tex (\ctrl): remove this long-obsolete control sequence.
Modified: trunk/info/display.c
===================================================================
--- trunk/info/display.c 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/display.c 2015-08-02 22:49:53 UTC (rev 6491)
@@ -702,8 +702,10 @@
if ((win->first_row < 0) || (win->first_row > the_screen->height))
goto funexit;
- if (win->node && win->line_starts)
+ if (win->node)
{
+ if (!win->line_starts)
+ calculate_line_starts (win);
line_index = display_update_node_text (win);
if (display_was_interrupted_p)
Modified: trunk/info/display.h
===================================================================
--- trunk/info/display.h 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/display.h 2015-08-02 22:49:53 UTC (rev 6491)
@@ -72,4 +72,6 @@
extern void display_scroll_line_starts (WINDOW *window, int old_pagetop,
long *old_starts, int old_count);
+void calculate_line_starts (WINDOW *window);
+
#endif /* not INFO_DISPLAY_H */
Modified: trunk/info/infomap.c
===================================================================
--- trunk/info/infomap.c 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/infomap.c 2015-08-02 22:49:53 UTC (rev 6491)
@@ -230,6 +230,9 @@
KEYMAP_META('r'), NUL, A_info_move_to_window_line,
KEYMAP_META('v'), NUL, A_info_scroll_backward_page_only,
KEYMAP_META('x'), NUL, A_info_execute_command,
+ KEYMAP_META('/'), NUL, A_info_tree_search,
+ KEYMAP_META('}'), NUL, A_info_tree_search_next,
+ KEYMAP_META('{'), NUL, A_info_tree_search_prev,
CONTROL('x'), CONTROL('b'), NUL, A_list_visited_nodes,
CONTROL('x'), CONTROL('c'), NUL, A_info_quit,
Modified: trunk/info/nodes.c
===================================================================
--- trunk/info/nodes.c 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/nodes.c 2015-08-02 22:49:53 UTC (rev 6491)
@@ -717,6 +717,13 @@
file_buffer = make_file_buffer ();
file_buffer->fullpath = xstrdup (fullpath);
file_buffer->filename = filename_non_directory (file_buffer->fullpath);
+ file_buffer->filename = xstrdup (file_buffer->filename);
+ /* Strip off a file extension, so we can find it again in info_find_file. */
+ {
+ char *p = strchr (file_buffer->filename, '.');
+ if (p)
+ *p = '\0';
+ }
file_buffer->finfo = finfo;
file_buffer->filesize = filesize;
file_buffer->contents = contents;
@@ -1242,7 +1249,10 @@
conditional above. */
(*h)->node = info_get_node (n->fullpath, n->nodename);
if ((*h)->node)
- free_history_node (n);
+ {
+ (*h)->node->active_menu = n->active_menu;
+ free_history_node (n);
+ }
else
{
/* We found the node before, but now we can't. Just leave
Modified: trunk/info/nodes.h
===================================================================
--- trunk/info/nodes.h 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/nodes.h 2015-08-02 22:49:53 UTC (rev 6491)
@@ -49,9 +49,10 @@
long body_start; /* Offset of the actual node body */
int flags; /* See immediately below. */
REFERENCE **references; /* Cross-references or menu items in node.
- references == 0 implies uninitialized,
- not empty */
+ Null-terminated. references == 0 implies
+ uninitialized, not empty */
char *up, *prev, *next; /* Names of nearby nodes. */
+ int active_menu; /* Used for subnodes search. */
} NODE;
/* Values for NODE.flags or FILE_BUFFER.flags. */
@@ -69,6 +70,7 @@
#define N_EOLs_Converted 0x1000 /* CR bytes were stripped before LF. */
#define N_Gone 0x2000 /* File is no more. */
#define N_Simple 0x4000 /* Data about cross-references is missing. */
+#define N_SeenBySearch 0x8000 /* Node has already been seen in a search. */
/* String constants. */
#define INFO_FILE_LABEL "File:"
@@ -106,7 +108,7 @@
long nodestart; /* The value read from the tag table. */
long nodestart_adjusted;
int flags; /* Same as NODE.flags. */
- NODE cache;
+ NODE cache; /* Saved information about pointed-to node. */
} TAG;
/* The following structure is used to remember information about the contents
Modified: trunk/info/session.c
===================================================================
--- trunk/info/session.c 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/session.c 2015-08-02 22:49:53 UTC (rev 6491)
@@ -881,13 +881,25 @@
free (n);
}
+static void
+put_node_in_window (WINDOW *win, NODE *node)
+{
+ win->node = node;
+ win->pagetop = 0;
+ win->point = 0;
+ free (win->matches); win->matches = 0;
+ free (win->line_starts); win->line_starts = 0;
+ free (win->log_line_no); win->log_line_no = 0;
+ win->flags |= W_UpdateWindow;
+}
+
/* Go back one in the node history. */
-void
-forget_node (WINDOW *win)
+int
+forget_node_fast (WINDOW *win)
{
int i = win->hist_index;
if (i == 0)
- return;
+ return 0;
free_history_node (win->hist[i - 1]->node);
free (win->hist[i - 1]);
@@ -895,7 +907,23 @@
i = --win->hist_index;
if (i == 0)
+ /* Window history is empty. */
+ win->node = 0;
+ else
{
+ put_node_in_window (win, win->hist[i - 1]->node);
+ win->point = win->hist[i - 1]->point;
+ }
+ return i;
+}
+
+void
+forget_node (WINDOW *win)
+{
+ int i = forget_node_fast (win);
+
+ if (i == 0)
+ {
win->node = 0;
return; /* Window history is empty. */
}
@@ -922,6 +950,27 @@
free (win->hist);
}
+/* Like info_set_node_of_window, but only do enough so to extend the
+ window history, avoiding calculating line starts. */
+void
+info_set_node_of_window_fast (WINDOW *win, NODE *node)
+{
+ WINDOW_STATE *new;
+
+ if (win->hist_index && win->hist[win->hist_index - 1]->node == win->node)
+ {
+ win->hist[win->hist_index - 1]->pagetop = win->pagetop;
+ win->hist[win->hist_index - 1]->point = win->point;
+ }
+ put_node_in_window (win, node);
+
+ new = xmalloc (sizeof (WINDOW_STATE));
+ new->node = win->node;
+ new->pagetop = win->pagetop;
+ new->point = win->point;
+ add_pointer_to_array (new, win->hist_index, win->hist, win->hist_slots, 16);
+}
+
/* Set WINDOW to show NODE. Remember the new window in our list of
Info windows. If we are doing automatic footnote display, try to display
the footnotes for this window. */
@@ -4262,6 +4311,344 @@
gc_file_buffers_and_nodes ();
}
+/* Set *T to an offset within the tags table of the node referenced by R,
+ using WINDOW for defaults. *FB is set to the file buffer structure for
+ the node. */
+static int
+tag_of_reference (REFERENCE *r, WINDOW *window, FILE_BUFFER **fb, TAG ***t)
+{
+ char *filename, *nodename;
+ int i;
+
+ filename = r->filename;
+ nodename = r->nodename;
+ if (!filename)
+ filename = window->node->fullpath;
+ if (!nodename || !*nodename)
+ nodename = "Top";
+
+ *fb = info_find_file (filename);
+ if (!*fb)
+ return 0;
+
+ for (i = 0; *(*t = &(*fb)->tags[i]); i++)
+ if (!strcmp (nodename, (**t)->nodename))
+ goto found_tag;
+ return 0;
+found_tag: ;
+ return 1;
+}
+
+static void tree_search_check_node (WINDOW *window);
+static void tree_search_check_node_backwards (WINDOW *window);
+
+/* Search in WINDOW->node, and nodes reachable by menus from it, for
+ WINDOW->search_string. */
+static void
+tree_search_check_node (WINDOW *window)
+{
+ long start_off;
+ enum search_result result;
+ char *string;
+ int previous_match;
+
+ if (window->node->active_menu != 0)
+ previous_match = 1;
+ else
+ {
+ previous_match = 0;
+ window->node->active_menu = -99;
+ }
+ string = xstrdup (window->search_string);
+ goto check_node;
+
+check_node:
+ result = info_search_in_node_internal (window, window->node,
+ string,
+ window->point + 1,
+ 1, /* Search forwards */
+ 1, /* Case-sensitive */
+ 0, /* No regular expressions. */
+ &start_off);
+ if (result == search_success)
+ {
+ info_show_point (window);
+ goto funexit;
+ }
+
+ /* Otherwise, try each menu entry in turn. */
+ if (window->matches)
+ window->point++; /* Find this match again if/when we come back. */
+ goto check_menus;
+
+ /* At this juncture, window->node->active_menu is the index of the last
+ reference in the node to have been checked, plus one. -99 is a special
+ code to say that none of them have been checked. */
+check_menus:
+ if (!(window->node->flags & N_IsIndex)) /* Don't go down menus in index */
+ { /* nodes, because this leads to loops. */
+ REFERENCE *r;
+ int ref_index;
+ if (window->node->active_menu != -99)
+ ref_index = window->node->active_menu;
+ else
+ ref_index = 0;
+ for (; (r = window->node->references[ref_index]); ref_index++)
+ if (r->type == REFERENCE_MENU_ITEM)
+ {
+ FILE_BUFFER *file_buffer;
+ TAG **tag;
+ NODE *node;
+
+ if (!tag_of_reference (r, window, &file_buffer, &tag))
+ continue;
+
+ if ((*tag)->flags & N_SeenBySearch)
+ continue;
+ (*tag)->flags |= N_SeenBySearch;
+
+ window->node->active_menu = ref_index + 1;
+ node = info_node_of_tag (file_buffer, tag);
+ if (!node)
+ continue;
+ info_set_node_of_window_fast (window, node);
+ window->node->active_menu = -99;
+ goto check_node;
+ }
+ }
+ goto go_up;
+
+go_up:
+ /* If no more menu entries, try going back. */
+ if (window->hist_index >= 2
+ && window->hist[window->hist_index - 2]->node->active_menu != 0)
+ {
+ forget_node_fast (window);
+ goto check_menus;
+ }
+
+ /* Go back to the final match. */
+ if (previous_match)
+ {
+ REFERENCE *mentry;
+
+ message_in_echo_area (_("Going back to last match from %s"),
+ window->node->nodename);
+
+ /* This is a trick. Add an arbitrary node to the window history,
+ but set active_menu to one more than the number of references. When
+ we call tree_search_check_node_backwards, this will repeatedly go
down
+ the last menu entry for us. */
+ {
+ int n = 0;
+
+ while (window->node->references[n])
+ n++;
+ window->node->active_menu = n + 1;
+
+ mentry = select_menu_digit (window, '1');
+ if (!mentry)
+ goto funexit;
+ if (!info_select_reference (window, mentry))
+ goto funexit;
+ window->node->active_menu = -99;
+ }
+ window->point = window->node->body_start;
+ tree_search_check_node_backwards (window);
+ }
+ info_error (_("No more matches."));
+
+ /*window->node->active_menu = 0;
+ free (window->search_string); window->search_string = 0;*/
+
+funexit:
+ free (string);
+} /*********** end tree_search_check_node *************/
+
+
+/* The same as tree_search_check_node, but backwards. */
+static void
+tree_search_check_node_backwards (WINDOW *window)
+{
+ long start_off;
+ enum search_result result;
+ char *string;
+
+ string = xstrdup (window->search_string);
+ goto check_node;
+
+check_node:
+ result = info_search_in_node_internal (window, window->node,
+ string,
+ window->point - 1,
+ -1, /* Search backwards */
+ 1, /* Case-sensitive */
+ 0, /* No regular expressions. */
+ &start_off);
+ if (result == search_success)
+ {
+ info_show_point (window);
+ goto funexit;
+ }
+
+ goto go_up;
+
+ /* Check through menus in current node, in reverse order.
+ At this juncture, window->node->active_menu is the index of the last
+ reference in the node to have been checked, plus one. -99 is a special
+ code to say that none of them have been checked. */
+check_menus:
+ if (!(window->node->flags & N_IsIndex)) /* Don't go down menus in index */
+ { /* nodes, because this leads to loops. */
+ REFERENCE *r;
+ int ref_index;
+ if (window->node->active_menu == -99)
+ goto check_node;
+ else
+ ref_index = window->node->active_menu - 2;
+ for (; ref_index >= 0; ref_index--)
+ {
+ r = window->node->references[ref_index];
+ if (r->type == REFERENCE_MENU_ITEM)
+ {
+ TAG **tag;
+ FILE_BUFFER *file_buffer;
+ NODE *node;
+
+ if (!tag_of_reference (r, window, &file_buffer, &tag))
+ continue;
+
+ /* This inverts what is done for the forwards search. It's
+ possible that we will visit the nodes in a different order if
+ there is more than one reference to a node. */
+ if (!((*tag)->flags & N_SeenBySearch))
+ {
+ /*fprintf (stderr, "omitting (%s)%s\n",
+ (*tag)->filename,
+ (*tag)->nodename);*/
+ continue;
+ }
+
+ node = info_node_of_tag (file_buffer, tag);
+ if (!node)
+ continue;
+ window->node->active_menu = ref_index + 1;
+ info_set_node_of_window_fast (window, node);
+ window->point = window->node->nodelen;
+ {
+ /* Start at the last menu entry in the subordinate node. */
+ int i;
+ i = 0;
+ while(window->node->references[i])
+ i++;
+ window->node->active_menu = i + 1;
+ }
+ goto check_menus;
+ }
+ }
+ }
+ window->node->active_menu = -99;
+ goto check_node;
+
+ /* Try going back. */
+go_up:
+ if (window->hist_index >= 2
+ && window->hist[window->hist_index - 2]->node->active_menu != 0)
+ {
+ TAG **tag;
+ REFERENCE *r;
+ FILE_BUFFER *file_buffer;
+
+ //fprintf (stderr, "going up to %d\n", window->node->active_menu);
+ forget_node_fast (window);
+ r = window->node->references[window->node->active_menu - 1];
+
+ /* Clear the flag to say we've been to the node we just came back
+ from. This reverse the order from the forwards search, where
+ we set this flag just before going down. */
+ if (r && tag_of_reference (r, window, &file_buffer, &tag))
+ {
+ (*tag)->flags &= ~N_SeenBySearch;
+ }
+
+ goto check_menus;
+ }
+
+ /* Otherwise, no result. */
+ info_error (_("No more matches."));
+ /*window->node->active_menu = 0;
+ free (window->search_string); window->search_string = 0;*/
+
+funexit:
+ free (string);
+} /*********** end tree_search_check_node_backwards *************/
+
+
+/* Clear N_SeenBySearch for all nodes. */
+void
+wipe_seen_flags (void)
+{
+ int fb_index;
+ TAG **t;
+
+ for (fb_index = 0; fb_index < info_loaded_files_index; fb_index++)
+ {
+ t = info_loaded_files[fb_index]->tags;
+ if (!t)
+ continue; /* Probably a sub-file of a split file. */
+ for (; *t; t++)
+ {
+ (*t)->flags &= ~N_SeenBySearch;
+ }
+ }
+}
+
+DECLARE_INFO_COMMAND (info_tree_search,
+ _("Search this node and subnodes for a string."))
+{
+ char *prompt, *line;
+ int i;
+
+ /* TODO: Display manual name */
+ asprintf (&prompt, "Search under %s: ",
+ //window->node->filename,
+ window->node->nodename);
+ line = info_read_in_echo_area (prompt); free (prompt);
+ if (!line)
+ return;
+
+ /* Remove relics of previous tree searches. */
+ wipe_seen_flags ();
+ for (i = 0; i < window->hist_index; i++)
+ window->hist[i]->node->active_menu = 0;
+ window->search_string = line;
+ tree_search_check_node (window);
+}
+
+DECLARE_INFO_COMMAND (info_tree_search_next,
+ _("Go to next match in Info sub-tree"))
+{
+ if (!window->search_string || window->node->active_menu == 0)
+ {
+ info_error (_("No active search"));
+ return;
+ }
+
+ tree_search_check_node (window);
+}
+
+DECLARE_INFO_COMMAND (info_tree_search_prev,
+ _("Go to previous match in Info sub-tree"))
+{
+ if (!window->search_string || window->node->active_menu == 0)
+ {
+ info_error (_("No active search"));
+ return;
+ }
+
+ tree_search_check_node_backwards (window);
+}
+
DECLARE_INFO_COMMAND (info_search_case_sensitively,
_("Read a string and search for it case-sensitively"))
{
Modified: trunk/info/session.h
===================================================================
--- trunk/info/session.h 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/session.h 2015-08-02 22:49:53 UTC (rev 6491)
@@ -64,6 +64,7 @@
int insert, int *count);
extern unsigned char info_input_pending_p (void);
extern void info_set_node_of_window (WINDOW *window, NODE *node);
+extern void info_set_node_of_window_fast (WINDOW *window, NODE *node);
extern void initialize_keyseq (void);
extern void add_char_to_keyseq (int character);
extern FILE_BUFFER *file_buffer_of_window (WINDOW *window);
@@ -81,8 +82,9 @@
associated nodes. */
extern void info_delete_window_internal (WINDOW *window);
-extern void forget_window_and_nodes (WINDOW *window);
-extern void forget_node (WINDOW *win);
+void forget_window_and_nodes (WINDOW *window);
+void forget_node (WINDOW *win);
+int forget_node_fast (WINDOW *win);
/* Tell Info that input is coming from the file FILENAME. */
extern void info_set_input_from_file (char *filename);
Modified: trunk/info/window.c
===================================================================
--- trunk/info/window.c 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/window.c 2015-08-02 22:49:53 UTC (rev 6491)
@@ -27,8 +27,6 @@
#include "tag.h"
#include "variables.h"
-static void calculate_line_starts (WINDOW *window);
-
/* The window which describes the screen. */
WINDOW *the_screen = NULL;
@@ -824,6 +822,9 @@
{
register int i, start = 0;
+ if (!window->line_starts)
+ calculate_line_starts (window);
+
/* Try to optimize. Check to see if point is past the pagetop for
this window, and if so, start searching forward from there. */
if (window->pagetop > -1 && window->pagetop < window->line_count
@@ -1170,7 +1171,7 @@
Note that this function must agree with what display_update_one_window
in display.c does. */
-static void
+void
calculate_line_starts (WINDOW *win)
{
long pl_chars = 0; /* Number of characters in line so far. */
Modified: trunk/info/window.h
===================================================================
--- trunk/info/window.h 2015-08-01 21:39:41 UTC (rev 6490)
+++ trunk/info/window.h 2015-08-02 22:49:53 UTC (rev 6491)
@@ -96,9 +96,9 @@
size_t match_count;
/* History of nodes visited in this window. */
- WINDOW_STATE **hist; /* Nodes visited in this window. */
- size_t hist_index; /* Index where to add the next node. */
- size_t hist_slots; /* Number of slots allocated to HIST. */
+ WINDOW_STATE **hist; /* Nodes visited in this window, including current. */
+ size_t hist_index; /* Index where to add the next node. */
+ size_t hist_slots; /* Number of slots allocated to HIST. */
} WINDOW;
#define W_UpdateWindow 0x01 /* WINDOW needs updating. */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [6491] Info sub-tree search,
Gavin D. Smith <=