poke-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] Add doc command


From: John Darrington
Subject: Re: [PATCH] Add doc command
Date: Sat, 29 Feb 2020 17:34:33 +0100
User-agent: Mutt/1.10.1 (2018-07-13)

On Sat, Feb 29, 2020 at 05:24:13PM +0100, Jose E. Marchesi wrote:
     
     Hi John.
     
     This is nice, but I think it would be better to call the command .info
     instead of .doc.  WDYT?

I think so too.   But unfortunately that name is already taken :(

     
         ---
          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]