texinfo-commits
[Top][All Lists]
Advanced

[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. */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]