poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Add doc command


From: Jose E. Marchesi
Subject: Re: [PATCH] Add doc command
Date: Sat, 29 Feb 2020 17:24:13 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux)

Hi John.

This is nice, but I think it would be better to call the command .info
instead of .doc.  WDYT?

    ---
     doc/Makefile.am |  11 +++++
     doc/poke.texi   |  21 +++++++++
     run.in          |   3 +-
     src/Makefile.am |   1 +
     src/pk-cmd.c    |   2 +
     src/pk-misc.c   | 116 ++++++++++++++++++++++++++++++++++++++++++++++++
     src/pk-repl.c   |  71 ++++++++++++++++++++++++++++-
     src/poke.c      |   9 ++++
     src/poke.h      |   1 +
     9 files changed, 233 insertions(+), 2 deletions(-)
    
    diff --git a/doc/Makefile.am b/doc/Makefile.am
    index ddf62f7b..58d88148 100644
    --- a/doc/Makefile.am
    +++ b/doc/Makefile.am
    @@ -16,3 +16,14 @@
     
     info_TEXINFOS = poke.texi
     poke_TEXINFOS = fdl.texi
    +
    +
    +# This rule generates a list of the node names from the manual.
    +# It then substitutes spaces with '/' which is a kludge used to
    +# work around some limitations of readline.
    +# Look for the macro SPACE_SUBSTITUTE in pk-repl.c to see how this
    +# is used.
    +$(srcdir)/nodelist: $(srcdir)/poke.info
    +   $(SED) -n -e 's/^\* \([^:]*\)::.*/\1/p' $< | $(SED) -e 's| |/|g' > $@
    +
    +INFO_DEPS = $(srcdir)/nodelist $(srcdir)/poke.info
    diff --git a/doc/poke.texi b/doc/poke.texi
    index 69548d0b..a7e270b0 100644
    --- a/doc/poke.texi
    +++ b/doc/poke.texi
    @@ -70,6 +70,7 @@ Dot-Commands
     * mem command::                    Opening and selecting memory IO spaces.
     * ios command::                    Switching between IO spaces.
     * close command::          Closing IO spaces.
    +* doc command::                 Online manual.
     * editor command::         Using an external editor for input.
     * info command::           Getting information about open files, @i{etc}.
     * set command::                    Querying and setting global options.
    @@ -582,6 +583,26 @@ is:
     
     Where @var{#tag} is a tag identifying an open IO stream.
     
    +@node doc command
    +@chapter @code{.doc}
    +@cindex @code{.doc}
    +@cindex doc
    +The @command{.doc} command is used to display this manual in poke's REPL.
    +The syntax is:
    +
    +@example
    +.doc [@var{node}]
    +@end example
    +
    +@noindent
    +where @var{node} is an optional parameter which indicates the chapter
    +or section at which the manual should be opened.
    +This command uses the info program (@ref{Top,,, info, The GNU Texinfo 
Manual})
    +to interactively present the manual.
    +Hence, it will fail if info is not installed.
    +If poke is not running interactively then @command{.doc} does nothing.
    +
    +
     @node editor command
     @chapter @code{.editor}
     @cindex @code{.editor}
    diff --git a/run.in b/run.in
    index 7254412a..7c0c031d 100644
    --- a/run.in
    +++ b/run.in
    @@ -31,9 +31,10 @@ b=$(cd @abs_builddir@ && pwd)
     # setup to run uninstalled poke
     PATH=$b/src:$PATH
     POKEDATADIR=$s/src
    +POKEINFODIR=$s/doc
     POKEPICKLESDIR=$s/pickles
     POKESTYLESDIR=$s/etc
    -export PATH POKEDATADIR POKEPICKLESDIR POKESTYLESDIR
    +export PATH POKEDATADIR POKEPICKLESDIR POKESTYLESDIR POKEINFODIR
     
     # Cheap way to find some use-after-free and uninit read problems with glibc
     MALLOC_CHECK_=1
    diff --git a/src/Makefile.am b/src/Makefile.am
    index 07db253b..21475612 100644
    --- a/src/Makefile.am
    +++ b/src/Makefile.am
    @@ -73,6 +73,7 @@ AM_LFLAGS = -d
     poke_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \
                     -DPKL_DEBUG \
                     -DPKGDATADIR=\"$(pkgdatadir)\" \
    +                -DPKGINFODIR=\"$(infodir)\" \
                     -DJITTER_VERSION=\"$(JITTER_VERSION)\" \
                     -DLOCALEDIR=\"$(localedir)\"
     poke_CFLAGS = -Wall $(BDW_GC_CFLAGS)
    diff --git a/src/pk-cmd.c b/src/pk-cmd.c
    index 547674fb..e920f5a9 100644
    --- a/src/pk-cmd.c
    +++ b/src/pk-cmd.c
    @@ -49,6 +49,7 @@ extern struct pk_cmd load_cmd; /* pk-file.c */
     extern struct pk_cmd info_cmd; /* pk-info.c  */
     extern struct pk_cmd exit_cmd; /* pk-misc.c  */
     extern struct pk_cmd version_cmd; /* pk-misc.c */
    +extern struct pk_cmd doc_cmd; /* pk-misc.c */
     extern struct pk_cmd jmd_cmd; /* pk-misc.c */
     extern struct pk_cmd help_cmd; /* pk-help.c */
     extern struct pk_cmd vm_cmd; /* pk-vm.c  */
    @@ -63,6 +64,7 @@ static struct pk_cmd *dot_cmds[] =
         &file_cmd,
         &exit_cmd,
         &version_cmd,
    +    &doc_cmd,
         &jmd_cmd,
         &info_cmd,
         &close_cmd,
    diff --git a/src/pk-misc.c b/src/pk-misc.c
    index cd0fc6c3..44717e6b 100644
    --- a/src/pk-misc.c
    +++ b/src/pk-misc.c
    @@ -20,6 +20,8 @@
     #include <assert.h>
     #include <time.h>
     
    +#include "findprog.h"
    +#include "readline.h"
     #include "poke.h"
     #include "pk-cmd.h"
     
    @@ -54,6 +56,59 @@ pk_cmd_version (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
       return 1;
     }
     
    +/* Call the info command for the poke documentation, using
    +   the requested node.  */
    +static int
    +pk_cmd_doc (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
    +{
    +  int ret = 1;
    +
    +  /* This command is inherently interactive.  So if we're not
    +     supposed to be in interactive mode, then do nothing.  */
    +  if (poke_interactive_p)
    +  {
    +    int size = 0;
    +    char *cmd = NULL;
    +    int bytes = 64;
    +
    +    const char info_prog_name[] = "info";
    +    const char *ip = find_in_path (info_prog_name);
    +    if (strcmp (ip, info_prog_name) == 0)
    +      {
    +   pk_term_class ("error");
    +   pk_puts ("error: ");
    +   pk_term_end_class ("error");
    +   pk_puts ("the \"info\" program is not installed.\n");
    +   return 0;
    +      }
    +
    +    do
    +      {
    +   size = bytes + 1;
    +   cmd = xrealloc (cmd, size);
    +   bytes = snprintf (cmd, size, "info -f \"%s/poke.info\"",
    +                     poke_infodir);
    +      }
    +    while (bytes >= size);
    +
    +    if (argv[0].type == PK_CMD_ARG_STR)
    +      {
    +   const char *node = argv[0].val.str;
    +   cmd = xrealloc (cmd, bytes + 7 + strlen (node));
    +   strcat (cmd, " -n \"");
    +   strcat (cmd, node);
    +   strcat (cmd, "\"");
    +      }
    +
    +    /* Open the documentation at the requested page.  */
    +    ret = (0 == system (cmd));
    +
    +    free (cmd);
    +  }
    +
    +  return ret;
    +}
    +
     static int
     pk_cmd_jmd (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
     {
    @@ -94,6 +149,64 @@ pk_cmd_jmd (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
       return 1;
     }
     
    +/* A completer to provide the node names of the info
    +   documentation.  */
    +char *
    +doc_completion_function (const char *x, int state)
    +{
    +  static char **nodelist = NULL;
    +  if (nodelist == NULL)
    +    {
    +      int n_nodes = 0;
    +      char nlfile[256];
    +      snprintf (nlfile, 256, "%s/nodelist", poke_infodir);
    +      FILE *fp = fopen (nlfile, "r");
    +      if (fp == NULL)
    +   return NULL;
    +      char *lineptr = NULL;
    +      size_t size = 0;
    +      while (!feof (fp))
    +   {
    +     int x = getline (&lineptr, &size, fp);
    +     if (x != -1)
    +       {
    +         nodelist = xrealloc (nodelist, ++n_nodes * sizeof (*nodelist));
    +         lineptr [strlen (lineptr) - 1] = '\0';
    +         nodelist[n_nodes - 1] = strdup (lineptr);
    +       }
    +   }
    +      fclose (fp);
    +      free (lineptr);
    +      nodelist = xrealloc (nodelist, ++n_nodes * sizeof (*nodelist));
    +      nodelist[n_nodes - 1] = NULL;
    +    }
    +
    +  static int idx = 0;
    +  if (state == 0)
    +    idx = 0;
    +  else
    +    ++idx;
    +
    +  int len = strlen (x);
    +  while (1)
    +    {
    +      const char *name = nodelist[idx];
    +      if (name == NULL)
    +   break;
    +
    +      int match = strncmp (name, x, len);
    +      if (match != 0)
    +   {
    +     idx++;
    +     continue;
    +   }
    +      return strdup (name);
    +    }
    +
    +  return NULL;
    +}
    +
    +
     struct pk_cmd exit_cmd =
       {"exit", "?i", "", 0, NULL, pk_cmd_exit, "exit [CODE]", NULL};
     
    @@ -102,3 +215,6 @@ struct pk_cmd version_cmd =
     
     struct pk_cmd jmd_cmd =
       {"jmd", "", "", 0, NULL, pk_cmd_jmd, "jmd", NULL};
    +
    +struct pk_cmd doc_cmd =
    +  {"doc", "?s", "", 0, NULL, pk_cmd_doc, "doc [section]", 
doc_completion_function};
    diff --git a/src/pk-repl.c b/src/pk-repl.c
    index 3e7215ae..a8ae15f0 100644
    --- a/src/pk-repl.c
    +++ b/src/pk-repl.c
    @@ -152,6 +152,49 @@ null_completion_function (const char *x, int state)
       return NULL;
     }
     
    +char * doc_completion_function (const char *x, int state);
    +
    +#define SPACE_SUBSTITUTE  '/'
    +
    +/* Display the list of matches, replacing SPACE_SUBSTITUTE with
    +   a space.  */
    +static void
    +space_substitute_display_matches (char **matches, int num_matches,
    +                           int max_length)
    +{
    +  for (int i = 0; i < num_matches + 1; ++i)
    +    {
    +      for (char *m = matches[i]; *m; ++m)
    +   {
    +     if (*m == SPACE_SUBSTITUTE)
    +       *m = ' ';
    +   }
    +    }
    +
    +  rl_display_match_list (matches, num_matches, max_length);
    +}
    +
    +/* Display the rl_line_buffer substituting
    +SPACE_SUBSTITUTE with a space.  */
    +static void
    +space_substitute_redisplay (void)
    +{
    +  /* Take a copy of the line_buffer.  */
    +  char *olb = strdup (rl_line_buffer);
    +
    +  for (char *x = rl_line_buffer; *x ; x++)
    +    {
    +      if (*x == SPACE_SUBSTITUTE)
    +        *x = ' ';
    +    }
    +
    +  rl_redisplay ();
    +
    +  /* restore the line_buffer to its original state.  */
    +  strcpy (rl_line_buffer, olb);
    +  free (olb);
    +}
    +
     /* Readline's getc callback.
        Use this function to update the completer which
        should be used.
    @@ -181,7 +224,27 @@ poke_getc (FILE *stream)
          }
       free (line_to_point);
     
    -  return rl_getc (stream);
    +  int c =  rl_getc (stream);
    +
    +  /* Due to readline's apparent inability to change the word break
    +     character in the middle of a line, we have to do some underhand
    +     skullduggery here.  Spaces are substituted with SPACE_SUBSTITUTE,
    +     and then substituted back again in various callback functions.  */
    +  if (rl_completion_entry_function == doc_completion_function)
    +    {
    +      rl_completion_display_matches_hook = 
space_substitute_display_matches;
    +      rl_redisplay_function = space_substitute_redisplay;
    +
    +      if (c == ' ')
    +   c = SPACE_SUBSTITUTE;
    +    }
    +  else
    +    {
    +      rl_completion_display_matches_hook = NULL;
    +      rl_redisplay_function = rl_redisplay;
    +    }
    +
    +  return c;
     }
     
     
    @@ -299,6 +362,12 @@ pk_repl (void)
               break;
             }
     
    +      for (char *s = line; *s; ++s)
    +   {
    +     if (*s == SPACE_SUBSTITUTE)
    +       *s = ' ';
    +   }
    +
           /* Ignore empty lines.  */
           if (*line == '\0')
             continue;
    diff --git a/src/poke.c b/src/poke.c
    index 48f5055c..cabc8a36 100644
    --- a/src/poke.c
    +++ b/src/poke.c
    @@ -56,6 +56,11 @@ int poke_quiet_p;
     
     char *poke_datadir;
     
    +/* The following global contains the directory holding the program's
    +   info file(s).  */
    +
    +char *poke_infodir;
    +
     /* The following global contains the directory holding pickles shipped
        with poke.  In an installed program, this is the same than
        poke_datadir, but the POKE_PICKLESDIR environment variable can be
    @@ -366,6 +371,10 @@ initialize (int argc, char *argv[])
       if (poke_picklesdir == NULL)
         poke_picklesdir = poke_datadir;
     
    +  poke_infodir = getenv ("POKEINFODIR");
    +  if (poke_infodir == NULL)
    +    poke_infodir = PKGINFODIR;
    +
       /* Initialize the terminal output.  */
       pk_term_init (argc, argv);
     
    diff --git a/src/poke.h b/src/poke.h
    index 1ee798c9..c8027de6 100644
    --- a/src/poke.h
    +++ b/src/poke.h
    @@ -28,6 +28,7 @@ extern int poke_exit_code;
     extern pkl_compiler poke_compiler;
     extern pvm poke_vm;
     extern char *poke_datadir;
    +extern char *poke_infodir;
     extern char *poke_picklesdir;
     extern int poke_obase;



reply via email to

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