;+ ; NAME: ; CoolHelp ; ; PURPOSE: ; This object is a wrapper around the ADC_Help (ala 'ch') routine that ; makes available speedy online help for IDL version 5.5. ; ; REFERENCE: ; The text help file 'coolhelp_idl55_help.txt' lists the syntax of each ; (many anyway) IDL routine. It was mangled from the text file ; included in the IDLWAVE Emacs distribution from J.D. Smith. ; ; CATEGORY: ; Programming ; ; SUPERCLASSES: ; MGS_BASEOBJECT ; ; ; INITIALIZATION: ; objref = OBJ_NEW('CoolHelp', [HelpPath = HelpPath], $ ; [File = File], [Brief = Brief]) ; ; ; In addition to the keywords for MGS_BASEOBJECT there are three ; for this object: ; HELPPATH The Path to the help file (default = !PATH) ; FILE The name of the help file (default = 'coolhelp_idl55_help.txt') ; BRIEF Set this keyword to show only the syntax statement. (default = 0) ; NOGUI Set this keyword to suppress the GUI and send the results to the ; output log. (default = 0) ; HISTORY_LENGTH Set this keyword to the default number of entries to ; retain in the History list (default = 10) ; ; PUBLIC METHODS: ; ; See MGS_BASEOBJECT for the usual GET/SET/INIT/etc.methods ; ; QueryRoutine: text = objref->QueryRoutine(['routine_name'], $ ; [ SeeAlso = SeeAlso], [count = count], [/ NoUpDateList] ; Use this method to retrieve the text vector of help text for the string scalar ; 'routine_name' (default = '!CPU') ; KEYWORDS: ; COUNT Set equal to a named variable to return a 1 if the routine_name is found ; and 0 otherwise ; SEEALSO Set equal to a name dvariable to retrieve a string vector of the ; routines liosted under 'SEE ALSO' ; NOUPDATELIST Set this keyword to prevent the widget list in the GUI from being ; updated at inappropriate times. There is no need to use this keyword is you ; are working at the command line rather than the GUI. ; ; ; EXAMPLES: ; ; Intializing the object and accessing it directly ; IDL> o = obj_new('coolhelp') ;initialize ; IDL> helptext = o->QueryRoutine('uniq') ;no GUI involved ; IDL> print, helptext ;messy! ; IDL> o->gui, qr = 'uniq' ;GUI is realized all set to peek at 'qr' the queried routine 'uniq' ; IDL> obj_destroy, o ;cleanup! ; ; Accessing the object via a system variable (!CH) ; ; IDL> ch, 'uniq' ; ; MODIFICATION HISTORY: ; June 2002 Written by Andew Cool and Ben Tupper ; 16 JUNE 2002 BT fixed a number of things ; Fixed buggy duplicate entires for XROI ; Renamed help file to be MAC friendly ; Decreased memory useage by saving navigation markers rather than all of the help text. ; Incorporated Reimar's usage of FILESIZE and FILELINE into a new method called ; MapFile. ; Added search field and button (either press Search Button or ) ; Made it a bit smaller on display. ; Fixed File_Which call to include current directory ; ; 18 JULY 2002 BT ; Added Brief keyword ; Fixed GetPad for *nix platforms. ; 22 JULY 2002 BT ; Added HISTORY (and HISTORY_LENGTH) ; Added reference for source data. ; Added internal Path_Sep for IDL 5.4 users. ; Added ability to mine header info from user procedures. ; Added resizable text box. ; 29 JULY 2002 BT ; Changed behavior of the keyword BRIEF to that which it rightly should be. ; Added NOGUI property. ; Added ParseSyntax method and update the rest of the code to reflect this change. ; Added Brief button to GUI ; ADC 31-Jul-2002 Kludge it check for vector index reversal ; 5 AUG 2002 BT ; Modified widget and button names. ; Fixed Syntax parsing bug - now searches for 'Keyword', 'Example'... lines,too. ; 14 AUG 2002 ADC ; Purged messy 'See Also' entries from help text file. ; ;- ;------- ; Event ;------- PRO CoolHelp_Event, event ;event handler Catch, Error If Error NE 0 Then Begin OK = Error_Message(Traceback = 1) Catch, /Cancel Return EndIf Widget_Control, Event.ID, Get_Uvalue = Info OK = Call_Method(Info.Method, Info.Object, event) Return End ;Event ;------- ; fEvent ;------- FUNCTION CoolHelp_fEvent, event ;event handler Catch, Error If Error NE 0 Then Begin OK = Error_Message(Traceback = 1) Catch, /Cancel Return, 0 EndIf Widget_Control, Event.ID, Get_Uvalue = Info OK = Call_Method(Info.Method, Info.Object, event) Return, 1 End ;fEvent ;------- ; Brief ;------- FUNCTION CoolHelp::Brief, event Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf Self.Brief = KeyWord_Set(Event.Select[0]) helptext = self->QueryRoutine(Self.Recent, /noUpdateHistory, /noUpdateList) Return, 1 END ; Brief ;----- ; ResizeEvent ;----- FUNCTION CoolHelp::ResizeEvent, event ;this method manages user resize events of the widget Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf WIdget_Control, Self.TLB, Get_UValue = info ;how does one resize a text widget? Widget_Control, Self.TextID, scr_xsize = event.x - info.pad[0], $ scr_ysize = event.y- info.pad[1] Return, 1 END ; Resize event ;----- ; OnlineHelp ;------ FUNCTION CoolHelp::OnlineHelp, event ;this method spawns the RSI online help Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf Index = Widget_Info(Self.ListID, /List_Select) OnLine_Help, (*Self.sorted_routine_names)[Index[0]] Return, 1 END ;OnLineHelp ;------ ; SearchEvent ;------ FUNCTION CoolHelp::SearchEvent, event ;this method searches for a routine typed into the text entry field Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf Widget_Control, Self.FieldID, Get_Value = qr ;do something unless the value is null string If StrUpCase(qr) NE '' Then Begin ;find the text-help associated with the selected name helptext = Self->QueryRoutine(qr, count = count) EndIf ;SeeAlso has a value other than null string Widget_Control, Self.FieldID, Set_Value = '' Return, 1 END ;SearchEvent ;------- ; AlphaIndexEvent ;------- FUNCTION CoolHelp::AlphaIndexEvent, event ;this event handles selections from the a-z listing ;the first routine of that letter is promoted to the top of the routine list ;text field is updated ;SeeAlso is updated Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf firstLetter = Self.Beta[event.index[0]] KeyCode = StrUpCase(StrMid(*Self.Sorted_Routine_names, 0,1)) A = Where(FirstLetter EQ KeyCode, cnt) If cnt EQ 0 Then Begin Self->ErrorMessage, 'There are no commands starting with the letter ' + FirstLetter ;Self->ErrorMessage, 'Unable to locate '+ FirstLetter + ' in routine list' Return, 0 EndIf qr = (*Self.Sorted_Routine_names)[A[0]] helpText = Self->QueryRoutine(qr, count = count, /noUpdateHistory) Return, 1 END ;AlphaIndexEvent ;------- ; SeeAlsoEvent ;-------- FUNCTION CoolHelp::SeeAlsoEvent, event ;this handles events from the see Also listing ; the A-Z index list is also updated Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf ;this this the name of the selected item qr = (*Self.SeeAlso)[Event.Index] ;do something unless the value is null string If StrUpCase(qr) NE '' Then Begin ;find the text-help associated with the selected name helptext = Self->QueryRoutine(qr, count = count) EndIf ;SeeAlso has a value other than null string Return, 1 END ;SeeAlsoEvent ;------- ; SeeAlsoEvent ;-------- FUNCTION CoolHelp::HistoryEvent, event ;this handles events from the see Also listing ; the A-Z index list is also updated Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf ;this this the name of the selected item qr = (*Self.History)[Event.Index] ;do something unless the value is null string If StrUpCase(qr) NE '' Then Begin ;find the text-help associated with the selected name helptext = Self->QueryRoutine(qr, count = count) EndIf ;SeeAlso has a value other than null string Return, 1 END ;HistoryEvent ;------- ; ListEvent ;------- FUNCTION CoolHelp::ListEvent, event ;this handles events from the routine listing ; the A-Z index list is also updated Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf ;this this the name of the selected item qr = (*Self.Sorted_Routine_names)[Event.Index] ;find the text-help associated with the selected name helptext = Self->QueryRoutine(qr, count = count, /noUpDateList) Return, 1 END ;ListEvent ;------- ; Dismiss ;------- FUNCTION CoolHelp::Dismiss, event ;handles the dismiss button event Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return,0 EndIf CoolHelp_CleanUpGUI, self.tlb END ;Dismiss ;--------- ; CleanupGUI ;--------- PRO CoolHelp_CleanUpGUI, tlb ;cleans up the gui (if valid) If Widget_Info(tlb, /valid) EQ 1 Then Widget_Control, tlb, /destroy End ;CleanUpGUI ;------- ; BuildGUI ;------- PRO CoolHelp::BuildGUI ;builds the simple gui Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return EndIf ColBase = Widget_Base(Self.TLB, column = 3, /Base_align_center) dummy = widget_base(ColBase, Column = 1, Event_pro = 'CoolHelp_Event' ) beta = '- ' + self.beta + ' -' Self.AlphaIndexID = Widget_List(Dummy, value = Beta, $ xsize = 4, ysize = 28, $ Event_pro = 'CoolHelp_Event', $ uValue = {Object:Self, Method: 'AlphaIndexEvent'}) Self.ListID = Widget_List(ColBase, value = *Self.sorted_routine_names, $ xsize = 30, ysize = 28, $ Event_pro = 'CoolHelp_Event', $ uValue = {Object:Self, Method: 'ListEvent'}) Self.TextID = Widget_Text(ColBase, $ xsize = 50, ysize = 28, value = ' ', /scroll, editable = 1) dummy = Widget_Base(Self.TLB, row = 1, /base_align_center) base = widget_base(dummy, col = 1, /base_align_center) Self.FieldID = CW_Field(base, title = 'Search for ...', /column, $ /Return_Event, $ uValue = {Object:Self, Method:'SearchEvent'}) Widget_Control, Self.FieldID, Editable = 1 Search = Widget_Button(base, value = 'Search', $ Event_pro = 'CoolHelp_Event', $ uValue = {Object:Self, Method:'SearchEvent'}) base = widget_base(dummy, col = 1, /base_align_center) title = widget_Label(base, Value = 'See Also', /Align_Center) Self.SeeAlsoID = Widget_List(base, $ ySize = 5, xSize = 20, $ Event_pro = 'CoolHelp_Event', $ uValue = {Object:Self, Method: 'SeeAlsoEvent'}) base = widget_base(dummy, col = 1, /base_align_center) title = widget_Label(base, Value = 'History', /Align_Center) Self.HistoryID = Widget_List(base, value = *Self.History, $ ySize = 5, xSize = 20, $ Event_pro = 'CoolHelp_Event', $ uValue = {Object:Self, Method: 'HistoryEvent'}) box = widget_base(dummy, /base_align_center, row = 2) Self.ButtonsID = CW_Bgroup( box, ['Brief version only'], $ Set_Value = [Self.Brief], /NonExclusive, $ uValue = {Method: 'Brief', Object: Self}, $ Event_Func = 'CoolHelp_fEvent') base = widget_Base(box, /base_align_Center, col = 2) Case Float(!Version.Release) of 5.5: v = '5.4' Else: v = StrTrim(v,2) EndCase OnLineHelp = Widget_Button(base, $ Value = 'Launch RSI IDL v'+ v+ ' Help', $ uValue = {Method: 'OnlineHelp', Object: Self}, $ Event_pro = 'CoolHelp_Event') DismissButton = Widget_Button(base, Value = 'Dismiss', $ uValue = {Method: 'Dismiss', Object: Self}, $ Event_pro = 'CoolHelp_Event') END ;BUILDGUI ;------- ; GUI ;------- PRO CoolHelp::GUI, qr = qr, Group = Group, _extra = Extra ;call this method to 'pop' the GUI Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return EndIf If Self.NoGUI EQ 1 Then Begin text = self->QueryRoutine(qr, _extra = extra) Return EndIf If Widget_Info(Self.TLB, /Valid) Then Begin If n_elements(qr) GT 0 Then text = Self->QueryRoutine(qr, _Extra = extra) Widget_Control, Self.TLB, /Show Return EndIf ;Group is the group_leader for the TLB Self.TLB = Widget_Base(Group = Group, Column = 1, /base_align_center, $ Event_pro = 'CoolHelp_Event', $ uValue = {Object:Self, Method:'ResizeEvent'}, $ /TLB_SIZE_EVENT, Title = 'Cool Help for IDL v5.5') Self->BuildGUI Widget_Control, Self.TLB, /realize ;update the info text = Self->QueryRoutine(qr, _extra = extra) ;determine how much area is covered by non text widget items ;save that for resizing issues gbase = widget_info(Self.tlb, /geometry) gtext = widget_info(self.textID, /geometry) px = gbase.scr_xsize- gtext.scr_xsize py = gbase.scr_ysize - gtext.scr_ysize Widget_Control, Self.TLB, $ Set_Uvalue = {Object:Self, Method:'ResizeEvent', Pad: [px,py] } XMANAGER, 'CoolHelp_' + Self.Name, Self.TLB, $ Event_Handler = 'CoolHelp_Event', $ CleanUp = 'CoolHelp_CleanUpGUI', $ No_Block = 1 END ;GUI ;------- ; QueryRoutine ;------- FUNCTION CoolHelp::QueryRoutine, qr, SeeAlso = SeeAlso, count = count, $ NoUpDateList = NoUpDateList, NoUpdateHistory = NoUpdateHistory ;this method is the guts of the search routine ;this method returns the text vector for the queried routine name ;the a-z list is also updated ;count = 0 if failure, 1 otherwise ;SeeAlso = a string array of the seeAlso routines Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return, 0 EndIf Count = 0 If n_elements(qr) EQ 0 Then qr = '!CPU' RoutineName = StrUpCase(qr[0]) ;find the location of name in the IDL 5.5 listing (non-alphabetic) rn_index = Where(*self.routines EQ RoutineName, querycnt) ;if not fond, search for user routines if querycnt EQ 0 Then Begin ok = Self->SearchForFile( RoutineName, text = text) If OK EQ 0 Then Begin Self->ErrorMessage, 'Routine '+qr + ' was not found' Return, 0 EndIf text = StrTrim(StrMid(text,1),2) nLines = n_elements(text) EndIf Else Begin ;othereise... start searching for the routine in the IDL 5.5 help file ;determine the begiining and end bytes in the text file start_byte = (*Self.Names_index)[rn_index[0]] If RoutineName EQ 'XROI[2]' Then End_Byte = (File_Info(Self.File)).Size Else $ end_byte = $ (*Self.Names_index)[(rn_index[0]+1) < (n_elements(*Self.Names_Index) -1)]-1 ;read in the help text text = BytArr(End_byte - Start_byte) OpenR, U, Self.File, /Get_LUN Point_LUN, U, Start_Byte ReadU, U, text If text[End_Byte - Start_Byte -1] NE 10B Then text = [text, 10B] ends = Where(text EQ 10B, nLines) text = StrArr(nLines) Point_LUN, U, Start_Byte ReadF, U, text FREE_LUN, U EndElse ;RSI routine or user routine? ;change the current a-z selection FirstLetter = StrUpCase(StrMid(RoutineName, 0,1)) Alpha = Where(FirstLetter EQ Self.Beta, cnt) Count = 1 ;pull out SeeAlso stuff if requested *Self.SeeAlso = [''] A = Where(StrTrim(text,2) EQ 'See Also', alsocount) If alsocount GT 0 Then $ *Self.SeeAlso = StrTrim( StrSplit( text[A[0] + 1], ',', /extract) ,2) If RoutineName NE 'XROI[2]' Then text = text[0:nLines-6] Self.Recent = RoutineName[0] If cnt GT 0 Then Begin ;should the history be updated? If KeyWord_Set(NoUpdateHistory) EQ 0 Then Begin ;check for duplicates A = Where(StrUpCase(*Self.History) EQ RoutineName, hcnt, $ complement = comp, ncomplement = ncomp) If hcnt GT 0 Then Begin *Self.History = [RoutineName, (*Self.History)[comp]] EndIf Else Begin *Self.History = SHIFT(*Self.History,1) (*Self.History)[0]= RoutineName EndElse EndIf If KeyWord_Set(Self.Brief) EQ 1 Then text = Self->ParseSyntax(text) If KeyWord_Set(Self.NoGUI) EQ 0 Then Begin If Widget_Info(Self.AlphaIndexID, /Valid) GT 0 Then $ Widget_Control, Self.AlphaIndexID, Set_List_Select = Alpha[0] If Widget_Info(Self.SeeAlsoID, /Valid) GT 0 Then $ Widget_Control, Self.SeeAlsoID, Set_Value = *Self.SeeAlso If Widget_Info(Self.TextID, /valid) Then $ Widget_Control, Self.TextID, Set_Value = Text If Widget_Info(Self.HistoryID,/Valid) Then $ Widget_Control, Self.HistoryID, Set_Value = *Self.History If KeyWord_Set(NoUpDateList) EQ 0 Then Begin If Widget_Info(Self.ListID, /Valid) GT 0 Then Begin A = Where(*Self.Sorted_Routine_Names EQ qr[0], counter) If Counter GT 0 Then $ Widget_Control, Self.ListID, Set_list_Select= A[0], Set_list_Top= A[0] EndIf ;update list? EndIf ;noupdatelist *not* set EndIf Else For i = 0, n_elements(Text) -1 Do Print, Text[i] EndIf SeeAlso = *Self.SeeAlso Return, text END ;QueryRoutine ;------ ; ParseSyntax ;------ FUNCTION CoolHelp::ParseSyntax, text ;finds the syntax statement for most header formats ;returns the original if the BRIEF keyword is set to 0 Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /cancel Return, '' EndIf ;If Self.Brief EQ 0 Then Return, text Squeezed = StrUpCase(STrTrim(text,2)) If StrMid(Text[0], 0,1) EQ ';' Then Squeezed = StrMid(Squeezed, 1) A = Where(Squeezed EQ 'SYNTAX', acnt) If acnt EQ 0 Then A = Where(Squeezed EQ 'SYNTAX:', acnt) If acnt EQ 0 Then A = Where(Squeezed EQ 'CALLING SEQUENCE', acnt) If acnt EQ 0 Then A = Where(Squeezed EQ 'CALLING SEQUENCE:', acnt) ;the following are incase it's an object If acnt EQ 0 Then A = Where(Squeezed EQ 'CREATION', acnt) If acnt EQ 0 Then A = Where(Squeezed EQ 'CREATION:', acnt) If acnt EQ 0 Then A = Where(Squeezed EQ 'INITIALIZATION', acnt) If acnt EQ 0 Then A = Where(Squeezed EQ 'INITIALIZATION:', acnt) If acnt EQ 0 Then Begin ;Self->ErrorMessage, 'Syntax not found for '+ RoutineName Return, text EndIf Else Begin B = Where(Squeezed EQ 'RETURN VALUE', bcnt) If bcnt EQ 0 Then B = Where(Squeezed EQ 'RETURNED VALUE', bcnt) If bcnt EQ 0 Then B = Where(Squeezed EQ 'ARGUMENTS', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'ARGUMENTS:', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'INPUT ARGUMENTS', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'INPUT ARGUMENTS:', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'INPUTS', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'INPUTS:', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'OPTIONAL INPUTS', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'OPTIONAL INPUTS:', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'KEYWORDS', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'KEYWORDS:', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'OPTIONAL KEYWORDS', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ 'OPTIONAL KEYWORDS:', bcnt) ;when all else fails, find the next blank line If bCnt EQ 0 Then Begin B = Where(Squeezed EQ '', bcnt) If bCnt EQ 0 Then B = Where(Squeezed EQ ' ', bcnt) ;a blank line found? If bCnt GT 0 Then Begin ;where does it fall relative to the beginning? C = Where(B GT A[0], ccnt) if ccnt GT 0 Then Begin ;after the beginning B = B[c[0]] bcnt = 1 EndIf Else Begin ;before the begining - assume that we'll take it all B = n_elements(text) bcnt = 1 endelse EndIf EndIf ;If bCnt EQ 0 or A[0] GE B[0] Then Begin ; Return, text[A[0]+1: *] ;EndIf Else Begin ; Return, text[A[0]+1: B[0]-1] ;EndElse If bCnt EQ 0 Then Begin Return, text[A[0]+1: *] Endif Else Begin If B[0] LE 0 Then Begin Return, text[A[0]+1: A[0]+1] Endif Else Begin ;ADC 31-Jul-2002 Kludge it If B[0]-1 LT A[0]+1 Then B[0] = A[0] + 2 Return, text[A[0]+1: B[0]-1] Endelse Endelse EndElse END ;ParseSyntax ;------ ; SearchForFile ;------ FUNCTION CoolHelp::SearchForFile, qr, text = text ;this method searches for user written files ;with the standard IDL format header Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /Cancel Return, 0 EndIf text = '' RoutineName = StrUpCase(qr) file = FILE_WHICH(!Path, RoutineName + '.pro', /Include_Current_Dir) If file[0] NE '' Then Begin Alpha = ' ' Str = Ptr_NEW(Alpha) On_IOError, Fini OpenR, U, File[0], /Get_LUN Repeat ReadF, U, Alpha Until StrTrim(Alpha) EQ ';+' Repeat Begin ReadF, U, Alpha *Str = [*Str, Alpha] EndRep Until StrTrim(Alpha,2) EQ ';-' Fini: If (FSTAT(U)).Open Then Free_LUN, U EndIf Else Return, 0 Text = *Str Ptr_Free, Str Return, 1 END; SearchForFile ;------- ; Path_Sep ;-------- FUNCTION CoolHelp::Path_Sep ;this method makes it possible to run CoolHelp on IDL 5.4 case StrLowCase(!Version.OS_Family) of 'unix': separator = '/' 'windows': separator = '\' 'macos': separator = ':' Else: Separator = ']' endcase Return, Separator END ;------ ; Help ;------ PRO CoolHelp::Help ;a convenience Help, Self, /Obj End ;Help ;----- ; MapFile ;------ FUNCTION CoolHelp::MapFile Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /Cancel Return, 0 EndIf On_IOERROR,close_it OpenR, lun, Self.file, /GET_LUN ;get the size of the file in bytes Stat = FSTAT(lun) ;make a dummy bytarr for each byte ;and read them in to 'text' (even though its just bytes the first reading) text = BytArr(Stat.Size) ReadU, lun, text ;this idea is taken from Reimar Bauer's FileLine function ;10B indicates the end of a line... so search for the ends (one end per line) If text[Stat.Size-1] NE 10B Then text = [text, 10B] EndLines = Where(text EQ 10B, nLines) StartLines = [0L, EndLines + 1] ;remake temp into the strarr(nLines) text = StrArr(nLines) ;redirect the file pointer to the beginning ;and read in as lines of text Point_LUN, lun, 0 ReadF, lun, text Free_lun,lun ;names_index are the locations within the StrArr by *line* ;actually... the name is in the line following 'NAME:' ;; KR names_index =WHERE(STRMID(text,0,5) EQ 'NAME:') + 1L names_index=where(strpos(text,'NAME:') GE 0) + 1L Self.routines = ptr_new( StrUpCase(StrTrim((Text)[names_index],2) ) ) ;the strlen of each line tells us how many bytes to advance each to ;the beginning of each line + the end of line stuff len = LONG([0L, TOTAL(StrLen(Text) + Self->GetPad(), /Cumulative)]) ;these are the locations within each file of the 'NAME:' flag (actually, the ;line following 'NAME:' flag Self.Names_Index = Ptr_new(len[names_index]) ;sort the routine names for display routine_names_sort_index = SORT(*Self.routines) self.sorted_routine_names = ptr_new((*Self.routines)[routine_names_sort_index]) Close_It: If (FSTAT(lun)).Open EQ 1 Then Begin FREE_LUN, lun Return, 0 EndIf Return, 1 END ; MapFile ;----- ; GetPad ;----- FUNCTION CoolHelp::GetPad ;returns the number of extra bytes per line for CR and LF ;use this padding if the help file comes from an operating ;system other than DOS/Windows Path = StrSplit(self.file, self->path_Sep(),/extract) ;updated by KR Case Path[n_elements(Path)-1] of 'coolhelp_idl55_help.txt': Pad = 2 'help.txt': Pad = 1 Else: Pad = 2 EndCase ;Case Path[n_elements(Path)-1] of ; 'coolhelp_idl55_help.txt': Pad = 2 ; Else: ;EndCase Return, Pad END ; GetPad ;----- ; SetProperty ;----- PRO CoolHelp::SetProperty, brief = brief, NoGUI = NoGUI, $ HISTORY_LENGTH = history_length, $ _Ref_Extra = extra If n_elements(Brief) NE 0 Then Self.Brief = KeyWord_Set(Brief) If n_elements(NoGUI) NE 0 Then Self.NoGUI = KeyWord_Set(NoGUI) hist_len = n_elements(History_Length) prev_len = n_elements(*Self.History) Case 1 of hist_len EQ 0: ;do nothing hist_len EQ prev_len: ;do nothing hist_len GT prev_len: *Self.History = [*Self.History, StrArr(hist_len-prev_len)] hist_len LT prev_len: *Self.History = (*Self.History)[0:(Hist_Len-1)>0] EndCase Self->MGS_BaseObject::SetProperty, _extra = extra End ;SetProperty ;----- ; Init ;----- FUNCTION CoolHelp::Init, qr, $ help_path = help_path,$ Help_File = Help_File, $ History_Length = History_Length, $ Brief = brief, NoGUI = NoGUI, $ _ref_Extra = extra ;qr = an optional scalar string of routine name ;help_path = an optional redirect to the help file location ;help_file = an optional help file name ;history_length = optional history length, default = 5 If Self->MGS_BaseObject::Init(_extra = extra) EQ 0 Then Return, 0 Catch, Error If Error NE 0 Then Begin Self->ErrorMessage Catch, /Cancel Return, 0 EndIf If n_elements(Help_Path) EQ 0 Then Help_Path = !Path If N_elements(Help_File) EQ 0 Then Begin Case 1 of Float(!Version.Release) LE 5.5 : Help_File = 'coolhelp_idl55_help.txt' Else: ;now what? EndCase EndIf Self.file =File_Which(Help_Path[0], Help_File[0], $ /INCLUDE_CURRENT_DIR) If Self.file EQ '' Then Begin Self->ErrorMessage, 'Unable to locate help file!' Return, 0 EndIf ;set up the file navigation OK = Self->MapFile() If OK NE 1 Then Return, 0 ;make an a-z list (plus ! and .) and pad with leading and following dashes ;this seems prettier and less squnchedtogetherinoneplace ;store this list as a property alpha = Bindgen(26) + 65B beta = strarr(26) for i = 0, 25 do beta[i] = string(alpha[i]) Self.Beta = ['!', '.', beta] ;the default query name if n_elements(qr) eq 0 Then qr = '!CPU' If n_elements(History_Length) EQ 0 Then Self.History = Ptr_New(StrArr(10)) Else $ Self.History = Ptr_New(StrArr(History_Length[0])) Self.NoGUI = KeyWord_Set(NoGUI) Self.Brief = KeyWord_Set(Brief) Self.SeeAlso = Ptr_NEW(/Allocate) Return, 1 END ;init ;------- ; CleanUp ;------- PRO CoolHelp::CleanUp If Ptr_Valid(Self.Names_Index) Then Ptr_Free, Self.Names_Index If Ptr_Valid(Self.Routines) Then Ptr_Free, Self.Routines If Ptr_Valid(Self.Sorted_Routine_Names) Then Ptr_Free, Self.Sorted_Routine_Names If Ptr_Valid(Self.SeeAlso) Then Ptr_Free, Self.SeeAlso If Ptr_Valid(Self.History) Then Ptr_Free, Self.History Self->MGS_BaseObject::CleanUp END; Cleanup ;------- ; Definition ;------- PRO CoolHelp__Define Struct = {CoolHelp, $ Inherits MGS_BaseObject, $ TLB: 0L, $ NoGUI: 0, $ ; 0 = GUI ;1 = no GUI Brief: 0, $ ; 0 = full text ; 1 = just the syntax Parse: 0, $ ; 0 = no parsing ;1 = parse out ARGS and KEYWORDS File: '', $ Recent:'', $ HistoryID: 0L, $ History: Ptr_new(), $ FieldID: 0L, $ AlphaIndexID: 0L, $ ;list of a-z (plus ! and .) widget_list Beta: StrArr(28) , $ ;list of letter byte values ListID: 0L, $ ;list of routine names ButtonsID: 0L, $ ;nonexclusive buttons TextID: 0L , $ ;text widget to display help text SeeAlsoID: 0L, $ ;widget_listID of see also routines Names_Index: Ptr_new(), $ ;the index map into help textfile Sorted_Routine_Names: Ptr_new(),$ ;the names of routines sorted Routines: Ptr_new(), $ ;the names of the routines SeeAlso: Ptr_New()} ;a list of SeeAlso values END ;definition