From 1e2cf8e670180e40043d779204d49f02ef59164b Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Thu, 13 Jun 2019 16:17:31 +0200 Subject: [PATCH 1/7] show GAP help in Julia with 'GAP.show_GAP_help' This is a first approximation. The functions in the file `helpstring.g` arose from those in GAP's library file `helpbase.gi`. The idea is to extract the requested information from the text format files of the GAP manuals, and to collect it in a string, also in the case where several matches are found. Currently the following problems are known. - When the last subsection of a section is requested then also the part of the next section (in the same chapter) until the start of its first subsection is shown; apparently the sections themselves have no entry numbers in the sense of `HELP_BOOK_HANDLER.(book.handler).HelpData`. (An example is `SizeScreen`.) - Some pieces of GAP help are very long, an example is the entry for `Size` in the HAP package. On the other hand, duplicate entries are filtered out, which should perhaps also done in GAP's help system. --- pkg/GAPJulia/JuliaInterface/gap/helpstring.g | 536 +++++++++++++++++++ pkg/GAPJulia/JuliaInterface/read.g | 1 + src/gap2.jl | 5 + 3 files changed, 542 insertions(+) create mode 100644 pkg/GAPJulia/JuliaInterface/gap/helpstring.g diff --git a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g new file mode 100644 index 00000000..60c73958 --- /dev/null +++ b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g @@ -0,0 +1,536 @@ +############################################################################# +## +## copied from GAP's 'lib/helpbase.gi', then adjusted +## +## The aim of these functions is to collect the information printed by +## GAP's HELP function in a string instead of printing it to the screen. +## In particular, if several matches are found then their help strings +## are concatenated. +## + + +############################################################################# +## +#F HELP_DESC_BOOKS( ignored... ) . . . . . . . . . . . show available books +## +BindGlobal( "HELP_DESC_BOOKS", function( arg ) + local books; + + books := [" Table of currently available help books", + FILLED_LINE( "short name for ? commands", "Description", '_')]; + Append(books, List(HELP_KNOWN_BOOKS[2], a-> FILLED_LINE(a[1], a[2], ' '))); + return [ true, books ]; +end); + +############################################################################# +## +#F HELP_DESC_CHAPTERS( ) . . . . . . . . . . . . . show all chapters +## +BindGlobal( "HELP_DESC_CHAPTERS", function(book) + local info; + # delegate to handler + info := HELP_BOOK_INFO(book); + if info = fail then + return [ true, [ Concatenation( "#W Help: Book ", book, " not found." ) ] ]; + else + HELP_LAST.BOOK := book; + HELP_LAST.MATCH := 1; + return [ true, HELP_BOOK_HANDLER.(info.handler).ShowChapters(info) ]; + fi; +end); + +############################################################################# +## +#F HELP_DESC_SECTIONS( ) . . . . . . . . . . . . . show all sections +## +BindGlobal( "HELP_DESC_SECTIONS", function(book) + local info; + # delegate to handler + info := HELP_BOOK_INFO(book); + if info = fail then + return [ true, [ Concatenation( "#W Help: Book ", book, " not found." ) ] ]; + else + HELP_LAST.BOOK := book; + HELP_LAST.MATCH := 1; + return [ true, HELP_BOOK_HANDLER.(info.handler).ShowSections(info) ]; + fi; +end); + +############################################################################# +## +#F HELP_DESC_MATCH( ) . . . . . . the core function which finally +## gets the data for displaying the help it +## +## is [book, entrynr] +## +BindGlobal( "HELP_DESC_MATCH", function(match) + local book, entrynr, viewer, hv, pos, type, data, + firstline, nextentrynr, nextdata, lastline, lines; + + book := HELP_BOOK_INFO(match[1]); + entrynr := match[2]; +# viewer:= UserPreference("HelpViewers"); + viewer:= [ "screen" ]; + if HELP_LAST.NEXT_VIEWER = false then + hv := viewer; + else + pos := Position( viewer, HELP_LAST.VIEWER ); + if pos = fail then + hv := viewer; + else + hv := viewer{Concatenation([pos+1..Length(viewer)],[1..pos])}; + fi; + HELP_LAST.NEXT_VIEWER := false; + fi; + data:= fail; + for viewer in hv do + # type of data we need now depends on help viewer + type := HELP_VIEWER_INFO.(viewer).type; + # get the data via appropriate handler + data := HELP_BOOK_HANDLER.(book.handler).HelpData(book, entrynr, type); + if data <> fail then + firstline:= data.start; + nextentrynr:= entrynr; + repeat + nextentrynr:= nextentrynr + 1; + nextdata:= HELP_BOOK_HANDLER.(book.handler).HelpData(book, nextentrynr, type); + until nextdata.start <> firstline or nextdata.lines <> data.lines; + if nextdata.lines = data.lines then + lastline:= nextdata.start - 1; + else + lastline:= fail; + fi; + break; + fi; + HELP_LAST.VIEWER := viewer; + od; + HELP_LAST.BOOK := book; + HELP_LAST.MATCH := entrynr; + HELP_LAST.VIEWER := viewer; + if data <> fail then + if IsString( data.lines ) then + # GAPDoc format manuals + lines:= SplitString( data.lines, "\n" ); + else + # gapmacro.tex format manuals + lines:= data.lines; + fi; + if lastline = fail then + lastline:= Length( lines ); + fi; + return [ true, lines{ [ firstline .. lastline ] } ]; + else + return [ false ]; + fi; +end); + +############################################################################# +## +#F HELP_DESC_PREV_CHAPTER( ) . . . . . . . . show chapter introduction +## +BindGlobal( "HELP_DESC_PREV_CHAPTER", function( arg ) + local info, match; + if HELP_LAST.BOOK = 0 then + return [ true, "Help: no history so far." ]; + fi; + info := HELP_BOOK_INFO(HELP_LAST.BOOK); + match := HELP_BOOK_HANDLER.(info.handler).MatchPrevChap(info, + HELP_LAST.MATCH); + if match[2] = fail then + return [ true, "Help: no match found." ]; + else + HELP_LAST.MATCH := match[2]; + return HELP_DESC_MATCH( match ); + fi; +end); + +############################################################################# +## +#F HELP_DESC_NEXT_CHAPTER( ) . . . . . . . . . . . show next chapter +## +BindGlobal( "HELP_DESC_NEXT_CHAPTER", function( arg ) + local info, match; + if HELP_LAST.BOOK = 0 then + return [ true, [ "Help: no history so far." ] ]; + fi; + info := HELP_BOOK_INFO(HELP_LAST.BOOK); + match := HELP_BOOK_HANDLER.(info.handler).MatchNextChap(info, + HELP_LAST.MATCH); + if match[2] = fail then + return [ true, [ "Help: no match found." ] ]; + else + HELP_LAST.MATCH := match[2]; + return HELP_DESC_MATCH( match ); + fi; +end); + +############################################################################# +## +#F HELP_DESC_PREV( ) . . . . . . . . . . . . . show previous section +## +BindGlobal( "HELP_DESC_PREV", function( arg ) + local info, match; + if HELP_LAST.BOOK = 0 then + return [ true, [ "Help: no history so far." ] ]; + fi; + info := HELP_BOOK_INFO(HELP_LAST.BOOK); + match := HELP_BOOK_HANDLER.(info.handler).MatchPrev(info, + HELP_LAST.MATCH); + if match[2] = fail then + return [ true, [ "Help: no match found." ] ]; + else + HELP_LAST.MATCH := match[2]; + return HELP_DESC_MATCH( match ); + fi; +end); + +############################################################################# +## +#F HELP_DESC_NEXT( ) . . . . . . . . . . . . . . . show next section +## +BindGlobal( "HELP_DESC_NEXT", function( arg ) + local info, match; + if HELP_LAST.BOOK = 0 then + return [ true, [ "Help: no history so far." ] ]; + fi; + info := HELP_BOOK_INFO(HELP_LAST.BOOK); + match := HELP_BOOK_HANDLER.(info.handler).MatchNext(info, + HELP_LAST.MATCH); + if match[2] = fail then + return [ true, [ "Help: no match found." ] ]; + else + HELP_LAST.MATCH := match[2]; + return HELP_DESC_MATCH( match ); + fi; +end); + +############################################################################# +## +#F HELP_DESC_WELCOME( ) . . . . . . . . . . . . show welcome message +## +BindGlobal( "HELP_DESC_WELCOME", function( book ) + return [ true, [ +" Welcome to GAP 4\n", +" Try '?tutorial: The Help system' (without quotes) for an introduction to", +" the help system.", +"", +" '?chapters' and '?sections' will display tables of contents." + ] ]; +end); + + +############################################################################# +## +#F HELP_GET_MATCHES2( , , ) . . . search through +#F the books +## +## This function returns a list of two lists [exact, match] and these lists +## consist of pairs [book, entrynumber], where book is a help book and +## entrynumber is the number of a match in book.entries. As the names say, +## the first list "exact" contains the exact matches and "match" the +## remaining ones. +## +BindGlobal( "HELP_GET_MATCHES2", function( books, topic, frombegin ) + local exact, match, em, b, x, topics, transatl, pair, newtopic, getsecnum; + + # First we try to produce some suggestions for possible different spellings + # (see the global variable 'TRANSATL' for the list of spelling patterns). + if topic = "size" then # "size" is a notable exception (lowercase is guaranteed) + topics:=[ topic ]; + else + topics:=HELP_SEARCH_ALTERNATIVES( topic ); + fi; + + # and contain the topics matching + exact := []; + match := []; + + if IsString(books) or IsRecord(books) then + books := [books]; + fi; + + # collect the matches (by number) + books := List(books, HELP_BOOK_INFO); + for b in books do + for topic in topics do + # now delegate the work to the handler functions + if b<>fail then + em := HELP_BOOK_HANDLER.(b.handler).SearchMatches(b, topic, frombegin); + for x in em[1] do + Add(exact, [b, x]); + od; + for x in em[2] do + Add(match, [b, x]); + od; + fi; + od; + od; + + # different from GAP's function: Do *NOT* join the two lists. + # match := Concatenation(exact, match); + # exact := []; + + # check if all matches point to the same subsection of the same book, + # in that case we only keep the first match which then will be displayed + # immediately + + # this function makes sure that nothing breaks if the help book handler + # has no support for SubsectionNumber + getsecnum := function(m) + if IsBound(HELP_BOOK_HANDLER.(m[1].handler).SubsectionNumber) then + return HELP_BOOK_HANDLER.(m[1].handler).SubsectionNumber(m[1], m[2]); + else + return m[2]; + fi; + end; + if Length(match) > 1 and Length(Set(List(match, + m-> [m[1].bookname,getsecnum(m)]))) = 1 then + match := [match[1]]; + fi; + + return [exact, match]; +end); + + +############################################################################# +## +#F HELP_DESC_MATCHES( , , ) . . . collect matches +## +BindGlobal( "HELP_DESC_MATCHES", function( books, topic, frombegin, onlyexact... ) + local exact, match, x, lines, cnt, i, str, n, sep, known, desc; + + # first get lists of exact and other matches + x := HELP_GET_MATCHES2( books, topic, frombegin ); + exact := x[1]; + if Length( onlyexact ) = 1 and onlyexact[1] = true then + match:= []; + else + match:= x[2]; + fi; + + # no topic found + if 0 = Length(match) and 0 = Length(exact) then + return [ false, [ "Help: no matching entry found" ] ]; + + # one exact or together one topic found + elif 1 = Length(exact) or (0 = Length(exact) and 1 = Length(match)) then + if Length(exact) = 0 then exact := match; fi; + i := exact[1]; + str := Concatenation("Help: Showing `", i[1].bookname,": ", + StripEscapeSequences( i[1].entries[i[2]][1] ), "'"); + # to avoid line breaking when str contains escape sequences: + n := 0; + lines:= []; + while n < Length(str) do + Add( lines, str{[n+1..Minimum(Length(str), + n + QuoInt(SizeScreen()[1] ,2))]} ); + n := n + QuoInt(SizeScreen()[1] ,2); + od; + return [ true, Concatenation( lines, HELP_DESC_MATCH(i)[2] ) ]; + + # more than one topic found, show all entries + else + lines := [ "Help: several entries match this topic", "" ]; + sep:= [ "", RepeatedUTF8String( "─", SizeScreen()[1] ), "" ]; + HELP_LAST.TOPICS:=[]; + # show exact matches first + match := Concatenation(exact, match); + known:= []; + for i in match do + desc:= HELP_DESC_MATCH(i)[2]; + if not desc in known then + Add( lines, Concatenation( i[1].bookname, ":" ) ); + Append( lines, desc ); + Append( lines, sep ); + AddSet( known, desc ); + fi; + Add(HELP_LAST.TOPICS, i); + od; + return [ true, lines ]; + fi; +end); + + +# choosing one of last shown list of matches +BindGlobal( "HELP_DESC_FROM_LAST_TOPICS", function(nr) + if nr = 0 or Length(HELP_LAST.TOPICS) < nr then + return [ false, [ "Help: No such topic." ] ]; + fi; + return [ true, HELP_DESC_MATCH(HELP_LAST.TOPICS[nr]) ]; +end); + + +############################################################################# +## +#F HELP_String( [, ] ) . . . . . deal with a help request +## +DeclareGlobalFunction( "HELP_String" ); + +InstallGlobalFunction( HELP_String, function( str, onlyexact... ) + local origstr, nwostr, p, book, books, move, add, + match; + + onlyexact:= ( Length( onlyexact ) = 1 and onlyexact[1] = true ); + + origstr := ShallowCopy(str); + nwostr := NormalizedWhitespace(origstr); + + # extract the book + p := Position( str, ':' ); + if p <> fail then + book := str{[1..p-1]}; + str := str{[p+1..Length(str)]}; + else + book := ""; + fi; + + # normalizing for search + book := SIMPLE_STRING(book); + str := SIMPLE_STRING(str); + + # we check if `book' MATCH_BEGINs some of the available books + books := Filtered(HELP_KNOWN_BOOKS[1], bn-> MATCH_BEGIN(bn, book)); + if Length(book) > 0 and Length(books) = 0 then + return [ true, [ "Help: None of the available books matches (try: '?books')." ] ]; + fi; + + # function to add a topic to the ring + move := false; + add := function( books, topic ) + if not move then + HELP_RING_IDX := (HELP_RING_IDX+1) mod HELP_RING_SIZE; + HELP_BOOK_RING[HELP_RING_IDX+1] := books; + HELP_TOPIC_RING[HELP_RING_IDX+1] := topic; + fi; + end; + + # if the topic is empty show the last shown one again + if book = "" and str = "" then + if HELP_LAST.BOOK = 0 then + return HELP_String( "Tutorial: Help" ); + else + return HELP_DESC_MATCH( [HELP_LAST.BOOK, HELP_LAST.MATCH] ); + fi; + + # if topic is "&" show last topic again, but with next viewer in viewer + # list, or with last viewer again if there is no next one + elif book = "" and str = "&" and Length(nwostr) = 1 then + if HELP_LAST.BOOK = 0 then + return HELP_String("Tutorial: Help"); + else + HELP_LAST.NEXT_VIEWER := true; + return HELP_DESC_MATCH( [HELP_LAST.BOOK, HELP_LAST.MATCH] ); + fi; + + # if the topic is '-' we are interested in the previous search again + elif book = "" and str = "-" and Length(nwostr) = 1 then + HELP_RING_IDX := (HELP_RING_IDX-1) mod HELP_RING_SIZE; + books := HELP_BOOK_RING[HELP_RING_IDX+1]; + str := HELP_TOPIC_RING[HELP_RING_IDX+1]; + move := true; + + # if the topic is '+' we are interested in the last section again + elif book = "" and str = "+" and Length(nwostr) = 1 then + HELP_RING_IDX := (HELP_RING_IDX+1) mod HELP_RING_SIZE; + books := HELP_BOOK_RING[HELP_RING_IDX+1]; + str := HELP_TOPIC_RING[HELP_RING_IDX+1]; + move := true; + fi; + + # number means topic from HELP_LAST.TOPICS list + if book = "" and ForAll(str, a-> a in "0123456789") then + return HELP_DESC_FROM_LAST_TOPICS(Int(str)); + + # if the topic is '<' we are interested in the one before 'LastTopic' + elif book = "" and str = "<" and Length(nwostr) = 1 then + return HELP_DESC_PREV(); + + # if the topic is '>' we are interested in the one after 'LastTopic' + elif book = "" and str = ">" and Length(nwostr) = 1 then + return HELP_DESC_NEXT(); + + # if the topic is '<<' we are interested in the previous chapter intro + elif book = "" and str = "<<" then + return HELP_DESC_PREV_CHAPTER(); + + # if the topic is '>>' we are interested in the next chapter intro + elif book = "" and str = ">>" then + return HELP_DESC_NEXT_CHAPTER(); + + # if the subject is 'Welcome to GAP' display a welcome message + elif book = "" and str = "welcome to gap" then + str:= HELP_DESC_WELCOME( book ); + if str[1] = true then + add( books, "Welcome to GAP" ); + fi; + return str; + + # if the topic is 'books' display the table of books + elif book = "" and str = "books" then + str:= HELP_DESC_BOOKS(); + if str[1] = true then + add( books, "books" ); + fi; + return str; + + # if the topic is 'chapters' display the table of chapters + elif str = "chapters" or str = "contents" or book <> "" and str = "" then + str:= List( books, HELP_DESC_CHAPTERS ); + if ForAll( str, b -> b[1] = true ) then + add( books, "chapters" ); + fi; + return [ true, Concatenation( List( str, x -> x[2] ) ) ]; + + # if the topic is 'sections' display the table of sections + elif str = "sections" then + str:= List( books, HELP_DESC_SECTIONS ); + if ForAll( str, b -> b[1] = true ) then + add(books, "sections"); + fi; + return [ true, Concatenation( List( str, x -> x[2] ) ) ]; + + # if the topic is '?' search the index for any entries for + # which is a substring (as opposed to an abbreviation) + elif Length(str) > 0 and str[1] = '?' then + str := str{[2..Length(str)]}; + NormalizeWhitespace(str); + match:= HELP_DESC_MATCHES( books, str, false, onlyexact ); + if match[1] = true then + add( books, str ); + fi; + return match; + + # search for this topic + else + match:= HELP_DESC_MATCHES( books, str, true, onlyexact ); + if match[1] = true then + add( books, str ); + return match; + elif origstr in NAMES_SYSTEM_GVARS then + return [ true, [ Concatenation( "Help: '", origstr, "' is currently undocumented." ), + " For details, try ?Undocumented Variables" ] ]; + elif book = "" and + ForAny(HELP_KNOWN_BOOKS[1], bk -> MATCH_BEGIN(bk, str)) then + return [ true, Concatenation( [ Concatenation( + "Help: Are you looking for a certain book? (Trying '?", origstr, + ":' ..." ) ], + HELP_String( Concatenation(origstr, ":") )[2] ) ]; + else + # seems unnecessary, since some message is already printed in all + # cases above (?): + # Print( "Help: Sorry, could not find a match for '", origstr, "'.\n"); + return [ false ]; + fi; + fi; +end); + + +############################################################################# +## +#F HelpString( , ) +## +BindGlobal( "HelpString", function( topic, onlyexact ) + return JoinStringsWithSeparator( HELP_String( topic, onlyexact )[2], "\n" ); +end ); + + diff --git a/pkg/GAPJulia/JuliaInterface/read.g b/pkg/GAPJulia/JuliaInterface/read.g index d0529c26..edff4527 100644 --- a/pkg/GAPJulia/JuliaInterface/read.g +++ b/pkg/GAPJulia/JuliaInterface/read.g @@ -21,3 +21,4 @@ ReadPackage( "JuliaInterface", "gap/adapter.gi"); ReadPackage( "JuliaInterface", "gap/calls.gi"); ReadPackage( "JuliaInterface", "gap/convert.gi"); ReadPackage( "JuliaInterface", "gap/utils.gi"); +ReadPackage( "JuliaInterface", "gap/helpstring.g"); diff --git a/src/gap2.jl b/src/gap2.jl index 59242214..583b3f7e 100644 --- a/src/gap2.jl +++ b/src/gap2.jl @@ -149,3 +149,8 @@ function Display(x::GapObj) error("variable was not correctly evaluated") end end + +function show_GAP_help( topic::String, onlyexact::Bool=false ) + print( GAP.gap_to_julia( GAP.Globals.HelpString( + GAP.julia_to_gap( topic ), onlyexact ) ) ) +end From 2a64fa0722930f234cbde27c7c6fcdff11db601a Mon Sep 17 00:00:00 2001 From: Sebastian Gutsche Date: Mon, 17 Jun 2019 17:19:23 +0200 Subject: [PATCH 2/7] Enable ? help for `GAP.Globals.FOO` --- src/GAP.jl | 1 + src/gap2.jl | 5 ----- src/help.jl | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/help.jl diff --git a/src/GAP.jl b/src/GAP.jl index 8358a493..13a75ef4 100644 --- a/src/GAP.jl +++ b/src/GAP.jl @@ -130,5 +130,6 @@ include( "macros.jl" ) include( "gap_to_julia.jl" ) include( "julia_to_gap.jl" ) include( "utils.jl" ) +include( "help.jl" ) end diff --git a/src/gap2.jl b/src/gap2.jl index 583b3f7e..59242214 100644 --- a/src/gap2.jl +++ b/src/gap2.jl @@ -149,8 +149,3 @@ function Display(x::GapObj) error("variable was not correctly evaluated") end end - -function show_GAP_help( topic::String, onlyexact::Bool=false ) - print( GAP.gap_to_julia( GAP.Globals.HelpString( - GAP.julia_to_gap( topic ), onlyexact ) ) ) -end diff --git a/src/help.jl b/src/help.jl new file mode 100644 index 00000000..6d109c06 --- /dev/null +++ b/src/help.jl @@ -0,0 +1,25 @@ +function GAP_help_string(topic::String, onlyexact::Bool = false) + return GAP.gap_to_julia(GAP.Globals.HelpString(GAP.julia_to_gap(topic), onlyexact)) +end + +function show_GAP_help(topic::String, onlyexact::Bool = false) + print(GAP_help_string(topic, onlyexact)) +end + +import Base.Docs: Binding, getdoc, docstr + +## Create a helper type that gets returned by Binding +struct GAPHelpType + name::Symbol +end + +Base.Docs.Binding(x::GlobalsType, name::Symbol) = GAPHelpType(name) + +function Base.Docs.doc(x::GAPHelpType, typesig::Type = Union{}) + return Text(GAP_help_string(string(x.name))) +end + +## Set getdoc for GlobalsType to nothing, +## so it dispatches on the Binding. +Base.Docs.getdoc(x::GlobalsType) = nothing +Base.Docs.getdoc(x::GapObj) = Text(GAP_help_string(gap_to_julia(Globals.NameFunction(x)))) From 0e9c22664faf070961a3d4bd43047be6f713fbcb Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 21 Jun 2019 18:03:06 +0200 Subject: [PATCH 3/7] added some tests for help requests The tests cover the situation where one asks for help about a topic, and where an exact match is found or just partial matches are found or no matches are found at all. There is code in `helpstring.g` which cannot be reached via these requests, such as requests for the next or previous topic in a manual (which do not make sense in the current setup for Julia), but I wanted to have a complete "string returning" variant of GAP's `helpbase.gi`. --- pkg/GAPJulia/JuliaInterface/gap/helpstring.g | 5 +---- pkg/GAPJulia/JuliaInterface/tst/help.tst | 17 +++++++++++++++++ test/help.jl | 9 +++++++++ test/runtests.jl | 1 + 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 pkg/GAPJulia/JuliaInterface/tst/help.tst create mode 100644 test/help.jl diff --git a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g index 60c73958..54291ff1 100644 --- a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g +++ b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g @@ -516,10 +516,7 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) ":' ..." ) ], HELP_String( Concatenation(origstr, ":") )[2] ) ]; else - # seems unnecessary, since some message is already printed in all - # cases above (?): - # Print( "Help: Sorry, could not find a match for '", origstr, "'.\n"); - return [ false ]; + return match; fi; fi; end); diff --git a/pkg/GAPJulia/JuliaInterface/tst/help.tst b/pkg/GAPJulia/JuliaInterface/tst/help.tst new file mode 100644 index 00000000..4e1d976e --- /dev/null +++ b/pkg/GAPJulia/JuliaInterface/tst/help.tst @@ -0,0 +1,17 @@ +#@local HelpTestFunction +gap> START_TEST( "help.tst" ); + +# +gap> HelpTestFunction:= topic -> IsString( HelpString( topic, false ) ) and +> IsString( HelpString( topic, true ) );; + +# +gap> HelpTestFunction( "IsObject" ); +true +gap> HelpTestFunction( "Unknow" ); +true +gap> HelpTestFunction( "something for which no match is found" ); +true + +# +gap> STOP_TEST( "help.tst" ); diff --git a/test/help.jl b/test/help.jl new file mode 100644 index 00000000..7b6a89d8 --- /dev/null +++ b/test/help.jl @@ -0,0 +1,9 @@ +@testset "help" begin + @test isa( GAP.GAP_help_string( "IsObject" ), String ) + @test isa( GAP.GAP_help_string( "IsObject", true ), String ) + @test isa( GAP.GAP_help_string( "unknow" ), String ) + @test isa( GAP.GAP_help_string( "unknow", true ), String ) + @test isa( GAP.GAP_help_string( "something for which no match is found" ), String ) + @test isa( GAP.GAP_help_string( "something for which no match is found", true ), String ) +end + diff --git a/test/runtests.jl b/test/runtests.jl index 23285eeb..aeeec921 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,3 +6,4 @@ include("basics.jl") include("convenience.jl") include("conversion.jl") include("macros.jl") +include("help.jl") From 8c24b62acaad00502d687f4a3499df0122965ba2 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Tue, 25 Jun 2019 17:07:20 +0200 Subject: [PATCH 4/7] some improvements in extracting GAP help strings - fixed the computation of the end lines of subsections - changed input and output format of `HELP_String` - added more tests --- pkg/GAPJulia/JuliaInterface/gap/helpstring.g | 123 ++++++++++++------- pkg/GAPJulia/JuliaInterface/tst/help.tst | 44 ++++++- test/help.jl | 32 ++++- 3 files changed, 146 insertions(+), 53 deletions(-) diff --git a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g index 54291ff1..02e7907e 100644 --- a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g +++ b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g @@ -35,6 +35,8 @@ BindGlobal( "HELP_DESC_CHAPTERS", function(book) else HELP_LAST.BOOK := book; HELP_LAST.MATCH := 1; + # The second entry can be a string or a list of strings + # or a record with the components 'lines' and 'start'. return [ true, HELP_BOOK_HANDLER.(info.handler).ShowChapters(info) ]; fi; end); @@ -52,6 +54,8 @@ BindGlobal( "HELP_DESC_SECTIONS", function(book) else HELP_LAST.BOOK := book; HELP_LAST.MATCH := 1; + # The second entry can be a string or a list of strings + # or a record with the components 'lines' and 'start'. return [ true, HELP_BOOK_HANDLER.(info.handler).ShowSections(info) ]; fi; end); @@ -65,7 +69,7 @@ end); ## BindGlobal( "HELP_DESC_MATCH", function(match) local book, entrynr, viewer, hv, pos, type, data, - firstline, nextentrynr, nextdata, lastline, lines; + nextn, nextentry, firstline, lastline, lines; book := HELP_BOOK_INFO(match[1]); entrynr := match[2]; @@ -89,16 +93,23 @@ BindGlobal( "HELP_DESC_MATCH", function(match) # get the data via appropriate handler data := HELP_BOOK_HANDLER.(book.handler).HelpData(book, entrynr, type); if data <> fail then + # Find the end of the subsection in question. + # This is defined either by the start of the next subsection + # of the same section, or by the start of the next section or chapter. + nextn:= book.entries[ entrynr ][3] + [ 0, 0, 1 ]; + nextentry:= PositionProperty( book.entries, x -> x[3] = nextn ); + if nextentry = fail then + nextn:= nextn + [ 0, 1, -nextn[3] ]; + nextentry:= PositionProperty( book.entries, x -> x[3] = nextn ); + fi; firstline:= data.start; - nextentrynr:= entrynr; - repeat - nextentrynr:= nextentrynr + 1; - nextdata:= HELP_BOOK_HANDLER.(book.handler).HelpData(book, nextentrynr, type); - until nextdata.start <> firstline or nextdata.lines <> data.lines; - if nextdata.lines = data.lines then - lastline:= nextdata.start - 1; - else + if nextentry = fail then lastline:= fail; + else + # Just taking 'book.entries[ nextentry ][4]' as the startline + # would not be correct. + lastline:= HELP_BOOK_HANDLER.( book.handler ).HelpData( book, + nextentry, type ).start - 1; fi; break; fi; @@ -120,7 +131,7 @@ BindGlobal( "HELP_DESC_MATCH", function(match) fi; return [ true, lines{ [ firstline .. lastline ] } ]; else - return [ false ]; + return [ false, [] ]; fi; end); @@ -131,13 +142,13 @@ end); BindGlobal( "HELP_DESC_PREV_CHAPTER", function( arg ) local info, match; if HELP_LAST.BOOK = 0 then - return [ true, "Help: no history so far." ]; + return [ true, [ "Help: no history so far." ] ]; fi; info := HELP_BOOK_INFO(HELP_LAST.BOOK); match := HELP_BOOK_HANDLER.(info.handler).MatchPrevChap(info, HELP_LAST.MATCH); if match[2] = fail then - return [ true, "Help: no match found." ]; + return [ true, [ "Help: no match found." ] ]; else HELP_LAST.MATCH := match[2]; return HELP_DESC_MATCH( match ); @@ -206,9 +217,9 @@ end); ############################################################################# ## -#F HELP_DESC_WELCOME( ) . . . . . . . . . . . . show welcome message +#F HELP_DESC_WELCOME() . . . . . . . . . . . . . . . . show welcome message ## -BindGlobal( "HELP_DESC_WELCOME", function( book ) +BindGlobal( "HELP_DESC_WELCOME", function() return [ true, [ " Welcome to GAP 4\n", " Try '?tutorial: The Help system' (without quotes) for an introduction to", @@ -356,22 +367,25 @@ BindGlobal( "HELP_DESC_FROM_LAST_TOPICS", function(nr) if nr = 0 or Length(HELP_LAST.TOPICS) < nr then return [ false, [ "Help: No such topic." ] ]; fi; - return [ true, HELP_DESC_MATCH(HELP_LAST.TOPICS[nr]) ]; + return [ true, HELP_DESC_MATCH(HELP_LAST.TOPICS[nr])[2] ]; end); ############################################################################# ## -#F HELP_String( [, ] ) . . . . . deal with a help request +#F HELP_String( , ) . . . . . . deal with a help request ## +## The return value is a list. +## Each of its entries is either a list of strings +## or a record with the components 'lines' (a string or a list of strings) +## and 'start' (the position of the first line to show). +## DeclareGlobalFunction( "HELP_String" ); -InstallGlobalFunction( HELP_String, function( str, onlyexact... ) +InstallGlobalFunction( HELP_String, function( str, onlyexact ) local origstr, nwostr, p, book, books, move, add, match; - onlyexact:= ( Length( onlyexact ) = 1 and onlyexact[1] = true ); - origstr := ShallowCopy(str); nwostr := NormalizedWhitespace(origstr); @@ -391,7 +405,7 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) # we check if `book' MATCH_BEGINs some of the available books books := Filtered(HELP_KNOWN_BOOKS[1], bn-> MATCH_BEGIN(bn, book)); if Length(book) > 0 and Length(books) = 0 then - return [ true, [ "Help: None of the available books matches (try: '?books')." ] ]; + return [ [ "Help: None of the available books matches (try: '?books')." ] ]; fi; # function to add a topic to the ring @@ -407,19 +421,19 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) # if the topic is empty show the last shown one again if book = "" and str = "" then if HELP_LAST.BOOK = 0 then - return HELP_String( "Tutorial: Help" ); + return HELP_String( "Tutorial: Help", onlyexact ); else - return HELP_DESC_MATCH( [HELP_LAST.BOOK, HELP_LAST.MATCH] ); + return [ HELP_DESC_MATCH( [HELP_LAST.BOOK, HELP_LAST.MATCH] )[2] ]; fi; # if topic is "&" show last topic again, but with next viewer in viewer # list, or with last viewer again if there is no next one elif book = "" and str = "&" and Length(nwostr) = 1 then if HELP_LAST.BOOK = 0 then - return HELP_String("Tutorial: Help"); + return HELP_String( "Tutorial: Help", onlyexact ); else HELP_LAST.NEXT_VIEWER := true; - return HELP_DESC_MATCH( [HELP_LAST.BOOK, HELP_LAST.MATCH] ); + return [ HELP_DESC_MATCH( [HELP_LAST.BOOK, HELP_LAST.MATCH] )[2] ]; fi; # if the topic is '-' we are interested in the previous search again @@ -439,31 +453,31 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) # number means topic from HELP_LAST.TOPICS list if book = "" and ForAll(str, a-> a in "0123456789") then - return HELP_DESC_FROM_LAST_TOPICS(Int(str)); + return [ HELP_DESC_FROM_LAST_TOPICS(Int(str))[2] ]; # if the topic is '<' we are interested in the one before 'LastTopic' elif book = "" and str = "<" and Length(nwostr) = 1 then - return HELP_DESC_PREV(); + return [ HELP_DESC_PREV()[2] ]; # if the topic is '>' we are interested in the one after 'LastTopic' elif book = "" and str = ">" and Length(nwostr) = 1 then - return HELP_DESC_NEXT(); + return [ HELP_DESC_NEXT()[2] ]; # if the topic is '<<' we are interested in the previous chapter intro elif book = "" and str = "<<" then - return HELP_DESC_PREV_CHAPTER(); + return [ HELP_DESC_PREV_CHAPTER()[2] ]; # if the topic is '>>' we are interested in the next chapter intro elif book = "" and str = ">>" then - return HELP_DESC_NEXT_CHAPTER(); + return [ HELP_DESC_NEXT_CHAPTER()[2] ]; # if the subject is 'Welcome to GAP' display a welcome message elif book = "" and str = "welcome to gap" then - str:= HELP_DESC_WELCOME( book ); + str:= HELP_DESC_WELCOME(); if str[1] = true then add( books, "Welcome to GAP" ); fi; - return str; + return [ str[2] ]; # if the topic is 'books' display the table of books elif book = "" and str = "books" then @@ -471,7 +485,7 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) if str[1] = true then add( books, "books" ); fi; - return str; + return [ str[2] ]; # if the topic is 'chapters' display the table of chapters elif str = "chapters" or str = "contents" or book <> "" and str = "" then @@ -479,7 +493,7 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) if ForAll( str, b -> b[1] = true ) then add( books, "chapters" ); fi; - return [ true, Concatenation( List( str, x -> x[2] ) ) ]; + return List( str, x -> x[2] ); # if the topic is 'sections' display the table of sections elif str = "sections" then @@ -487,7 +501,7 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) if ForAll( str, b -> b[1] = true ) then add(books, "sections"); fi; - return [ true, Concatenation( List( str, x -> x[2] ) ) ]; + return List( str, x -> x[2] ); # if the topic is '?' search the index for any entries for # which is a substring (as opposed to an abbreviation) @@ -498,25 +512,25 @@ InstallGlobalFunction( HELP_String, function( str, onlyexact... ) if match[1] = true then add( books, str ); fi; - return match; + return [ match[2] ]; # search for this topic else match:= HELP_DESC_MATCHES( books, str, true, onlyexact ); if match[1] = true then add( books, str ); - return match; + return [ match[2] ]; elif origstr in NAMES_SYSTEM_GVARS then - return [ true, [ Concatenation( "Help: '", origstr, "' is currently undocumented." ), + return [ [ Concatenation( "Help: '", origstr, "' is currently undocumented." ), " For details, try ?Undocumented Variables" ] ]; elif book = "" and ForAny(HELP_KNOWN_BOOKS[1], bk -> MATCH_BEGIN(bk, str)) then - return [ true, Concatenation( [ Concatenation( + return Concatenation( [ [ Concatenation( "Help: Are you looking for a certain book? (Trying '?", origstr, - ":' ..." ) ], - HELP_String( Concatenation(origstr, ":") )[2] ) ]; + ":' ...)" ) ] ], + HELP_String( Concatenation( origstr, ":" ), onlyexact ) ); else - return match; + return [ match[2] ]; fi; fi; end); @@ -524,10 +538,31 @@ end); ############################################################################# ## -#F HelpString( , ) +#F HelpString( [, ] ) ## -BindGlobal( "HelpString", function( topic, onlyexact ) - return JoinStringsWithSeparator( HELP_String( topic, onlyexact )[2], "\n" ); +BindGlobal( "HelpString", function( topic, onlyexact... ) + local res, entry, lines; + + onlyexact:= ( Length( onlyexact ) = 1 and onlyexact[1] = true ); + + res:= ""; + for entry in HELP_String( topic, onlyexact ) do + if IsRecord( entry ) then + lines:= entry.lines; + if IsString( lines ) then + lines:= SplitString( lines, "\n" ); + fi; + Append( res, JoinStringsWithSeparator( + lines{ [ entry.start .. Length( lines ) ] }, + "\n" ) ); + elif IsList( entry ) and ForAll( entry, IsString ) then + Append( res, JoinStringsWithSeparator( entry, "\n" ) ); + else + Error( " must be a record or a list of strings" ); + fi; + od; + + return res; end ); diff --git a/pkg/GAPJulia/JuliaInterface/tst/help.tst b/pkg/GAPJulia/JuliaInterface/tst/help.tst index 4e1d976e..fde9838f 100644 --- a/pkg/GAPJulia/JuliaInterface/tst/help.tst +++ b/pkg/GAPJulia/JuliaInterface/tst/help.tst @@ -5,10 +5,48 @@ gap> START_TEST( "help.tst" ); gap> HelpTestFunction:= topic -> IsString( HelpString( topic, false ) ) and > IsString( HelpString( topic, true ) );; -# -gap> HelpTestFunction( "IsObject" ); +# navigate in the help +gap> HelpTestFunction( "" ); # first help access +true +gap> HelpTestFunction( "" ); # show the last shown entry again +true +gap> HelpTestFunction( "&" ); # show the last shown entry again +true +gap> HelpTestFunction( "-" ); # show the previous entry in help history +true +gap> HelpTestFunction( "+" ); # show the next entry in help history +true +gap> HelpTestFunction( "<" ); # show the topic before the last shown one +true +gap> HelpTestFunction( "<<" ); # show the last topic's chapter's start +true +gap> HelpTestFunction( ">" ); # show the topic after the last shown one +true +gap> HelpTestFunction( ">>" ); # show the next chapter's start +true +gap> HelpTestFunction( "welcome to gap" ); # show welcome info +true + +# substring search +gap> HelpTestFunction( "?determinant" ); +true + +# ask for overviews +gap> HelpTestFunction( "books" ); +true +gap> HelpTestFunction( "tut:chapters" ); +true +gap> HelpTestFunction( "tut:sections" ); +true + +# ask for help about topics +gap> HelpTestFunction( "isobject" ); +true +gap> HelpTestFunction( "tut:isobject" ); +true +gap> HelpTestFunction( "ref:isobject" ); true -gap> HelpTestFunction( "Unknow" ); +gap> HelpTestFunction( "unknow" ); true gap> HelpTestFunction( "something for which no match is found" ); true diff --git a/test/help.jl b/test/help.jl index 7b6a89d8..5004f5cc 100644 --- a/test/help.jl +++ b/test/help.jl @@ -1,9 +1,29 @@ @testset "help" begin - @test isa( GAP.GAP_help_string( "IsObject" ), String ) - @test isa( GAP.GAP_help_string( "IsObject", true ), String ) - @test isa( GAP.GAP_help_string( "unknow" ), String ) - @test isa( GAP.GAP_help_string( "unknow", true ), String ) - @test isa( GAP.GAP_help_string( "something for which no match is found" ), String ) - @test isa( GAP.GAP_help_string( "something for which no match is found", true ), String ) + function test_gap_help( topic::String ) + return isa( GAP.GAP_help_string( topic ), String ) && + isa( GAP.GAP_help_string( topic, true ), String ) + end + + @test test_gap_help( "" ) + @test test_gap_help( "&" ) + @test test_gap_help( "-" ) + @test test_gap_help( "+" ) + @test test_gap_help( "<" ) + @test test_gap_help( "<<" ) + @test test_gap_help( ">" ) + @test test_gap_help( ">>" ) + @test test_gap_help( "welcome to gap" ) + + @test test_gap_help( "?determinant" ) + + @test test_gap_help( "books" ) + @test test_gap_help( "tut:chapters" ) + @test test_gap_help( "tut:sections" ) + + @test test_gap_help( "isobject" ) + @test test_gap_help( "tut:isobject" ) + @test test_gap_help( "ref:isobject" ) + @test test_gap_help( "unknow" ) + @test test_gap_help( "something for which no match is found" ) end From 9a77160696d47aee69ea666b498d012cda8df59b Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 28 Jun 2019 14:59:18 +0200 Subject: [PATCH 5/7] several fixes - If a `.txt` file is missing then the `HelpData` result has no component `start`. - Some entries in `book.entries` store strings in their first position, not numbers; be aware of this when navigating to the next entry. - If there is exactly one exact match then do not suppress partial matches. (This does not happen inside GAP because partial matches are joined with the exact matches; but then one cannot restrict the search to exact matches.) --- pkg/GAPJulia/JuliaInterface/gap/helpstring.g | 69 +++++++++++++------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g index 02e7907e..44182c44 100644 --- a/pkg/GAPJulia/JuliaInterface/gap/helpstring.g +++ b/pkg/GAPJulia/JuliaInterface/gap/helpstring.g @@ -96,20 +96,30 @@ BindGlobal( "HELP_DESC_MATCH", function(match) # Find the end of the subsection in question. # This is defined either by the start of the next subsection # of the same section, or by the start of the next section or chapter. - nextn:= book.entries[ entrynr ][3] + [ 0, 0, 1 ]; + nextn:= book.entries[ entrynr ][3] + [ ,, 1 ]; nextentry:= PositionProperty( book.entries, x -> x[3] = nextn ); if nextentry = fail then - nextn:= nextn + [ 0, 1, -nextn[3] ]; + nextn:= nextn + [ , 1, -nextn[3] ]; nextentry:= PositionProperty( book.entries, x -> x[3] = nextn ); fi; - firstline:= data.start; + if IsBound( data.start ) then + firstline:= data.start; + else + # Perhaps the '.txt' file is not available. + firstline:= 1; + fi; if nextentry = fail then lastline:= fail; else # Just taking 'book.entries[ nextentry ][4]' as the startline # would not be correct. lastline:= HELP_BOOK_HANDLER.( book.handler ).HelpData( book, - nextentry, type ).start - 1; + nextentry, type ); + if IsBound( lastline.start ) then + lastline:= lastline.start - 1; + else + lastline:= fail; + fi; fi; break; fi; @@ -323,25 +333,31 @@ BindGlobal( "HELP_DESC_MATCHES", function( books, topic, frombegin, onlyexact... if 0 = Length(match) and 0 = Length(exact) then return [ false, [ "Help: no matching entry found" ] ]; - # one exact or together one topic found - elif 1 = Length(exact) or (0 = Length(exact) and 1 = Length(match)) then - if Length(exact) = 0 then exact := match; fi; - i := exact[1]; - str := Concatenation("Help: Showing `", i[1].bookname,": ", - StripEscapeSequences( i[1].entries[i[2]][1] ), "'"); - # to avoid line breaking when str contains escape sequences: - n := 0; - lines:= []; - while n < Length(str) do - Add( lines, str{[n+1..Minimum(Length(str), - n + QuoInt(SizeScreen()[1] ,2))]} ); - n := n + QuoInt(SizeScreen()[1] ,2); - od; - return [ true, Concatenation( lines, HELP_DESC_MATCH(i)[2] ) ]; - - # more than one topic found, show all entries +# # one exact or together one topic found +# elif 1 = Length(exact) or (0 = Length(exact) and 1 = Length(match)) then +# if Length(exact) = 0 then exact := match; fi; +# i := exact[1]; +# str := Concatenation("Help: Showing `", i[1].bookname,": ", +# StripEscapeSequences( i[1].entries[i[2]][1] ), "'"); +# # to avoid line breaking when str contains escape sequences: +# n := 0; +# lines:= []; +# while n < Length(str) do +# Add( lines, str{[n+1..Minimum(Length(str), +# n + QuoInt(SizeScreen()[1] ,2))]} ); +# n := n + QuoInt(SizeScreen()[1] ,2); +# od; +# return [ true, Concatenation( lines, HELP_DESC_MATCH(i)[2] ) ]; +# +# # more than one topic found, show all entries else - lines := [ "Help: several entries match this topic", "" ]; + if 1 = Length(exact) or (0 = Length(exact) and 1 = Length(match)) then + # one topic found + lines:= []; + else + # more than one topic found, show all entries + lines := [ "Help: several entries match this topic", "" ]; + fi; sep:= [ "", RepeatedUTF8String( "─", SizeScreen()[1] ), "" ]; HELP_LAST.TOPICS:=[]; # show exact matches first @@ -541,7 +557,7 @@ end); #F HelpString( [, ] ) ## BindGlobal( "HelpString", function( topic, onlyexact... ) - local res, entry, lines; + local res, entry, lines, start; onlyexact:= ( Length( onlyexact ) = 1 and onlyexact[1] = true ); @@ -552,8 +568,13 @@ BindGlobal( "HelpString", function( topic, onlyexact... ) if IsString( lines ) then lines:= SplitString( lines, "\n" ); fi; + if IsBound( entry.start ) then + start:= entry.start; + else + start:= 1; + fi; Append( res, JoinStringsWithSeparator( - lines{ [ entry.start .. Length( lines ) ] }, + lines{ [ start .. Length( lines ) ] }, "\n" ) ); elif IsList( entry ) and ForAll( entry, IsString ) then Append( res, JoinStringsWithSeparator( entry, "\n" ) ); From 3b0db3bea747b8ac5673610cb5eb27b4bc9ba412 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 3 Jul 2019 22:41:06 +0200 Subject: [PATCH 6/7] test/help.jl: Lookup something in the JuliaInterface manual --- test/help.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/help.jl b/test/help.jl index 5004f5cc..f928b9f2 100644 --- a/test/help.jl +++ b/test/help.jl @@ -15,6 +15,8 @@ @test test_gap_help( "welcome to gap" ) @test test_gap_help( "?determinant" ) + @test test_gap_help( "?IsJuliaWrapper" ) + println(GAP.GAP_help_string( "?IsJuliaWrapper" )) @test test_gap_help( "books" ) @test test_gap_help( "tut:chapters" ) From f9748026ff22e4fb3ec58bb960d7059b727471ed Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 8 Jul 2019 15:01:50 +0200 Subject: [PATCH 7/7] Travis: run Julia tests before GAP tests --- etc/travis_test.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/travis_test.sh b/etc/travis_test.sh index d1e7641b..2520507b 100755 --- a/etc/travis_test.sh +++ b/etc/travis_test.sh @@ -13,6 +13,10 @@ git diff --exit-code -- . # detect if there are any diffs # GAP="${HOME}/.julia/gap -A --quitonbreak --norepl" +# +pwd +julia -e 'using Pkg ; Pkg.test("GAP"; coverage=true)' || AnyFailures=Yes + # cd ${TRAVIS_BUILD_DIR}/pkg/GAPJulia/JuliaInterface pwd @@ -29,10 +33,6 @@ ${GAP} --cover ${TRAVIS_BUILD_DIR}/coverage/JuliaExperimental.coverage tst/testa gcov -o $HOME/.julia/packages/GAP/*/pkg/GAPJulia/JuliaExperimental/gen/src/.libs src/*.c* cd .. -# -pwd -julia -e 'using Pkg ; Pkg.test("GAP"; coverage=true)' || AnyFailures=Yes - if [ ${AnyFailures} = Yes ] then exit 1