repl help system

Started by starseed, August 03, 2006, 11:40:32 AM

Previous topic - Next topic

starseed

I like to have an interpreter open, to check code snippets. Now, if the interpreter is already there, it would be nice to have an online help system ... here it is ;-)



(define-macro (def)
   "Creates a lambda expression, while checking for doc-strings"
   (let  ((__def_func (args))
           (__def_help ""))
      (dolist (val (rest (__def_func 0)))
         (if (string? val)
            (set '__def_help (append __def_help val)))
         (if (symbol? val)
            (set '__def_help (append __def_help "n   " (string val) "t - "))))
      (nth-set (__def_func 0) (clean string? (__def_func 0)))
      (set '__def_help (append (string (nth 0 __def_func)) "n" __def_help))
      (if (string? (nth 1 __def_func))
         (begin
            (set '__def_help (append __def_help "n" (nth 1 __def_func)))
            (pop __def_func 1)))
      (push __def_help __def_func 1)
      (push 'define __def_func)
      (eval __def_func)
   )
)

(def (help "get quick help on function"
      on-func "function you want help for")
   {displays the doc-string of a function
   if on-func is a string, it searches all symbols for occurrence of this string
   if on-func is nil, return a list of all lambda, macro-lambda and primitives}
   (if
      (nil? on-func)
         (filter (lambda (x) (or (lambda? (eval x))(macro? (eval x))(primitive? (eval x)))) (symbols))
      (string? on-func)
         (filter (lambda (x) (find on-func (string x))) (symbols))
      (lambda? on-func)
         (if (string? (nth 1 on-func))
            (begin
               (println (nth 1 on-func))
               '-)
            'not-documented)
      'not-a-lambda-expression
   )
)

Usage:

def - see 'help definition

help -
> (help help)
(help on-func)
get quick help on function
   on-func - function you want help for
displays the doc-string of a function
   if on-func is a string, it searches all symbols for occurrence of this string
   if on-func is nil, return a list of all lambda, macro-lambda and primitives
-
> (help "xml")
(xml-error xml-parse xml-type-tags)


And again, comments are appreciated.





Ingo

cormullion

#1
First comment - thanks!



Second comment - you're not really a newbie ! ;-) I'm a newbie, so you can't be ...!



Third comment - Your suggestion made me wonder is there a good way of doing newLISP code? I know there's a Lisp way (probably a One True Lisp Way eg http://dept-info.labri.u-bordeaux.fr/~strandh/Teaching/Langages-Enchasses/Common/Strandh-Tutorial/indentation.html">//http://dept-info.labri.u-bordeaux.fr/~strandh/Teaching/Langages-Enchasses/Common/Strandh-Tutorial/indentation.html), but I wonder how many of the current newLISP users use a similar methodology.



I was using semicolons but my attempts at formatting code using (load) always strip them out, so I've been tempted to switch to strings...



Keep up the great work - I'll understand it eventually...!

starseed

#2
1) You're welcome! ;-)

2) OK, I cheated a little bit. I've done some programming in Rebol, which has lispy roots. But it does away with all these parens - which now are my main problem ...

3) See above ... I sometimes need the parens on their lines, to be able to read it. But maybe I'll learn with time.

4) The main advantage of semicolons is that they can be optimized away while loading (hey, it's a comment, no need to keep it around). The main advantage of strings is, that they stay in the code, and thus can be saved from a running system. On the other hand, they pose a speed penalty, but I don't know how big it is ...

I first wanted to search for doc-strings throughout the whole function body, but I realized that this is too complicated for me now.





Ingo

pjot

#3
Hi,



There is also an interesting idea about defining help for newLISP in this topic:



http://www.alh.net/newlisp/phpbb/viewtopic.php?t=881">http://www.alh.net/newlisp/phpbb/viewtopic.php?t=881



I have put this in my VIM macro's for newLISP, so within VIM I can always get info on a command (thanks to Lutz and  Cormullion).


Quote
I've done some programming in Rebol, which has lispy roots.


You should meet newdep, he is a Rebol guy also ;-)



Peter

HPW

#4
In Ultraedit I have defined a tool/button:


"C:ProgrammeInternet ExplorerIEXPLORE.EXE" "C:Programmenewlispnewlisp_manual.html#%sel%"

to get context help like in newLISP-TK.
Hans-Peter

frontera000

#5
Thanks. This is great!



I noticed if you do (help something-bogus) it will print list of symbols because

something-bogus will evaluate to nil.



Also (help xml-error) or (help 'xml-error) will print not-a-lambda expression.



I wrote this:


Quote
(def (help2 "get quick help on function v.2")

   {displays the doc-string of a function

   if argument provided is a string, it searches all symbols for occurrence of this string

   if no argument is provided return a list of all lambda, macro-lambda and primitives

   if argument provided is a primitive, it tells you that it is}

   (let (on-func (args 0))

   (if

     (empty? (args))

         (filter (lambda (x) (or (lambda? (eval x))(macro? (eval x))(primitive? (eval x)))) (symbols))

       (primitive? (eval on-func))

        (println (format "%s is a built-in primitive" (string on-func)))

      (string? on-func)

         (filter (lambda (x) (find on-func (string x))) (symbols))

      (lambda? on-func)

         (if (string? (nth 1 on-func))

            (begin

               (println (nth 1 on-func))

               '-)

            'not-documented)

      'not-a-lambda-expression)))

which will do:


Quote
> (help2 something-bogus)

not-a-lambda-expression

> (help2 xml-error)

xml-error <41B383> is a built-in primitiv

"xml-error <41B383> is a built-in primiti

> (help2 'xml-error)

xml-error is a built-in primitive

"xml-error is a built-in primitive"

>


I also wrote something that will parse the HTML Documentation for newLISP and fetch documentation for built-in functions.  But it looks ugly with HTML stuff, even when HTML tags are stripped.  I am still thinking how to get that done. Perhaps there is a better way. Like Common LISP Hyperspec way.

Lutz

#6
Quote also wrote something that will parse the HTML Documentation for newLISP and fetch documentation for built-in functions. But it looks ugly with HTML stuff, even when HTML tags are stripped.


Here is the perfect HTML cleaner on UNIX (and you also can get lynx for the PC):


(define (html2text url)
   (exec "lynx -dump  > /tmp/text-file" (get-url url))
   (read-file "/tmp/text-file"))


As a help facitlity when in the newLISP console you can use:


(define-macro (help func)
  (if (primitive? (eval func))
    (!  (format "lynx /usr/share/newlisp/doc/newlisp_manual.html#%s" (name func)))
    (format "%s is not a built-in function" (name func))))


After quitting out of Lynx, you are back in the newLISP console.



I wonder if that function could be somehow integrated into the newLISP EMACS facility. OSs which have EMACS tend to have lynx too. For the Mac there is "sudo port install lynx", when you have Darwin port tools installed.



Lutz



ps: the last function should be enhanced to translate the question mark '?' into 'p' for help on predicate keywords ending in '?'



- I just realize, an improved help function is already in the file: init.lsp.example in the newLISP source distribution.

starseed

#7
Actually, all displayed behaviour has been by design ... maybe based on just being lazy ;-)



I'll have a look into your changes - and then it would be nice to integrate both html-help, and online quickhelp.



Regards,



Ingo ;-)

frontera000

#8
I wrote something similar to online help available in Common LISP.  apropos will list out built-in functions that contain a string provided as an argument.  describe will print out the manual page for the function and return the string containing the printed documentation.


Quote


(set '_manual-location "c:\newlisp_manual.html")

(set '_manual-content "")



(define (apropos function-name-string context-name )

  (if (nil? context-name) (setq context-name MAIN))

  (if (context? context-name)

      (filter (lambda (x) (find function-name-string (string x))) (symbols context-name))))



(define-macro (describe function-name-string)

  (set '_str "")

  (if (apropos function-name-string MAIN)

      (begin

   (if (= _manual-content "")

       (set '_manual-content (read-file _manual-location)))

   (set '_where (find (append "<a name="" function-name-string """) _manual-content 1))

   (if (nil? _where)

       (format "no entry for in the manual" function-name-string)

       (begin

         (set '_end (find "<a>")    ; from Peter's code

   (replace "<" _str "<replace>")

   (for (a 33 255)

        (replace (append "&#" (string a) ";") _str (char a))

        (replace (append "&#0" (string a) ";") _str (char a))

        (replace (append "&#" (string a) ";") _str (char a)))   

   (replace "(<[^>]*>)" _str " " 1)

   (println (format "%s" _str)))

      (println "No such entry exists in the newLISP manual.")))


>


I tried to make 'describe' be easy to read, by stripping out HTML tags but I don't know if it is sufficiently readable.  It is for me.



Hope this is useful.

frontera000

#9
Before someone points it out... I know "describe" does something different in Common LISP.  The equivalent would be "documentation".  But I find that it is easier for me to remember and type "describe".

frontera000

#10
Already I noticed a problem.  It seems that newLISP Documentation tag for predicates (context? nil? etc.) which end with "?" are tagged with "p" instead of "?".  So I had to change the code a bit:



(set '_manual-location "c:\newlisp_manual.html")
(set '_manual-content "")

(define (apropos function-name-string context-name )
  (if (nil? context-name) (setq context-name MAIN))
  (if (context? context-name)
      (filter (lambda (x) (find function-name-string (string x))) (symbols context-name))))

(define-macro (describe function-name-string)
  (set '_str "")
  (if (apropos function-name-string MAIN)
      (begin
(if (= _manual-content "")
   (set '_manual-content (read-file _manual-location)))
(if (ends-with function-name-string "?")
   (set 'function-name-string (append (chop function-name-string) "p")))
(set '_where (find (append "<a name="" function-name-string """) _manual-content 1))
(if (nil? _where)
   (format "no entry for <s> in the manual" function-name-string)
   (begin
     (set '_end (find "<a>")    ; from Peter's code
(replace "<" _str "<replace>")
(for (a 33 255)
    (replace (append "&#" (string a) ";") _str (char a))
    (replace (append "&#0" (string a) ";") _str (char a))
    (replace (append "&#" (string a) ";") _str (char a)))
(replace "(<[^>]*>)" _str " " 1)
(println (format "%s" _str)))
      (println "No such entry exists in the newLISP manual.")))

Tim Johnson

#11
I've been coding in rebol for 9 years now.

I use a user-defined function (Also called 'def):

That generates a subroutine where all defined 'words

are of scope local to the subroutine. It would be great if

something like that were available in newlisp, but I suspect that

would be impossible with newlisp.

tim
Programmer since 1987. Unix environment.