├── LICENSE ├── README.md ├── batchInsert.gif ├── comments.gif ├── delimiter.gif ├── progressiveSearch.gif ├── simc.em ├── simcUnitTests.em ├── snippets.gif └── surrounder.gif /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Source Insight Macro Collection 2 | =============================== 3 | 4 | A collection of Source Insight macros which make coding easier and more enjoyable. 5 | 6 | It tends to be an example of developing your own macros, that's why there are only a few macros of classical use case included. 7 | 8 | ## Installation 9 | 10 | - Add `simc.em` to your project, or to the base project so that you just need to do it once for all your projects. 11 | - From menu "Options" -> "Key Assignments..." to bind any macro functions in this file to keys. Macros start with `simc` are from this package. 12 | 13 | ## Demo 14 | 15 | ### Snippets 16 | 17 | ![snippets](snippets.gif) 18 | 19 | ### Surrounder 20 | 21 | ![surrounder](surrounder.gif) 22 | 23 | ### Batch Insert 24 | 25 | ![batchInsert](batchInsert.gif) 26 | 27 | 28 | ### Fast commenting 29 | 30 | ![fastCommenting](comments.gif) 31 | 32 | ### Fast locating delimiter pairs 33 | 34 | ![delimiter](delimiter.gif) 35 | 36 | ### Progressive search 37 | 38 | ![progressiveSearch](progressiveSearch.gif) 39 | -------------------------------------------------------------------------------- /batchInsert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5shi/SourceInsightMacroCollection/5f12d607711d1289c075fbe517683e74e847b6bf/batchInsert.gif -------------------------------------------------------------------------------- /comments.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5shi/SourceInsightMacroCollection/5f12d607711d1289c075fbe517683e74e847b6bf/comments.gif -------------------------------------------------------------------------------- /delimiter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5shi/SourceInsightMacroCollection/5f12d607711d1289c075fbe517683e74e847b6bf/delimiter.gif -------------------------------------------------------------------------------- /progressiveSearch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5shi/SourceInsightMacroCollection/5f12d607711d1289c075fbe517683e74e847b6bf/progressiveSearch.gif -------------------------------------------------------------------------------- /simc.em: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | * Source Insight Macro Collection 3 | * 4 | * File: simc.em 5 | * 6 | * Author: Jia Shi 7 | * 8 | * Version: 0.0.1 9 | * 10 | * License: MIT License 11 | * 12 | * Last Modified: 2014-11-09 17:35:30 13 | * 14 | * Usage: 15 | * 1. Add this file to your project, or to the base project so 16 | * that you just need to do it once for all your projects. 17 | * 18 | * 2. From menu "Options" -> "Key Assignments..." to bind any 19 | * macro functions in this file to keys. 20 | * 21 | * 3. Enjoy the macros! 22 | * 23 | * Copyright (c) 2014-2015, Jia Shi 24 | **************************************************************/ 25 | 26 | /*------------------------------------------------------------------------- 27 | Automatically insert code snippet. 28 | 29 | Currently the following code snippets are supported, but this can 30 | be extened easily: 31 | 32 | - if 33 | - else 34 | - for 35 | - while 36 | - do-while 37 | - switch 38 | - case 39 | - default 40 | - main 41 | 42 | For example: 43 | 1. bind this function to "Tab" 44 | 2. type "for" and press "Tab" 45 | 3. this is what will be inserted: 46 | for (###; ###; ###) 47 | { 48 | ### 49 | } 50 | 4. and the first ### pattern is selected. 51 | -------------------------------------------------------------------------*/ 52 | macro simcInsertSnippet() 53 | { 54 | var sMacroName; sMacroName = "simcInsertSnippet" 55 | var hWnd 56 | var rSel 57 | var hBuf 58 | var sLine 59 | var iCh 60 | var sIndent 61 | var iChLim 62 | var asciiA 63 | var asciiZ 64 | var cCharUpper 65 | var asciiCharUpper 66 | var rWordinfo 67 | var lnCurrent 68 | var PATTERN; PATTERN = "###" 69 | var TAB; TAB = CharFromAscii(9) 70 | var SPACE; SPACE = CharFromAscii(32) 71 | 72 | // if no windows is opened, then do nothing. 73 | hWnd = GetCurrentWnd() 74 | if (hWnd == 0) 75 | { 76 | stop 77 | } 78 | else 79 | { 80 | rSel = GetWndSel(hWnd) 81 | hBuf = GetWndBuf(hWnd) 82 | sLine = GetBufLine(hBuf, rSel.lnFirst) 83 | 84 | // scan backwords over white space and tab, if any, 85 | // to the ending of a word 86 | iCh = rSel.ichFirst - 1 87 | if (iCh >= 0) 88 | { 89 | while (sLine[iCh] == SPACE || sLine[iCh] == TAB) 90 | { 91 | iCh = iCh - 1 92 | if (iCh < 0) 93 | break 94 | } 95 | } 96 | 97 | // scan backwords to start of word 98 | iChLim = iCh + 1 99 | asciiA = AsciiFromChar("A") 100 | asciiZ = AsciiFromChar("Z") 101 | while (iCh >= 0) 102 | { 103 | cCharUpper = toupper(sLine[iCh]) 104 | asciiCharUpper = AsciiFromChar(cCharUpper) 105 | if ((asciiCharUpper < asciiA || asciiCharUpper > asciiZ) && !IsNumber(cCharUpper)) 106 | break // stop at first non-identifier character 107 | iCh = iCh - 1 108 | } 109 | 110 | // parse word just to the left of the cursor 111 | // and store the result to the rWordinfo record 112 | // rWordinfo.szWord = the word string 113 | // rWordinfo.ich = the first ich of the word 114 | // rWordinfo.ichLim = the limit ich of the word 115 | iCh = iCh + 1 116 | rWordinfo = "" 117 | rWordinfo.sWord = strmid(sLine, iCh, iChLim) 118 | rWordinfo.iCh = iCh 119 | rWordinfo.iChLim = iChLim 120 | 121 | // generate the indent string, tab will be replaced 122 | // by 4 spaces. 123 | iCh = 0 124 | sIndent = "" 125 | while (sLine[iCh] == SPACE || sLine[iCh] == TAB) 126 | { 127 | if (sLine[iCh] == SPACE) 128 | sIndent = sIndent # SPACE 129 | else if (sLine[iCh] == TAB) 130 | sIndent = sIndent # SPACE # SPACE # SPACE # SPACE 131 | 132 | iCh++ 133 | } 134 | 135 | // select any space / tab between the end 136 | // of the identifier and the cursor and 137 | // replace them with the snippet. 138 | if (rWordinfo.sWord == "if" || rWordinfo.sWord == "while" || 139 | rWordinfo.sWord == "else" || rWordinfo.sWord == "for" || 140 | rWordinfo.sWord == "switch" || rWordinfo.sWord == "do" || 141 | rWordinfo.sWord == "case" || rWordinfo.sWord == "default" ) 142 | { 143 | SetBufIns(hBuf, rSel.lnFirst, rWordinfo.iChLim) 144 | rSel.ichFirst = rWordinfo.ichLim 145 | rSel.ichLim = rSel.ichLim 146 | SetWndSel(hWnd, rSel) 147 | } 148 | 149 | if (rWordinfo.sWord == "if" || rWordinfo.sWord == "while") 150 | { 151 | SetBufSelText(hBuf, " (@PATTERN@)") 152 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "{") 153 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " @PATTERN@") 154 | InsBufLine(hBuf, rSel.lnFirst + 3, sIndent # "}") 155 | } 156 | else if (rWordinfo.sWord == "else") 157 | { 158 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "{") 159 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " @PATTERN@") 160 | InsBufLine(hBuf, rSel.lnFirst + 3, sIndent # "}") 161 | } 162 | else if (rWordinfo.sWord == "for") 163 | { 164 | SetBufSelText(hBuf, " (@PATTERN@; @PATTERN@; @PATTERN@)") 165 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "{") 166 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " @PATTERN@") 167 | InsBufLine(hBuf, rSel.lnFirst + 3, sIndent # "}") 168 | } 169 | else if (rWordinfo.sWord == "switch") 170 | { 171 | SetBufSelText(hBuf, " (@PATTERN@)") 172 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "{") 173 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " case @PATTERN@:") 174 | InsBufLine(hBuf, rSel.lnFirst + 3, sIndent # " @PATTERN@") 175 | InsBufLine(hBuf, rSel.lnFirst + 4, sIndent # " break;") 176 | InsBufLine(hBuf, rSel.lnFirst + 5, sIndent # "}") 177 | } 178 | else if (rWordinfo.sWord == "case") 179 | { 180 | SetBufSelText(hBuf, " @PATTERN@:") 181 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # " @PATTERN@") 182 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " break;") 183 | } 184 | else if (rWordinfo.sWord == "default") 185 | { 186 | SetBufSelText(hBuf, ":") 187 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # " @PATTERN@") 188 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " break;") 189 | } 190 | else if (rWordinfo.sWord == "do") 191 | { 192 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "{") 193 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " @PATTERN@") 194 | InsBufLine(hBuf, rSel.lnFirst + 3, sIndent # "} while (@PATTERN@)") 195 | } 196 | else if (rWordinfo.sWord == "main") 197 | { 198 | SetBufSelText(hBuf, "()") 199 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "{") 200 | InsBufLine(hBuf, rSel.lnFirst + 2, sIndent # " return @PATTERN@;") 201 | InsBufLine(hBuf, rSel.lnFirst + 3, sIndent # "}") 202 | } 203 | else if (rWordinfo.sWord == "add") 204 | { 205 | delete_line 206 | InsBufLine(hBuf, rSel.lnFirst, sIndent # "/* Begin Add by: @PATTERN@ PN: @PATTERN@ Dsc: @PATTERN@ */") 207 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "/* End Add PN: @PATTERN@ */") 208 | 209 | } 210 | else if (rWordinfo.sWord == "mod") 211 | { 212 | delete_line 213 | InsBufLine(hBuf, rSel.lnFirst, sIndent # "/* Begin Modify by: @PATTERN@ PN: @PATTERN@ Dsc: @PATTERN@ */") 214 | InsBufLine(hBuf, rSel.lnFirst + 1, sIndent # "/* End Modify PN: @PATTERN@ */") 215 | 216 | } 217 | else if (rWordinfo.sWord == "del") 218 | { 219 | delete_line 220 | InsBufLine(hBuf, rSel.lnFirst, sIndent # "/* Delete by: @PATTERN@ PN: @PATTERN@ Dsc: @PATTERN@ */") 221 | } 222 | else 223 | { 224 | // incase this macro is associated with 225 | // tab, then it needs to behavior like 226 | // a normal tab when the user doesn't want 227 | // to insert any snippets. 228 | if (CmdFromKey(AsciiFromChar(TAB)) == sMacroName) 229 | { 230 | // insert expanded tab (4 spaces) at the 231 | // begining of each selected line. 232 | rSel = GetWndSel(hWnd) 233 | lnCurrent = rSel.lnFirst 234 | while (lnCurrent <= rSel.lnLast) 235 | { 236 | SetBufIns(hBuf, lnCurrent, rSel.ichFirst) 237 | SetBufSelText(hBuf, SPACE # SPACE # SPACE # SPACE) 238 | lnCurrent++ 239 | } 240 | 241 | // in case multi-line are selected, keep the lines 242 | // selected after the macro finished executing, this 243 | // has the same behavior as pressing tabs. 244 | if (rSel.lnFirst != rSel.lnLast) 245 | { 246 | rSel.ichLim = rSel.ichLim + 4 247 | SetWndSel(hWnd, rSel) 248 | } 249 | } 250 | 251 | stop 252 | } 253 | 254 | // select the first PATTERN 255 | rSel.ichFirst = rWordinfo.ichLim 256 | rSel.ichLim = rWordinfo.ichLim 257 | SetWndSel(hWnd, rSel) 258 | LoadSearchPattern(PATTERN, False, False, True) 259 | Search_Forward 260 | } 261 | } 262 | 263 | 264 | /*------------------------------------------------------------------------- 265 | Close all non-dirty file windows, dirty file windows are those source 266 | file windows with unsaved mofidication. 267 | -------------------------------------------------------------------------*/ 268 | macro simcCloseAllNonDirtyWindow() 269 | { 270 | var hWnd; hWnd = GetCurrentWnd() 271 | var hWndNext 272 | var hBuf 273 | 274 | while (hWnd != 0) 275 | { 276 | hWndNext = GetNextWnd(hWnd) 277 | hBuf = GetWndBuf(hWnd) 278 | 279 | if (!IsBufDirty(hBuf)) 280 | CloseBuf(hBuf) 281 | 282 | hWnd = hWndNext 283 | } 284 | } 285 | 286 | 287 | /*------------------------------------------------------------------------- 288 | Comment out the selected lines in single line comments style. 289 | 290 | By changing the @TOKEN@ variable in the macro function, user can 291 | replace default comment token from "// " to any other tokens, for 292 | example, "# " for Python. 293 | -------------------------------------------------------------------------*/ 294 | macro simcCommentLineOut() 295 | { 296 | var hWnd; hWnd = GetCurrentWnd() 297 | var hBuf; hBuf = GetCurrentBuf() 298 | var rSelOrig; rSelOrig = GetWndSel(hWnd) 299 | var rSelTemp; rSelTemp = rSelOrig 300 | var lnCurrentLine; lnCurrentLine = rSelOrig.lnFirst 301 | var sCurrentLine 302 | var iCurrentLineLen 303 | var iChar 304 | var TAB; TAB = CharFromAscii(9) 305 | var SPACE; SPACE = CharFromAscii(32) 306 | var TOKEN; TOKEN = "// " 307 | 308 | while (lnCurrentLine <= rSelOrig.lnLast) 309 | { 310 | sCurrentLine = GetBufLine(hBuf, lnCurrentLine) 311 | iCurrentLineLen = GetBufLineLength(hBuf, lnCurrentLine) 312 | iChar = 0 313 | 314 | while (iChar < iCurrentLineLen) 315 | { 316 | if (sCurrentLine[iChar] == SPACE || sCurrentLine[iChar] == TAB) 317 | { 318 | iChar++ 319 | } 320 | else 321 | { 322 | rSelTemp.lnFirst = lnCurrentLine 323 | rSelTemp.lnLast = lnCurrentLine 324 | rSelTemp.ichFirst = iChar 325 | rSelTemp.ichLim = iChar 326 | SetWndSel(hWnd, rSelTemp) 327 | SetBufSelText(hBuf, TOKEN) 328 | break 329 | } 330 | } 331 | lnCurrentLine++ 332 | } 333 | 334 | SetWndSel(hWnd, rSelOrig) 335 | } 336 | 337 | /*------------------------------------------------------------------------- 338 | Uncomment out the lines which have been commented out in single line 339 | comments style. 340 | 341 | By changing the @TOKEN@ variable in the macro function, user can 342 | replace default comment token from "// " to any other tokens, for 343 | example, "# " for Python. 344 | -------------------------------------------------------------------------*/ 345 | macro simcUncommentLineOut() 346 | { 347 | var hWnd; hWnd = GetCurrentWnd() 348 | var hBuf; hBuf = GetCurrentBuf() 349 | var rSelOrig; rSelOrig = GetWndSel(hWnd) 350 | var rSelTemp; rSelTemp = rSelOrig 351 | var lnCurrentLine; lnCurrentLine = rSelOrig.lnFirst 352 | var sCurrentLine 353 | var sCurrentLineTemp 354 | var iCurrentLineLen 355 | var iChar 356 | var TOKEN; TOKEN = "// " 357 | var TOKEN_LEN; TOKEN_LEN = strlen(TOKEN) 358 | 359 | while (lnCurrentLine <= rSelOrig.lnLast) 360 | { 361 | sCurrentLine = GetBufLine(hBuf, lnCurrentLine) 362 | sCurrentLineTemp = "" 363 | iCurrentLineLen = GetBufLineLength(hBuf, lnCurrentLine) 364 | iChar = 0 365 | 366 | while (iChar <= iCurrentLineLen - TOKEN_LEN) 367 | { 368 | if (strmid (sCurrentLine, iChar, iChar+TOKEN_LEN) == TOKEN) 369 | { 370 | rSelTemp.lnFirst = lnCurrentLine 371 | rSelTemp.lnLast = lnCurrentLine 372 | rSelTemp.ichFirst = iChar + TOKEN_LEN 373 | rSelTemp.ichLim = iCurrentLineLen 374 | SetWndSel(hWnd, rSelTemp) 375 | PutBufLine(hBuf, lnCurrentLine, cat(sCurrentLineTemp, strmid(sCurrentLine, rSelTemp.ichFirst, rSelTemp.ichLim))) 376 | break 377 | } 378 | else 379 | { 380 | sCurrentLineTemp = cat(sCurrentLineTemp, sCurrentLine[iChar]) 381 | iChar++ 382 | continue 383 | } 384 | } 385 | lnCurrentLine++ 386 | } 387 | SetWndSel(hWnd, rSelOrig) 388 | } 389 | 390 | /*------------------------------------------------------------------------- 391 | Comment out the selected lines in block comments style. 392 | 393 | By changing the @iFirstCommLineLen@ user can adjust the number of the 394 | asterisks in the first block comment line. But the final length of the 395 | first block comment line is decided by the longest line in the comment, 396 | if it is longer than default @iFirstCommLineLen@, then its length will 397 | be used as the value of @iFirstCommLineLen@. 398 | -------------------------------------------------------------------------*/ 399 | macro simcCommentBlockOut() 400 | { 401 | var hWnd; hWnd = GetCurrentWnd() 402 | var hBuf; hBuf = GetCurrentBuf() 403 | var rSelOrig; rSelOrig = GetWndSel(hWnd) 404 | var lnCurrentLine 405 | var sCurrentLine 406 | var iLineLen 407 | var iFirstCommLineLen; iFirstCommLineLen = 40 // default len of the 1st comment line 408 | 409 | // calculate the length of the longest line 410 | lnCurrentLine = rSelOrig.lnFirst 411 | while (lnCurrentLine <= rSelOrig.lnLast) 412 | { 413 | iLineLen = GetBufLineLength(hBuf, lnCurrentLine) 414 | if (iLineLen > iFirstCommLineLen) 415 | iFirstCommLineLen = iLineLen 416 | lnCurrentLine++ 417 | } 418 | 419 | // insert the first block comment line. 420 | InsBufLine(hBuf, rSelOrig.lnFirst, cat("/", __str_rep("*", iFirstCommLineLen))) 421 | 422 | // since an extra line in inserted, rSelOrig became incorrect 423 | // and needs to be fixed 424 | rSelOrig.lnFirst = rSelOrig.lnFirst + 1 425 | rSelOrig.lnLast = rSelOrig.lnLast + 1 426 | lnCurrentLine = rSelOrig.lnFirst 427 | while (lnCurrentLine <= rSelOrig.lnLast) 428 | { 429 | sCurrentLine = GetBufLine(hBuf, lnCurrentLine) 430 | PutBufLine(hBuf, lnCurrentLine, cat(" * ", sCurrentLine)) 431 | lnCurrentLine++ 432 | } 433 | InsBufLine(hBuf, lnCurrentLine, cat(" ", cat(__str_rep("*", iFirstCommLineLen), "/"))) 434 | } 435 | 436 | /*------------------------------------------------------------------------- 437 | Uncomment out the selected lines in block comments style. 438 | -------------------------------------------------------------------------*/ 439 | macro simcUncommentBlockOut() 440 | { 441 | var hWnd; hWnd = GetCurrentWnd() 442 | var hBuf; hBuf = GetCurrentBuf() 443 | var rSelOrig; rSelOrig = GetWndSel(hWnd) 444 | var lnCurrentLine; lnCurrentLine = rSelOrig.lnFirst 445 | var sCurrentLine 446 | var TOKEN_BEG; TOKEN_BEG = "/*" 447 | var TOKEN_MID; TOKEN_MID = "*" 448 | var TOKEN_END; TOKEN_END = "*/" 449 | var TAB; TAB = CharFromAscii(9) 450 | var SPACE; SPACE = CharFromAscii(32) 451 | 452 | while lnCurrentLine <= rSelOrig.lnLast 453 | { 454 | sCurrentLine = GetBufLine(hBuf, lnCurrentLine) 455 | if __str_only_contain(sCurrentLine, TOKEN_MID # SPACE # TAB) // performance consideration 456 | { 457 | PutBufLine(hBuf, lnCurrentLine, "") 458 | lnCurrentLine++ 459 | } 460 | else if __str_only_contain(sCurrentLine, TOKEN_BEG # TOKEN_END # SPACE # TAB) // performance consideration 461 | { 462 | DelBufLine(hBuf, lnCurrentLine) 463 | 464 | if (rSelOrig.lnLast > rSelOrig.lnFirst) 465 | rSelOrig.lnLast = rSelOrig.lnLast - 1 // the first line has been removed, no need to ++ 466 | else 467 | lnCurrentLine++ 468 | } 469 | else 470 | { 471 | if __str_begin_with(sCurrentLine, TOKEN_BEG) 472 | sCurrentLine = __str_lstrip(sCurrentLine, TOKEN_BEG # TAB # SPACE) 473 | 474 | if __str_begin_with(sCurrentLine, TOKEN_MID) 475 | { 476 | sCurrentLine = __str_lstrip(sCurrentLine, TOKEN_MID # TAB # SPACE) 477 | } 478 | 479 | if __str_end_with(sCurrentLine, TOKEN_END) 480 | sCurrentLine = __str_rstrip(sCurrentLine, TOKEN_END # TAB # SPACE) 481 | 482 | PutBufLine(hBuf, lnCurrentLine, sCurrentLine) 483 | lnCurrentLine++ 484 | } 485 | } 486 | } 487 | 488 | /*------------------------------------------------------------------------- 489 | Trims white spaces from the ends of the selected lines in the current 490 | file buffer, if the selection is empty, it does the whole file. 491 | -------------------------------------------------------------------------*/ 492 | macro simcTrimSpaces() 493 | { 494 | var TAB; TAB = CharFromAscii(9) 495 | var SPACE; SPACE = CharFromAscii(32) 496 | var hBuf; hBuf = GetCurrentBuf() 497 | var hWnd; hWnd = GetCurrentWnd() 498 | var rSel; rSel = GetWndSel(hWnd) 499 | var lnCurrent; lnCurrent = rSel.lnFirst 500 | 501 | while (lnCurrent <= rSel.lnLast) 502 | { 503 | PutBufLine(hBuf, lnCurrent, __str_rstrip(GetBufLine(hBuf, lnCurrent), SPACE # TAB)) 504 | lnCurrent++ 505 | } 506 | } 507 | 508 | /*------------------------------------------------------------------------- 509 | Paste what in the clipboard to every selected line at the position of 510 | the cursor in the first line. 511 | -------------------------------------------------------------------------*/ 512 | macro simcBatchInsert() 513 | { 514 | var hBuf; hBuf = GetCurrentBuf() 515 | var hWnd; hWnd = GetCurrentWnd() 516 | var rSel; rSel = GetWndSel(hWnd) 517 | var rCursor; 518 | var sLineBefore 519 | var sLineAfter 520 | var sClipboard 521 | var lnCurrentLine;lnCurrentLine = rSel.lnFirst 522 | 523 | // read content from clipboard 524 | sLineBefore = GetBufLine(hBuf, rSel.lnFirst) 525 | PasteBufLine(hBuf, rSel.lnFirst) 526 | sLineAfter = GetBufLine(hBuf, rSel.lnFirst) 527 | PutBufLine(hBuf, rSel.lnFirst, sLineBefore) 528 | sClipboard= __str_subtract(sLineAfter, sLineBefore) 529 | 530 | // generate the cursor selection 531 | rCursor = rSel 532 | rCursor.ichLim = rCursor.ichFirst 533 | rCursor.fExtended = False 534 | 535 | while (lnCurrentLine <= rSel.lnLast) 536 | { 537 | rCursor.lnFirst = lnCurrentLine 538 | rCursor.lnLast = rCursor.lnFirst 539 | 540 | if (strlen(GetBufLine(hBuf, lnCurrentLine)) < rCursor.ichFirst) 541 | PutBufLine(hBuf, lnCurrentLine, __str_padding(GetBufLine(hBuf, lnCurrentLine), rCursor.ichFirst)) 542 | 543 | SetWndSel(hWnd, rCursor) 544 | SetBufSelText(hBuf, sClipboard) 545 | lnCurrentLine++ 546 | } 547 | } 548 | 549 | /*------------------------------------------------------------------------- 550 | This macro allows users to bind macros with keys in Emacs style, e.g. 551 | , in this case, macro simcEmacsStyleKeyBinding is binded 552 | to , and is binded to the macro or command that the user 553 | want to execute. 554 | 555 | The main function of this macro is to extend the number of key bindings 556 | -------------------------------------------------------------------------*/ 557 | macro simcEmacsStyleKeyBinding() 558 | { 559 | var hBuf; hBuf = GetCurrentBuf() 560 | var hWnd; hWnd = GetCurrentWnd() 561 | var rSel; rSel = GetWndSel(hWnd) 562 | var functionKey; functionKey = GetKey() 563 | 564 | // Map the functionKey code into a simple character. 565 | ch = CharFromKey(functionKey) 566 | 567 | if ch == "w" 568 | simcCloseAllNonDirtyWindow 569 | else if ch == "s" 570 | simcSurrounder 571 | else if ch == "c" 572 | simcCommentLineOut 573 | else if ch == "C" 574 | simcUncommentLineOut 575 | else if ch == "b" 576 | simcCommentBlockOut 577 | else if ch == "B" 578 | simcUncommentBlockOut 579 | else if ch == "t" 580 | simcTrimSpaces 581 | else if ch == "d" 582 | simcMatchDelimiter 583 | else if ch == "i" 584 | simcBatchInsert 585 | } 586 | 587 | /*------------------------------------------------------------------------- 588 | Macro command that performs a progressive forward search as the user types, 589 | the search is case-insensitive and regex is not supported. 590 | 591 | Quit progressive search with 'Enter' 592 | -------------------------------------------------------------------------*/ 593 | macro simcProgressiveSearch() 594 | { 595 | var hBuf; hBuf = GetCurrentBuf() 596 | var hWnd; hWnd = GetCurrentWnd() 597 | var rSel; rSel = GetWndSel(hWnd) 598 | var rSearchRes 599 | var iKeyCode 600 | var cChar 601 | var sSearchStr; sSearchStr = "" 602 | 603 | while 1 604 | { 605 | iKeyCode = GetKey() 606 | cChar = CharFromKey(iKeyCode) 607 | 608 | if iKeyCode == 13 // Enter - perform search 609 | stop 610 | else if iKeyCode == 8 // Backspace 611 | { 612 | if strlen(sSearchStr) > 0 613 | sSearchStr = strtrunc(sSearchStr, strlen(sSearchStr)-1) 614 | else 615 | continue 616 | } 617 | else 618 | sSearchStr = cat(sSearchStr, cChar) 619 | 620 | rSearchRes = SearchInBuf(hBuf, sSearchStr, rSel.lnFirst, rSel.ichFirst, 0, 0, 0) 621 | 622 | // wrap search 623 | if rSearchRes == "" 624 | rSearchRes = SearchInBuf(hBuf, sSearchStr, 0, 0, 0, 0, 0) 625 | 626 | if rSearchRes!= "" 627 | { 628 | ScrollWndToLine(hWnd, rSearchRes.lnFirst) 629 | SetWndSel(hWnd, rSearchRes) 630 | LoadSearchPattern(sSearchStr, 0, 0, 0) 631 | } 632 | } 633 | } 634 | 635 | macro simcJumpForward() 636 | { 637 | var hBuf; hBuf = GetCurrentBuf() 638 | var hWnd; hWnd = GetCurrentWnd() 639 | var rSel; rSel = GetWndSel(hWnd) 640 | var rSearchRes 641 | var iKeyCode 642 | var cChar 643 | var sSearchStr; sSearchStr = "" 644 | 645 | while 1 646 | { 647 | iKeyCode = GetKey() 648 | cChar = CharFromKey(iKeyCode) 649 | 650 | if iKeyCode == 13 // Enter - perform search 651 | break 652 | else if iKeyCode == 8 // Backspace 653 | { 654 | if strlen(sSearchStr) > 0 655 | sSearchStr = strtrunc(sSearchStr, strlen(sSearchStr)-1) 656 | else 657 | continue 658 | } 659 | else 660 | sSearchStr = cat(sSearchStr, cChar) 661 | 662 | } 663 | LoadSearchPattern(sSearchStr, 0, 0, 0) 664 | Search_Forward 665 | } 666 | 667 | macro simcJumpBackward() 668 | { 669 | var hBuf; hBuf = GetCurrentBuf() 670 | var hWnd; hWnd = GetCurrentWnd() 671 | var rSel; rSel = GetWndSel(hWnd) 672 | var rSearchRes 673 | var iKeyCode 674 | var cChar 675 | var sSearchStr; sSearchStr = "" 676 | 677 | while 1 678 | { 679 | iKeyCode = GetKey() 680 | cChar = CharFromKey(iKeyCode) 681 | 682 | if iKeyCode == 13 // Enter - perform search 683 | break 684 | else if iKeyCode == 8 // Backspace 685 | { 686 | if strlen(sSearchStr) > 0 687 | sSearchStr = strtrunc(sSearchStr, strlen(sSearchStr)-1) 688 | else 689 | continue 690 | } 691 | else 692 | sSearchStr = cat(sSearchStr, cChar) 693 | 694 | } 695 | LoadSearchPattern(sSearchStr, 0, 0, 0) 696 | Search_Backward 697 | } 698 | 699 | /*------------------------------------------------------------------------- 700 | Finds matching scoping delimiters and jumps to them. 701 | 702 | If the cursor is not positioned on a delimiter but is inside 703 | a matching part then the macro will jump to the start of the closest 704 | scope. 705 | 706 | Currently matches [], (), <>, {} 707 | -------------------------------------------------------------------------*/ 708 | macro simcMatchDelimiter() 709 | { 710 | var hWnd; hWnd = GetCurrentWnd() 711 | var hBuf; hBuf = GetCurrentBuf() 712 | var rSel; rSel = GetWndSel(hWnd) 713 | var sOpenDelim; sOpenDelim = "[{(<" 714 | var sClosDelim; sClosDelim = "]})>" 715 | var sCurrentLine 716 | var cCurrentChar 717 | var iNumofSquareBracket;iNumofSquareBracket = 0 718 | var iNumofParentheses;iNumofParentheses = 0 719 | var iNumofFrenchQuotes;iNumofFrenchQuotes = 0 720 | var iNumofBrace;iNumofBrace = 0 721 | 722 | sCurrentLine = GetBufLine(hBuf, rSel.lnFirst) 723 | cCurrentChar = sCurrentLine[rSel.ichFirst] 724 | 725 | if(__str_contain(sOpenDelim, cCurrentChar)) 726 | jump_to_match 727 | else if(__str_contain(sClosDelim, cCurrentChar)) 728 | jump_to_match 729 | else 730 | { 731 | while 1 732 | { 733 | LoadSearchPattern("[\\[(<{}>)\\]]", 0, 1, 0) 734 | search_backward 735 | rSel = GetWndSel(hWnd) 736 | 737 | sCurrentLine = GetBufLine(hBuf, rSel.lnFirst) 738 | cCurrentChar = sCurrentLine[rSel.ichFirst] 739 | 740 | if cCurrentChar == "[" 741 | iNumofSquareBracket++ 742 | else if cCurrentChar == "]" 743 | iNumofSquareBracket-- 744 | else if cCurrentChar == "{" 745 | iNumofBrace++ 746 | else if cCurrentChar == "}" 747 | iNumofBrace-- 748 | else if cCurrentChar == "(" 749 | iNumofParentheses++ 750 | else if cCurrentChar == ")" 751 | iNumofParentheses-- 752 | else if cCurrentChar == "<" 753 | iNumofFrenchQuotes++ 754 | else if cCurrentChar == ">" 755 | iNumofFrenchQuotes-- 756 | 757 | if iNumofBrace > 0 || iNumofFrenchQuotes > 0 || iNumofParentheses > 0 || iNumofSquareBracket >0 758 | break 759 | } 760 | } 761 | } 762 | 763 | /*------------------------------------------------------------------------- 764 | Surround the selection with what you type. 765 | 766 | Hit 'Enter' to quit. 767 | -------------------------------------------------------------------------*/ 768 | macro simcSurrounder() 769 | { 770 | var hWnd; hWnd = GetCurrentWnd() 771 | var hBuf; hBuf = GetCurrentBuf() 772 | var rSel; rSel = GetWndSel(hWnd) 773 | var rSelOrig; rSelOrig = rSel 774 | var iKeyCode 775 | var cChar 776 | var sSelection 777 | var iLenSel; iLenSel = strlen(GetBufSelText(hBuf)) 778 | var sSurroundSymbol; sSurroundSymbol = "" 779 | var sSurroundSymbolPrev; sSurroundSymbolPrev = sSurroundSymbol 780 | 781 | if !rSel.fExtended 782 | stop 783 | 784 | while 1 785 | { 786 | SetWndSel(hWnd, rSel) 787 | iKeyCode = GetKey() 788 | cChar = CharFromKey(iKeyCode) 789 | 790 | if iKeyCode == 13 // Enter 791 | stop 792 | else if iKeyCode == 8 // && sSurroundSymbolPrev!= "" // Backspace 793 | { 794 | sSelection = GetBufSelText(hBuf) 795 | 796 | if strlen(sSelection) >= 2 797 | { 798 | SetBufSelText(hBuf, strmid(sSelection, 1, strlen(sSelection)-1)) 799 | 800 | // update selection 801 | rSel.ichLim = rSel.ichLim - 2 802 | } 803 | } 804 | else 805 | { 806 | sSurroundSymbol = cat(sSurroundSymbol, cChar) 807 | 808 | if sSurroundSymbol != "" 809 | { 810 | sSurroundSymbolPrev = sSurroundSymbol 811 | rSel.ichLim = rSel.ichLim + 2 * strlen(sSurroundSymbol) 812 | sSelection = GetBufSelText(hBuf) 813 | 814 | // insert surrounder 815 | if sSurroundSymbol == "(" || sSurroundSymbol == ")" 816 | SetBufSelText(hBuf, cat("(", cat(sSelection, ")"))) 817 | else if sSurroundSymbol == "[" || sSurroundSymbol == "]" 818 | SetBufSelText(hBuf, cat("[", cat(sSelection, "]"))) 819 | else if sSurroundSymbol == "{" || sSurroundSymbol == "}" 820 | SetBufSelText(hBuf, cat("{", cat(sSelection, "}"))) 821 | else if sSurroundSymbol == "<" || sSurroundSymbol == ">" 822 | SetBufSelText(hBuf, cat("<", cat(sSelection, ">"))) 823 | else 824 | SetBufSelText(hBuf, cat(sSurroundSymbol, cat(sSelection, sSurroundSymbol))) 825 | 826 | sSurroundSymbol = "" 827 | } 828 | } 829 | } 830 | } 831 | 832 | 833 | /*------------------------------------------------------------------------- 834 | Return the FIRST different part from string sA, sB must be a substring 835 | of sA. 836 | 837 | for exampele: 838 | 839 | sA = "Hello world!" 840 | sB = "world" 841 | __str_subtract will return: "Hello " 842 | -------------------------------------------------------------------------*/ 843 | macro __str_subtract(sA, sB) 844 | { 845 | var iLenA; iLenA = strlen(sA) 846 | var iLenB; iLenB = strlen(sB) 847 | var iLim; iLim = iLenA - iLenB 848 | var iCh; iCh = 0 849 | 850 | if iLenA <= iLenB // sB must be a substing of sA 851 | return "" 852 | 853 | while iCh <= iLim 854 | { 855 | i = 0 856 | while(sA[iCh+i] == sB[i]) 857 | { 858 | cA = sA[iCh+i] 859 | cB = sB[i] 860 | 861 | if (i < iLenB) 862 | i++ 863 | else 864 | return strmid(sA, 0, iCh) 865 | } 866 | iCh++ 867 | } 868 | } 869 | 870 | /*------------------------------------------------------------------------- 871 | Padding space at the end of the string to length iLen 872 | -------------------------------------------------------------------------*/ 873 | macro __str_padding(sLine, iLen) 874 | { 875 | var iLenLine; iLenLine = strlen(sLine) 876 | var SPACE; SPACE = CharFromAscii(32) 877 | var iLenDiff 878 | 879 | iLenDiff = iLenLine - iLen 880 | 881 | if iLenDiff >= 0 882 | return sLine 883 | 884 | while iLenDiff < 0 885 | { 886 | sLine = cat(sLine, SPACE) 887 | iLenDiff++ 888 | } 889 | 890 | return sLine 891 | } 892 | 893 | /*------------------------------------------------------------------------- 894 | Repeat strings and return the result 895 | -------------------------------------------------------------------------*/ 896 | macro __str_rep(sString, iRepeatTimes) 897 | { 898 | var iIndex; iIndex = 0 899 | var sRet; sRet = "" 900 | 901 | while (iIndex++ < iRepeatTimes) 902 | { 903 | sRet = sRet # sString 904 | } 905 | 906 | return sRet 907 | } 908 | 909 | /*------------------------------------------------------------------------- 910 | If string contains substring, return True, else False 911 | -------------------------------------------------------------------------*/ 912 | macro __str_contain(sStr, sSubStr) 913 | { 914 | var iStrLen; iStrLen = strlen(sStr) 915 | var iSubStrLen; iSubStrLen = strlen(sSubStr) 916 | var iChar; iChar = 0 917 | var iChStrLim; iChStrLim = iStrLen - iSubStrLen 918 | 919 | // every string contains a trailing "" 920 | if(iSubStrLen == 0) 921 | return True 922 | 923 | while (iChar <= iChStrLim) 924 | { 925 | if (iSubStrLen != 1) 926 | { 927 | if (strmid(sStr, iChar, iChar+iSubStrLen) == sSubStr) 928 | return True 929 | } 930 | else 931 | { 932 | // this will improve the performance dramatically! 933 | if (sStr[iChar] == sSubStr) 934 | return True 935 | } 936 | 937 | iChar++ 938 | } 939 | return False 940 | } 941 | 942 | /*------------------------------------------------------------------------- 943 | If string only contains chars which in substring, return True, else False 944 | -------------------------------------------------------------------------*/ 945 | macro __str_only_contain(sStr, sSubStr) 946 | { 947 | var iStrLen; iStrLen = strlen(sStr) 948 | var iSubStrLen; iSubStrLen = strlen(sSubStr) 949 | var iChStr; iChStr = 0 950 | var iChSubStr; iChSubStr = 0 951 | var cCharInStr 952 | 953 | while (iChStr <= iStrLen) 954 | { 955 | cCharInStr = sStr[iChStr++] 956 | 957 | if !(__str_contain(sSubStr, cCharInStr)) 958 | return False 959 | } 960 | return True 961 | } 962 | 963 | /*------------------------------------------------------------------------- 964 | If string begins with substring, then return true. 965 | 966 | the prefix spaces/tabs are ignored. 967 | -------------------------------------------------------------------------*/ 968 | macro __str_begin_with(sStr, sSubStr) 969 | { 970 | var TAB; TAB = CharFromAscii(9) 971 | var SPACE; SPACE = CharFromAscii(32) 972 | 973 | sStr = __str_lstrip(sStr, TAB # SPACE) 974 | sSubStr = __str_lstrip(sSubStr, TAB # SPACE) 975 | var iStrLen; iStrLen = strlen(sStr) 976 | var iSubStrLen; iSubStrLen = strlen(sSubStr) 977 | 978 | if iSubStrLen > iStrLen 979 | return False 980 | 981 | if (strmid(sStr, 0, iSubStrLen) == sSubStr) 982 | return True 983 | else 984 | return False 985 | } 986 | 987 | /*------------------------------------------------------------------------- 988 | If string ends with substring, then return true. 989 | 990 | the suffix spaces/tabs are ignored. 991 | -------------------------------------------------------------------------*/ 992 | macro __str_end_with(sStr, sSubStr) 993 | { 994 | 995 | var TAB; TAB = CharFromAscii(9) 996 | var SPACE; SPACE = CharFromAscii(32) 997 | 998 | sStr = __str_rstrip(sStr, TAB # SPACE) 999 | sSubStr = __str_rstrip(sSubStr, TAB # SPACE) 1000 | var iStrLen; iStrLen = strlen(sStr) 1001 | var iSubStrLen; iSubStrLen = strlen(sSubStr) 1002 | 1003 | if iSubStrLen > iStrLen 1004 | return False 1005 | 1006 | if (strmid(sStr, iStrLen-iSubStrLen, iStrLen) == sSubStr) 1007 | return True 1008 | else 1009 | return False 1010 | 1011 | } 1012 | 1013 | /*------------------------------------------------------------------------- 1014 | returns a copy of the string in which all chars in sSubStr have been 1015 | stripped from the beginning of the string. 1016 | -------------------------------------------------------------------------*/ 1017 | macro __str_lstrip(sStr, sSubStr) 1018 | { 1019 | var iStrLen; iStrLen = strlen(sStr) 1020 | var cCharInStr 1021 | var iCharInStr; iCharInStr = 0 1022 | 1023 | while iCharInStr < iStrLen 1024 | { 1025 | cCharInStr = sStr[iCharInStr] 1026 | s = strmid(sStr, iCharInStr, iStrLen) 1027 | 1028 | if !__str_contain(sSubStr, cCharInStr) 1029 | { 1030 | return strmid(sStr, iCharInStr, iStrLen) 1031 | } 1032 | 1033 | iCharInStr++ 1034 | } 1035 | return "" 1036 | } 1037 | 1038 | /*------------------------------------------------------------------------- 1039 | returns a copy of the string in which all chars in sSubStr have been 1040 | stripped from the ending of the string. 1041 | -------------------------------------------------------------------------*/ 1042 | macro __str_rstrip(sStr, sSubStr) 1043 | { 1044 | var iStrLen; iStrLen = strlen(sStr) 1045 | var cCharInStr 1046 | var iCharInStr 1047 | 1048 | if (iStrLen == 0) 1049 | return "" 1050 | 1051 | iCharInStr = iStrLen - 1 1052 | while(iCharInStr >= 0) 1053 | { 1054 | cCharInStr = sStr[iCharInStr] 1055 | 1056 | 1057 | if !(__str_contain(sSubStr, cCharInStr)) 1058 | return strmid(sStr, 0, iCharInStr+1) 1059 | 1060 | iCharInStr-- 1061 | } 1062 | return "" 1063 | } 1064 | 1065 | /*------------------------------------------------------------------------- 1066 | strip the substr from the str in left and right side and return the 1067 | stripped string. 1068 | 1069 | the prefix and suffix spaces/tabs are stripped by default. 1070 | -------------------------------------------------------------------------*/ 1071 | macro __str_strip(sStr, sSubStr) 1072 | { 1073 | var sStrStripped 1074 | 1075 | sStrStripped = __str_lstrip(sStr, sSubStr) 1076 | sStrStripped = __str_rstrip(sStrStripped, sSubStr) 1077 | 1078 | return sStrStripped 1079 | } 1080 | 1081 | -------------------------------------------------------------------------------- /simcUnitTests.em: -------------------------------------------------------------------------------- 1 | macro runAllUnitTests() 2 | { 3 | unitTest_str_lstrip() 4 | unitTest_str_rstrip() 5 | unitTest_str_contain() 6 | unitTest_str_only_contain() 7 | unitTest_str_strip() 8 | unitTest_str_begin_with() 9 | unitTest_str_end_with() 10 | unitTest_str_rep() 11 | unitTest_str_padding() 12 | unitTest_str_subtract() 13 | } 14 | 15 | macro unitTest_str_subtract() 16 | { 17 | sSub = " * #include " 18 | 19 | s = __str_subtract(cat("success", sSub), sSub) 20 | 21 | if s == "success" 22 | inf("__str_subtract() passed") 23 | else 24 | err("__str_subtract() failed") 25 | } 26 | 27 | macro unitTest_str_padding() 28 | { 29 | sSub = " * #include " 30 | 31 | s = __str_padding(sSub, strlen(sSub)+3) 32 | 33 | if s == cat(sSub, " ") 34 | inf("__str_padding() passed") 35 | else 36 | err("__str_padding() failed") 37 | } 38 | 39 | macro unitTest_str_rep() 40 | { 41 | sSub = " * #include " 42 | 43 | s = __str_rep(sSub, 3) 44 | 45 | if s == cat(cat(sSub, sSub), sSub) 46 | inf("__str_rep() passed") 47 | else 48 | err("__str_rep() failed") 49 | } 50 | 51 | macro unitTest_str_begin_with() 52 | { 53 | sSub = " * #include " 54 | 55 | s = __str_begin_with(cat(sSub, "success"), sSub) 56 | 57 | if s 58 | inf("__str_begin_with() passed") 59 | else 60 | err("__str_begin_with() failed") 61 | } 62 | 63 | macro unitTest_str_end_with() 64 | { 65 | sSub = " * #include " 66 | 67 | s = __str_end_with(cat("success", sSub), sSub) 68 | 69 | if s 70 | inf("__str_end_with() passed") 71 | else 72 | err("__str_end_with() failed") 73 | } 74 | 75 | 76 | macro unitTest_str_lstrip() 77 | { 78 | sSub = " * #include " 79 | 80 | s = __str_lstrip(cat(sSub, "success"), sSub) 81 | 82 | if s == "success" 83 | inf("__str_lstrip() passed") 84 | else 85 | err("__str_lstrip() failed") 86 | } 87 | 88 | macro unitTest_str_rstrip() 89 | { 90 | sSub = " * #include " 91 | 92 | s = __str_rstrip(cat("success", sSub), sSub) 93 | 94 | if s == "success" 95 | inf("__str_rstrip() passed") 96 | else 97 | err("__str_rstrip() failed") 98 | } 99 | 100 | macro unitTest_str_contain() 101 | { 102 | sStr = ">" 103 | sSubStr = ">" 104 | if !__str_contain(sStr, sSubStr) 105 | err("__str_contain() failed") 106 | 107 | sStr = " * #include " 108 | sSubStr = " * #incl >" 109 | if __str_contain(sStr, sSubStr) 110 | err("__str_contain() failed") 111 | 112 | inf("__str_contain() passed") 113 | } 114 | 115 | macro unitTest_str_only_contain() 116 | { 117 | sStr = "> !#$%%^&&*()" 118 | sSubStr = ")(*&^%$#! >" 119 | 120 | if !__str_only_contain(sStr, sSubStr) 121 | err("__str_only_contain() failed") 122 | 123 | sStr = " * #include " 124 | sSubStr = " * #incl <" 125 | if __str_contain(sStr, sSubStr) 126 | err("__str_only_contain() failed") 127 | 128 | inf("__str_only_contain() passed") 129 | 130 | } 131 | macro unitTest_str_strip() 132 | { 133 | tag = " * #/<>" 134 | s = cat(cat(tag, "success"), tag) 135 | 136 | s = __str_strip(s, tag) 137 | 138 | if s == "success" 139 | inf("__str_strip() passed") 140 | else 141 | err("__str_strip() failed") 142 | 143 | } 144 | 145 | macro inf(message) 146 | { 147 | msg(message) 148 | } 149 | macro err(message) 150 | { 151 | msg(message) 152 | stop 153 | } 154 | -------------------------------------------------------------------------------- /snippets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5shi/SourceInsightMacroCollection/5f12d607711d1289c075fbe517683e74e847b6bf/snippets.gif -------------------------------------------------------------------------------- /surrounder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5shi/SourceInsightMacroCollection/5f12d607711d1289c075fbe517683e74e847b6bf/surrounder.gif --------------------------------------------------------------------------------