home *** CD-ROM | disk | FTP | other *** search
/ Amiga Times / AmigaTimes.iso / programme / GoldED / developer / examples / api / mirror / funcs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-06  |  11.2 KB  |  448 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  ApiLib ©1995 Dietmar Eilert
  4.  
  5.  Mirror API client, ©1995 Dietmar Eilert. Highlights matching bracket if cursor
  6.  is moved over a bracket.
  7.  
  8.  Dice:
  9.  
  10.  DMAKE
  11.  
  12.  -------------------------------------------------------------------------------
  13.  
  14. */
  15.  
  16. #include "defs.h"
  17.  
  18. /// "Prototype"
  19.  
  20. // library functions
  21.  
  22. Prototype LibCall struct APIClient *APIMountClient(__A0 struct APIMessage *, __A1 char *);
  23. Prototype LibCall void              APICloseClient(__A0 struct APIClient *, __A1 struct APIMessage *);
  24. Prototype LibCall void              APIBriefClient(__A0 struct APIClient *, __A1 struct APIMessage *);
  25. Prototype LibCall void              APIFree       (__A0 struct APIClient  *, __A1 struct APIOrder   *);
  26.  
  27. // private functions
  28.  
  29. Prototype void Dispatch(struct APIMessage *);
  30. Prototype BOOL FindMarkedBracket(struct EditConfig *);
  31. Prototype BOOL NoUserBlock      (struct EditConfig *);
  32. Prototype BOOL IsABracket(UWORD);
  33. Prototype BOOL MatchingBracket(struct APIMessage *, UWORD);
  34.  
  35. // the following line determines if online checks are enabled
  36.  
  37. #undef ONLINECHECK
  38.  
  39. ///
  40. /// "library functions"
  41.  
  42. LibCall struct APIClient *
  43. APIMountClient(__A0 struct APIMessage *apiMsg, __A1 char *args)
  44. {
  45.     static struct APIClient apiClient;
  46.  
  47.     apiClient.api_APIVersion = API_INTERFACE_VERSION;
  48.     apiClient.api_Version    = 3;
  49.     apiClient.api_Name       = "Mirror API";
  50.     apiClient.api_Info       = "Bracket highlighting";
  51.     apiClient.api_Commands   = NULL;
  52.     apiClient.api_Serial     = 0;
  53.     apiClient.api_Classes    = API_CLASS_SYSTEM | API_CLASS_KEY;
  54.     apiClient.api_Area       = NULL;
  55.  
  56.     return(&apiClient);
  57. }
  58.  
  59. LibCall void
  60. APICloseClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
  61. {
  62.     // no ressources to be freed
  63. }
  64.  
  65. LibCall void
  66. APIBriefClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
  67. {
  68.     struct APIMessage *msg;
  69.  
  70.     // handle host's command notify
  71.  
  72.     for (msg = apiMsg; msg; msg = msg->api_Next) {
  73.  
  74.         if (msg->api_State == API_STATE_NOTIFY) {
  75.  
  76.             switch (msg->api_Class) {
  77.  
  78.                 case API_CLASS_KEY:
  79.  
  80.                     Dispatch(msg);
  81.  
  82.                 case API_CLASS_SYSTEM:
  83.  
  84.                     break;
  85.  
  86.                 default:
  87.  
  88.                     msg->api_Error = API_ERROR_UNKNOWN;
  89.             }
  90.         }
  91.     }
  92. }
  93.  
  94. LibCall void
  95. APIFree(__A0 struct APIClient *handle, __A1 struct APIOrder *apiOrder)
  96. {
  97.     // no ressources to be freed
  98. }
  99.  
  100. ///
  101. /// "private functions"
  102.  
  103. /* --------------------------------- Dispatch ----------------------------------
  104.  
  105.  Dispatch incoming API event
  106.  
  107. */
  108.  
  109. void
  110. Dispatch(apiMsg)
  111.  
  112. struct APIMessage *apiMsg;
  113. {
  114.     struct EditConfig *config = (struct EditConfig *)apiMsg->api_Instance->api_Environment;
  115.  
  116.     if (apiMsg->api_Action == API_ACTION_RAWKEY) {
  117.  
  118.         UWORD ascii = config->CurrentBuffer[config->Column];
  119.  
  120.         if (IsABracket(ascii) && NoUserBlock(config)) {
  121.  
  122.             if (MatchingBracket(apiMsg, ascii) == FALSE) {
  123.  
  124.                 if (FindMarkedBracket(config))
  125.  
  126.                     apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  127.             }
  128.         }
  129.         else if (FindMarkedBracket(config))
  130.  
  131.             apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  132.     }
  133.     else if (apiMsg->api_Action == API_ACTION_VANILLAKEY) {
  134.  
  135.         if (NoUserBlock(config)) {
  136.  
  137.             // check char under cursor
  138.  
  139.             UWORD ascii = config->CurrentBuffer[config->Column];
  140.  
  141.             if (IsABracket(ascii)) {
  142.  
  143.                 if (MatchingBracket(apiMsg, ascii) == FALSE) {
  144.  
  145.                     if (FindMarkedBracket(config))
  146.  
  147.                         apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  148.                 }
  149.             }
  150.  
  151.             #ifdef ONLINECHECK
  152.  
  153.             else if (config->Column) {
  154.  
  155.                 ascii = (UWORD)apiMsg->api_Data;
  156.  
  157.                 // check character next to cursor
  158.  
  159.                 --config->Column;
  160.  
  161.                 // just typed by user ?
  162.  
  163.                 if (config->CurrentBuffer[config->Column] == ascii) {
  164.  
  165.                     if (MatchingBracket(apiMsg, ascii) == FALSE)
  166.  
  167.                         if (FindMarkedBracket(config))
  168.  
  169.                             apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  170.                 }
  171.                 else if (FindMarkedBracket(config))
  172.  
  173.                     apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  174.  
  175.                 ++config->Column;
  176.             }
  177.  
  178.             #endif
  179.  
  180.             else if (FindMarkedBracket(config))
  181.  
  182.                 apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  183.         }
  184.     }
  185. }
  186.  
  187.  
  188. /* ------------------------------- MatchingBracket -----------------------------
  189.  
  190.  Find matching bracket. Ignore opening brackets preceeded by '/' (ASCII 92, TeX
  191.  style construction used to insert a bracket into text).
  192.  
  193.  \} ............ ignored      (TEX constant)
  194.  \\} ........... not ignored  (TEX bracket)
  195.  
  196. */
  197.  
  198. BOOL
  199. MatchingBracket(apiMsg, examine)
  200.  
  201. struct APIMessage *apiMsg;
  202. UWORD              examine;
  203. {
  204.     UBYTE *known;
  205.     WORD   step;
  206.  
  207.     for (step = 1, known = "(){}"; *known; ++known, step = -step) {
  208.  
  209.         if (examine == *known) {
  210.  
  211.             WORD   column;
  212.             UBYTE *current;
  213.             BOOL   isTEX;
  214.  
  215.             struct EditConfig *config = (struct EditConfig *)apiMsg->api_Instance->api_Environment;
  216.  
  217.             column  = config->Column;
  218.             current = config->CurrentBuffer;
  219.  
  220.             if ((column > 0) && (current[column - 1] == 92)) {
  221.  
  222.                 if ((column > 1) && (current[column - 2] == 92))
  223.                     isTEX = FALSE;
  224.                 else
  225.                     isTEX = TRUE;
  226.             }
  227.             else
  228.                 isTEX = FALSE;
  229.  
  230.             if (isTEX == FALSE) {
  231.  
  232.                 WORD   len, level, count, distance;
  233.                 BOOL   success, inString;
  234.                 ULONG  line;
  235.                 UBYTE  twin;
  236.  
  237.                 inString = FALSE;
  238.                 success  = FALSE;
  239.  
  240.                 line     = config->Line;
  241.                 len      = config->CurrentLen;
  242.  
  243.                 twin = *(known + step);
  244.  
  245.                 count    =  0;
  246.                 level    = -1;
  247.  
  248.                 // modify the scan depth (default: 50 lines) to speed up the client
  249.  
  250.                 for (distance = 0; distance <= 50; ++distance) {
  251.  
  252.                     while ((column >= 0) && (column < len)) {
  253.  
  254.                         UBYTE *next = current + column;
  255.  
  256.                         if ((*next == 34) || (*next == 39))
  257.  
  258.                             inString = !inString;
  259.  
  260.                         else if (!inString) {
  261.  
  262.                             if ((column > 0) && (*(next - 1) == 92)) {
  263.  
  264.                                 if ((column > 1) && (*(next - 2) == 92))
  265.                                     isTEX = FALSE;
  266.                                 else
  267.                                     isTEX = TRUE;
  268.                             }
  269.                             else
  270.                                 isTEX = FALSE;
  271.  
  272.                             if (!isTEX) {
  273.  
  274.                                 if (*next == twin) {
  275.  
  276.                                     if (level)
  277.                                         --level;
  278.  
  279.                                     else {
  280.  
  281.                                         success = TRUE;
  282.                                         break;
  283.                                     }
  284.                                 }
  285.                                 else if (*next == *known) {
  286.  
  287.                                     ++level;
  288.                                     ++count;
  289.                                 }
  290.                             }
  291.                         }
  292.  
  293.                         column += step;
  294.                     }
  295.  
  296.                     if (success) {
  297.  
  298.                         BOOL adjacent = FALSE;
  299.  
  300.                         if (line == config->Line)
  301.  
  302.                             adjacent = (column == (config->Column + step));
  303.  
  304.                         if (adjacent)
  305.  
  306.                             apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  307.  
  308.                         else {
  309.  
  310.                             // block markers may not be used in fold headers
  311.  
  312.                             if (GET_FOLD(config->TextNodes + line))
  313.  
  314.                                 return(FALSE);
  315.  
  316.                             else {
  317.  
  318.                                 if ((distance == 0) && ((config->Marker == BLOCKMODE_NONE) || ((line == config->BlockStartY) && (line == config->BlockEndY))))
  319.  
  320.                                     apiMsg->api_Refresh = API_REFRESH_LINE;
  321.  
  322.                                 else if (config->Marker == BLOCKMODE_NONE)
  323.  
  324.                                     apiMsg->api_Refresh = API_REFRESH_MARKER;
  325.                                 else
  326.                                     apiMsg->api_Refresh = API_REFRESH_DISPLAY;
  327.  
  328.                                 config->Marker = BLOCKMODE_CHAR;
  329.  
  330.                                 config->BlockStartX = config->BlockEndX = column;
  331.                                 config->BlockStartY = config->BlockEndY = line;
  332.  
  333.                                 return(TRUE);
  334.                             }
  335.                         }
  336.                     }
  337.                     else {
  338.  
  339.                         line    += step;
  340.                         inString = FALSE;
  341.  
  342.                         if ((line >= 0) && (line < config->Lines)) {
  343.  
  344.                             struct LineNode *lineNode = config->TextNodes + line;
  345.  
  346.                             current = lineNode->Text;
  347.                             len     = lineNode->Len;
  348.  
  349.                             column = (step == -1) ? len - 1 : 0;
  350.                         }
  351.                         else                         // no matching bracket
  352.                             break;
  353.                     }
  354.                 }
  355.  
  356.                 break;
  357.             }
  358.         }
  359.     }
  360.  
  361.     return(FALSE);
  362. }
  363.  
  364.  
  365. /* ------------------------------- NoUserBlock ---------------------------------
  366.  
  367.  Return TRUE if there is no user-defined block, i.e. either no block at all or a
  368.  marked bracket only (possibly marked by us).
  369.  
  370. */
  371.  
  372. BOOL
  373. NoUserBlock(config)
  374.  
  375. struct EditConfig *config;
  376. {
  377.     return((config->Marker == BLOCKMODE_NONE) || FindMarkedBracket(config));
  378. }
  379.  
  380.  
  381. /* ----------------------------- FindMarkedBracket -----------------------------
  382.  
  383.  Return TRUE if a single bracket has been marked (probably by us)
  384.  
  385. */
  386.  
  387. BOOL
  388. FindMarkedBracket(config)
  389.  
  390. struct EditConfig *config;
  391. {
  392.     if (config->Marker == BLOCKMODE_CHAR) {
  393.  
  394.         if (config->BlockStartY == config->BlockEndY) {
  395.  
  396.             if (config->BlockStartX == config->BlockEndX) {
  397.  
  398.                 UWORD pos = config->BlockStartX;
  399.  
  400.                 if (config->BlockStartY == config->Line) {
  401.  
  402.                     if (pos < config->CurrentLen)
  403.  
  404.                         return(IsABracket(config->CurrentBuffer[pos]));
  405.                 }
  406.                 else {
  407.  
  408.                     struct LineNode *lineNode = config->TextNodes + config->BlockStartY;
  409.  
  410.                     if (pos < lineNode->Len)
  411.  
  412.                         return(IsABracket(lineNode->Text[config->BlockStartX]));
  413.                 }
  414.             }
  415.         }
  416.     }
  417.  
  418.     return(FALSE);
  419. }
  420.  
  421. /* -------------------------------- IsABracket ---------------------------------
  422.  
  423.  Check whether character is a bracket
  424.  
  425. */
  426.  
  427. BOOL
  428. IsABracket(letter)
  429.  
  430. UWORD letter;
  431. {
  432.     if (letter == '(')
  433.         return(TRUE);
  434.  
  435.     if (letter == ')')
  436.         return(TRUE);
  437.  
  438.     if (letter == '{')
  439.         return(TRUE);
  440.  
  441.     if (letter == '}')
  442.         return(TRUE);
  443.  
  444.     return(FALSE);
  445. }
  446.  
  447. ///
  448.