home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR8 / FOLD11.ZIP / FOLD.S < prev    next >
Text File  |  1993-08-06  |  18KB  |  609 lines

  1. /* IF THIS MAKRO IS USED UNCHANGED, THE CLOSED FOLDS CAN BE OPENED WITH
  2.    CTRL-F12 AND CLOSED WITH CTRL-F11 */
  3.  
  4. //{{{ Title
  5. //
  6. // FOLD.S
  7. //
  8. // Version: 1.1 english / 06.08.1993
  9. //
  10. // Macro for TSE as folding editor
  11. //
  12. // Copyright (C) 1993 by Dirk Wissmann
  13. //
  14. // Bugfixes / Additional help:
  15. //
  16. // David Mayerovitch (file-status-bug)
  17. //    E-Mail: david.mayerovitch@canrem.com
  18. //
  19. //}}}
  20. //{{{ Introduction
  21. //
  22. // This Sourcefile ist at the same time an example for WHAT using
  23. // folds is able to do. The structure becomes somehow obvious...
  24. //
  25. // Closed folds are marked by three POINTS followed by a brief
  26. // description. Opening them is done by the procedure OpenFold.
  27. // Open folds are marked by user-defined character-strings.
  28. //
  29. // HINT: Please don't use the character "." (Ascii 46) inside the
  30. // description of any fold - it only causes much much trouble.
  31. //
  32. //}}}
  33. //{{{ Known Bugs
  34. //
  35. // Known Bugs in version 1.1:
  36. //
  37. // If you load a new file, where one or more folds have the identical
  38. // description as in an already loaded file, the contents of the fold
  39. // of the already loaded file are completely lost without a chance of
  40. // restoring. Until now, I don't have any idea how to prevent this.
  41. //
  42. // OpenAllClosedFolds doesn't work correct, when a fold is placed in
  43. // the topmost column (column 1 thus). There is no data lost, but it
  44. // is possible, that this fold is placed at a random place inside the
  45. // text.
  46. //
  47. // There is no protection for the folding-lines, thus if someone changes
  48. // the Line starting with the <closedfold> characters, he should know, that
  49. // TSE is perhaps not in state to find the internal buffer. The reason is,
  50. // that the description of the fold is taken as reference-name for this
  51. // internal system buffer. Overwriting lines starting with <startfold>
  52. // characters is not so harmful, but I advise you, NOT to do this.
  53. // ("Enter at your own risk" - B.Simpson)
  54. //
  55. // Nested folds are not possible yet. It would be too complex for me at the
  56. // moment to implement this feature. But if you absolutely want it, there
  57. // could be a dirty workaround, but I'm not sure, if it really works
  58. // (especially while initial closing or final opening of all folds for
  59. // saving the file): create one fold with a name, let's say "louie". Then,
  60. // WITHIN this fold create some empty lines, and then create another fold
  61. // with another name, let's say "foo". When you finished your work in
  62. // "foo", close this fold, and after finishing work in "louie", close this
  63. // fold too. Opening now must happen in reverse order: first open "louie",
  64. // then open "foo" - voilà, it should have worked. But I recommend you,
  65. // better NOT to do such things - leaving the editor would DEFINITELY
  66. // destroy "foo", I think.
  67. //
  68. //}}}
  69. //{{{ Improvements and new versions
  70. //
  71. // Improvements, new versions:
  72. //
  73. // If I find the time, I'm surely interested in improving my macro. I
  74. // think, in one of the next versions, the menu-driven configuration will
  75. // be implemented. I also will _try_ to implement nested folds, but that's
  76. // really complex, so this will take some time. Finally, in one of the next
  77. // versions, there will be a function to DEactivate the macro.
  78. //
  79. // If someone has suggestions or has done changes in sourcecode - please
  80. // send them to me (see below for my email-addresses).
  81. //
  82. // Improvements done so far:
  83. //
  84. // ---------------------------- Version 1.1 -----------------------
  85. // * David Mayerovitch has fixed the problem, that even if there were
  86. //   no changes at all, the editor always thought, there WERE some
  87. //   changes (caused by the use of system-buffers).
  88. //
  89. // * I slightly changed the key-assignment and added some keys.
  90. //   New: keys to open or close all folds with one keystroke, and
  91. //   a key to deactivate the macro (see below)
  92. //
  93. // * I added a function to deactivate the macro now. Before it is
  94. //   deactivated, all folds are opened, so there should be no loss
  95. //   of data.
  96. //
  97. //}}}
  98. //{{{ Copyright
  99. //
  100. // For those, who didn's open the fold "Title" in this source:
  101. // this macro is Copyrighted. For more details see the file
  102. // READ.ME, which should be found in this archive.
  103. //
  104. //}}}
  105.  
  106. //{{{ Global variables
  107.  
  108. string closedfold[6] = " ..."  // Alt-255 followed by 3 dots
  109. string startfold[6] = "{{{"
  110. string endfold[6] = "}}}"
  111. string startcomment[6] = "%"
  112. string endcomment[6] = ""
  113. integer create_history_num = 1
  114.  
  115. //}}}
  116.  
  117. //{{{ Function IsClosedFold
  118.  
  119. // IsClosedFold determines, if the current Cursorline could be
  120. // a closed fold. Returns 1, if yes, else 0.
  121.  
  122. integer proc IsClosedFold()
  123.     string foldline[6] = ""
  124.     integer result = 0
  125.  
  126.     foldline = GetText(1,Length(closedfold))
  127.     result = (foldline == closedfold)
  128.     return(result)
  129. end IsClosedFold
  130.  
  131. //}}}
  132. //{{{ Function IsOpenFold
  133.  
  134. // IsOpenFold determines, if the current Cursorline could be
  135. // an opened fold. Returns 1, if yes, else 0.
  136.  
  137. integer proc IsOpenFold()
  138.     string foldline[12] = ""
  139.     integer result = 0
  140.     string openfold[12] = ""
  141.  
  142.     openfold = startcomment + startfold
  143.     foldline = GetText(1,Length(openfold))
  144.     result = (foldline == openfold)
  145.     return(result)
  146. end IsOpenFold
  147.  
  148. //}}}
  149. //{{{ Fucktion GetFoldDescription
  150.  
  151. // GetFoldDescription gets the description of a fold
  152. // (I never would have guessed THAT ;-)
  153.  
  154. string proc GetFoldDescription()
  155.     string result[100] = ""
  156.     string foldsign_start[100] = ""
  157.     integer desc_start, desc_end
  158.     integer noclose = 0
  159.  
  160.     if NOT IsClosedFold()
  161.        foldsign_start = startcomment + startfold
  162.        noclose = 1
  163.     else
  164.        foldsign_start = closedfold
  165.        noclose = 0
  166.     endif
  167.     desc_start = Length(foldsign_start) + 2 // BEHIND the space, we start!
  168.     PushPosition()
  169.     EndLine()
  170.     if noclose
  171.        desc_end = CurrPos() - Length(endcomment) - desc_start
  172.     else
  173.        desc_end = CurrPos() - desc_start
  174.     endif
  175.     PopPosition()
  176.     result = GetText(desc_start,desc_end)
  177.     return(result)
  178. end GetFoldDescription
  179.  
  180. //}}}
  181. //{{{ Procedure MarkFold
  182.  
  183. // MarkFold marks a complete fold. Does'nt work yet for nested folds
  184.  
  185. proc MarkFold()
  186.      string findstr[18] = ""
  187.  
  188.      findstr = startcomment + endfold + endcomment
  189.      PushPosition()
  190.      UnmarkBlock()
  191.      MarkLine()
  192.      BegLine()
  193.      // Endmarks only may appear in column 1
  194.      while (lFind(findstr,"")) and (CurrCol()>1)
  195.            Right()
  196.      endwhile
  197.      MarkLine()
  198.      PopPosition()
  199. end MarkFold
  200.  
  201. //}}}
  202. //{{{ Procedure OpenFold
  203.  
  204. // OpenFold opens a closed fold (no, say...). Doesn't work yet
  205. // for nested folds.
  206. // File status is not affected now.
  207.  
  208. proc OpenFold()
  209.      string description[80] = ""
  210.      integer fold_id = 0
  211.      integer SaveClipboardId = 0
  212.      integer fileChanged = 0
  213.  
  214.      PushBlock()
  215.      if IsClosedFold()
  216.         description = GetFoldDescription()
  217.         SaveClipboardId = GetClipBoardId()  // save actual Clipboard
  218.         fold_id = GetBufferId(description)
  219.         if fold_id <> 0
  220.            fileChanged = IsChanged() // SAVE CURRENT FILE STATUS
  221.            DelLine()
  222.            Up()              // Necessary because of DelLine
  223.            SetClipBoardId(fold_id)
  224.            Paste()
  225.            ForceChanged(fileChanged) // RESTORE FILE STATUS
  226.            SetClipBoardId(SaveClipBoardId)
  227.            Down()           // and back
  228.         else
  229.            warn("FATAL: Buffer with this line not more available :-(")
  230.         endif
  231.      else
  232.         warn("WARNING: Line isn't a closed fold!")
  233.      endif
  234.      PopBlock()
  235. end OpenFold
  236.  
  237. //}}}
  238. //{{{ Procedure CloseFold
  239.  
  240. // CloseFold closes an open fold (hey, this guy knows what he says ;-) )
  241. // Doesn't work yet for nested folds.
  242. // File status is not affected now.
  243.  
  244. proc CloseFold()
  245.      string description[80] = ""
  246.      string cl_fold[80] = ""
  247.      integer fold_id = 0
  248.      integer SaveClipboardId = 0
  249.      integer curr_id = 0
  250.      integer fileChanged = 0
  251.  
  252.      if IsOpenFold()
  253.         description = GetFoldDescription()
  254.         PushBlock()
  255.         MarkFold()
  256.         SaveClipboardId = GetClipBoardId()   // save actual Clipboard
  257.         fold_id = GetBufferId(description)
  258.         if fold_id == 0
  259.            curr_id = GetBufferId()
  260.            fold_id = CreateBuffer(description,_SYSTEM_)
  261.            GotoBufferId(curr_id)
  262.         endif
  263.         if fold_id <> 0                          // put away this fold
  264.            SetClipBoardId(fold_id)
  265.            fileChanged = IsChanged() // SAVE CURRENT FILE STATUS
  266.            Cut()
  267.            SetClipBoardId(SaveClipboardId)
  268.            cl_fold = closedfold + " " + description
  269.            InsertLine(cl_fold)
  270.            ForceChanged(fileChanged) // RESTORE FILE STATUS
  271.         else
  272.            Warn("FATAL: fold could not be saved internally!")
  273.         endif
  274.         PopBlock()
  275.      else
  276.         Warn("WARNING: I don't like THIS as fold...")
  277.      endif
  278. end CloseFold
  279.  
  280. //}}}
  281. //{{{ Procedure CreateFold
  282.  
  283. // CreateFold... guess yourself :-) It also creates the description
  284. // and all necessary informations.
  285.  
  286. proc CreateFold()
  287.     string foldsign_start[100] = ""
  288.     string foldsign_end[18] = ""
  289.     string description[80] = ""
  290.  
  291.     foldsign_end   = startcomment + endfold + endcomment
  292.     Ask("Description for this fold: ", description, create_history_num)
  293.     foldsign_start = startcomment + startfold + " " + description + endcomment
  294.     AddLine(foldsign_start)
  295.     AddLine(foldsign_end)
  296. end CreateFold
  297.  
  298. //}}}
  299. //{{{ Function ContainsFileFold
  300.  
  301. // ContainsFileFold determines, whether a loaded file contains a fold
  302. // or not. (YIKES)
  303.  
  304. integer proc ContainsFileFold()
  305.     integer result = 0
  306.     integer lastline = 0
  307.  
  308.     BegFile()
  309.     while (not result) and (not lastline)
  310.           result = IsOpenFold()
  311.           lastline = not Down()
  312.     endwhile
  313.     return(result)
  314. end ContainsFileFold
  315.  
  316. //}}}
  317. //{{{ Function ContainsFileClosedFold
  318.  
  319. // ContainsFileClosedFold determines, if in the actual file, there
  320. // is any closed fold. The marking of these folds MUST appear
  321. // at the beginning of the line.
  322.  
  323. integer proc ContainsFileClosedFold()
  324.     integer result = 0
  325.     integer lastline = 0
  326.  
  327.     BegFile()
  328.     while (not result) and (not lastline)
  329.           result = IsClosedFold()
  330.           lastline = not Down()
  331.     endwhile
  332.     return(result)
  333. end ContainsFileClosedFold
  334.  
  335. //}}}
  336. //{{{ Function FindNextClosedFold
  337.  
  338. // FindNextClosedFold searches from within the cursorline down
  339. // to the next closed fold. Attention: if such a fold is found,
  340. // the following Down() must be omitted, else the cursor would be
  341. // on line too far down for opening this fold. Therefor the if-
  342. // construction marked with (1), also in the next procedure!
  343.  
  344. integer proc FindNextClosedFold()
  345.     integer result = 0
  346.     integer lastline = 0
  347.  
  348.     while (not result) and (not lastline)
  349.           result = IsClosedFold()
  350.           if not result                    // (1)
  351.              lastline = not Down()
  352.           endif
  353.     endwhile
  354.     return(result)
  355. end FindNextClosedFold
  356.  
  357. //}}}
  358. //{{{ Function FindNextOpenFold
  359.  
  360. // FindNextOpenFold searches from within the cursorline until the next
  361. // open fold. For (1), see FindNextClosedFold.
  362.  
  363. integer proc FindNextOpenFold()
  364.     integer result = 0
  365.     integer lastline = 0
  366.  
  367.     while (not result) and (not lastline)
  368.           result = IsOpenFold()
  369.           if not result                    // (1)
  370.              lastline = not Down()
  371.           endif
  372.     endwhile
  373.     return(result)
  374. end FindNextOpenFold
  375.  
  376. //}}}
  377. //{{{ Procedure OpenAllClosedFolds
  378.  
  379. // OpenAllClosedFolds opens all closed folds, so that the file is
  380. // ready to be saved. MUST be done, because all folds are stored
  381. // in system-buffers, which are NOT saved automatically!
  382.  
  383. proc OpenAllClosedFolds()
  384.      BegFile()
  385.      while FindNextClosedFold()
  386.         OpenFold()
  387.      endwhile
  388. end OpenAllClosedFolds
  389.  
  390. //}}}
  391. //{{{ Procedure CloseAllOpenFolds
  392.  
  393. // CloseAllOpenFolds is called upon first time loading a file:
  394. // contained folds are closed, so that the user directly sees the
  395. // structure of the file.
  396.  
  397. proc CloseAllOpenFolds()
  398.     BegFile()
  399.     while FindNextOpenFold()
  400.           CloseFold()
  401.     endwhile
  402. end CloseAllOpenFolds
  403.  
  404. //}}}
  405. //{{{ Procedure mExitAndSave
  406.  
  407. // mExitAndSave is an extended Exit-procedure, because there could
  408. // be closed folds in the system-buffers. They must be opened before
  409. // saving, otherwise you would have massive Date-loss.
  410.  
  411. proc mExitAndSave()
  412.     if ContainsFileClosedFold()
  413.        Message("One moment please...")
  414.        OpenAllClosedFolds()
  415.     endif
  416.     Exit()
  417. end mExitAndSave
  418.  
  419. //}}}
  420. //{{{ Procedure mQuitFile
  421.  
  422. // mQuitFile replaces QuitFile, because this procedure works only
  423. // for the part you SEE on screen. This can naturally cause heavy
  424. // loss of data, which I hope will be prevented by this procedure here.
  425.  
  426. proc mQuitFile()
  427.     if ContainsFileClosedFold()
  428.        Message("One moment please...")
  429.        OpenAllClosedFolds()
  430.     endif
  431.     QuitFile()
  432. end mQuitFile
  433.  
  434. //}}}
  435. //{{{ Prozedur mSaveFile
  436.  
  437. // mSaveFile replaces SaveFile, because this procedure works only
  438. // for the part you SEE on screen. This can naturally cause heavy
  439. // loss of data, which I hope will be prevented by this procedure here.
  440.  
  441. proc mSaveFile()
  442.     if ContainsFileClosedFold()
  443.        Message("One moment please...")
  444.        OpenAllClosedFolds()
  445.     endif
  446.     SaveFile()
  447. end mSaveFile
  448.  
  449. //}}}
  450. //{{{ Prozedur mSaveAndQuitFile
  451.  
  452. // mSaveAndQuitFile replaces SaveAndQuitFile, because this procedure
  453. // works only for the part you SEE on screen. This can naturally cause
  454. // heavy loss of data, which I hope will be prevented by this
  455. // procedure here.
  456.  
  457. proc mSaveAndQuitFile()
  458.     if ContainsFileClosedFold()
  459.        Message("One moment please...")
  460.        OpenAllClosedFolds()
  461.     endif
  462.     SaveAndQuitFile()
  463. end mSaveAndQuitFile
  464.  
  465. //}}}
  466. //{{{ Procedure PrepareLoadedFile
  467.  
  468. // PrepareLoadedFile checks, if a loaded file contains folds. If yes,
  469. // all folds are closed, so that the structure of the file can be seen.
  470. // Using hooking-technique, this procedure is called every time you
  471. // load a new file.
  472.  
  473. proc PrepareLoadedFile()
  474.     if ContainsFileFold()
  475.        CloseAllOpenFolds()
  476.     else
  477.        Message("INFO: File doesn't contain folds yet!")
  478.     endif
  479. end PrepareLoadedFile
  480.  
  481. //}}}
  482. //{{{ Procedure ReadConfigFile
  483.  
  484. // ReadConfigFile reads an eventually existing Configurationfile.
  485. // What you can see here: normally, the use of macro-instructions
  486. // for reading DOS-Files is not necessary, you can get everything
  487. // as shown here.
  488. // ReadConfigFile is called automatically upon start of macro.
  489. // The configurationfile MUST be named FOLD.CFG.
  490.  
  491. proc ReadConfigFile()
  492.      EditFile("fold.cfg")
  493.      BegFile()
  494.      lfind("startfold=","")
  495.      startfold = GetText(11,6)
  496.      BegFile()
  497.      lfind("endfold=","")
  498.      endfold = GetText(9,6)
  499.      BegFile()
  500.      lfind("startcomment=","")
  501.      startcomment = GetText(14,6)
  502.      BegFile()
  503.      lfind("endcomment=","")
  504.      endcomment = GetText(12,6)
  505.      BegFile()
  506.      lfind("closedfold=","")
  507.      closedfold = GetText(12,6)
  508.      AbandonFile()
  509. end ReadConfigFile
  510.  
  511. //}}}
  512. //{{{ Procedure SaveConfigFile
  513.  
  514. // SaveConfigFile writes a configurationfile to disk (not used yet).
  515. // You could apply this procedure to a special key. In a later version,
  516. // this procedure will be used from within an interactive menu.
  517. // Interesting: the file is built like a LIFO-buffer. This is caused
  518. // by the InsertLine-command.
  519.  
  520. proc SaveConfigFile()
  521.      integer id
  522.  
  523.      id = CreateBuffer("fold.cfg")
  524.      if id
  525.         InsertLine("closedfold="+closedfold)
  526.         InsertLine("endcomment="+endcomment)
  527.         InsertLine("startcomment="+startcomment)
  528.         InsertLine("endfold="+endfold)
  529.         InsertLine("startfold="+startfold)
  530.         EraseDiskFile("fold.cfg")
  531.         SaveAs("fold.cfg")
  532.         AbandonFile()
  533.      else
  534.         Warn("WARNING: Couldn't create configuration-file in memory!")
  535.      endif
  536. end SaveConfigFile
  537.  
  538. //}}}
  539. //{{{ Startup Macro WhenLoaded
  540.  
  541. // Executed upon start of TSE, but before the commandline is completely
  542. // evaluated and before any file is loaded.
  543.  
  544. proc WhenLoaded()
  545.         if FileExists("fold.cfg")   // Read configuration, if existing
  546.            ReadConfigFile()
  547.         endif
  548.         Set(Break,ON)
  549.         Hook(_ON_FIRST_EDIT_,PrepareLoadedFile)
  550. end WhenLoaded
  551.  
  552. //}}}
  553.  
  554. //{{{ Procedure DeactivateMacro
  555.  
  556. // With DeactivateMacro, the macro fold is fully disabled. But before
  557. // doing this, all folds are opened, so that there is no loss of data.
  558.  
  559. proc DeactivateMacro()
  560.      Message("The folding macro finishes his work. Live long and prosper!")
  561.      OpenAllClosedFolds()
  562.      PurgeMacro("fold")
  563. end DeactivateMacro
  564.  
  565. //}}}
  566.  
  567. //{{{ Startup Macro Main
  568.  
  569. // Main is executed upon start of macro, but AFTER a file named in the
  570. // command-line is loaded.
  571.  
  572. proc Main()
  573.         UpdateDisplay()
  574.         BegFile()
  575.         if (ContainsFileFold())
  576.            PrepareLoadedFile()
  577.         endif
  578.         Message("TSE is now configured as folding editor! (c) dw 93")
  579. end Main
  580.  
  581. //}}}
  582.  
  583. //{{{ Keydefinitions
  584.  
  585. // Keydefinitions for testing purposes.
  586. // Please change them following your own wishes.
  587. // I recommend the redefinition of Alt-x, and perhaps the new definition
  588. // of Ctrl F11 und Ctrl F12.
  589.  
  590. <Ctrl F3>      CloseAllOpenFolds()
  591. <Ctrl F4>      OpenAllClosedFolds()
  592. <Ctrl F6>      SaveConfigFile()
  593. <Ctrl F8>      ReadConfigFile()
  594. <Alt x>        mExitAndSave()
  595. <Ctrl F10>     CreateFold()
  596. <Ctrl F11>     CloseFold()
  597. <Ctrl F12>     OpenFold()
  598. <Shift F12>    DeactivateMacro()
  599.  
  600. // necessary new assignments
  601.  
  602. <Ctrl k><q>          mQuitFile() CloseWindow()
  603. <Ctrl k><d>          mQuitFile() CloseWindow()
  604. <Ctrl k><s>          mSaveFile()
  605. <Ctrl k><x>          mSaveAndQuitFile()
  606.  
  607. //}}}
  608.  
  609.