The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
9.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #include "../../Application/jucer_Headers.h"
  14. #include "jucer_CodeHelpers.h"
  15. //==============================================================================
  16. namespace CodeHelpers
  17. {
  18. String indent (const String& code, const int numSpaces, bool indentFirstLine)
  19. {
  20. if (numSpaces == 0)
  21. return code;
  22. auto space = String::repeatedString (" ", numSpaces);
  23. auto lines = StringArray::fromLines (code);
  24. for (auto& line : lines)
  25. {
  26. if (! indentFirstLine)
  27. {
  28. indentFirstLine = true;
  29. continue;
  30. }
  31. if (line.trimEnd().isNotEmpty())
  32. line = space + line;
  33. }
  34. return lines.joinIntoString (newLine);
  35. }
  36. String unindent (const String& code, const int numSpaces)
  37. {
  38. if (numSpaces == 0)
  39. return code;
  40. auto space = String::repeatedString (" ", numSpaces);
  41. auto lines = StringArray::fromLines (code);
  42. for (auto& line : lines)
  43. if (line.startsWith (space))
  44. line = line.substring (numSpaces);
  45. return lines.joinIntoString (newLine);
  46. }
  47. String createIncludeStatement (const File& includeFile, const File& targetFile)
  48. {
  49. return createIncludeStatement (build_tools::unixStylePath (build_tools::getRelativePathFrom (includeFile, targetFile.getParentDirectory())));
  50. }
  51. String createIncludeStatement (const String& includePath)
  52. {
  53. if (includePath.startsWithChar ('<') || includePath.startsWithChar ('"'))
  54. return "#include " + includePath;
  55. return "#include \"" + includePath + "\"";
  56. }
  57. String createIncludePathIncludeStatement (const String& includedFilename)
  58. {
  59. return "#include <" + includedFilename + ">";
  60. }
  61. String stringLiteral (const String& text, int maxLineLength)
  62. {
  63. if (text.isEmpty())
  64. return "String()";
  65. StringArray lines;
  66. {
  67. auto t = text.getCharPointer();
  68. bool finished = t.isEmpty();
  69. while (! finished)
  70. {
  71. for (auto startOfLine = t;;)
  72. {
  73. switch (t.getAndAdvance())
  74. {
  75. case 0: finished = true; break;
  76. case '\n': break;
  77. case '\r': if (*t == '\n') ++t; break;
  78. default: continue;
  79. }
  80. lines.add (String (startOfLine, t));
  81. break;
  82. }
  83. }
  84. }
  85. if (maxLineLength > 0)
  86. {
  87. for (int i = 0; i < lines.size(); ++i)
  88. {
  89. auto& line = lines.getReference (i);
  90. if (line.length() > maxLineLength)
  91. {
  92. const String start (line.substring (0, maxLineLength));
  93. const String end (line.substring (maxLineLength));
  94. line = start;
  95. lines.insert (i + 1, end);
  96. }
  97. }
  98. }
  99. for (int i = 0; i < lines.size(); ++i)
  100. lines.getReference(i) = CppTokeniserFunctions::addEscapeChars (lines.getReference(i));
  101. lines.removeEmptyStrings();
  102. for (int i = 0; i < lines.size(); ++i)
  103. lines.getReference(i) = "\"" + lines.getReference(i) + "\"";
  104. String result (lines.joinIntoString (newLine));
  105. if (! CharPointer_ASCII::isValidString (text.toUTF8(), std::numeric_limits<int>::max()))
  106. result = "CharPointer_UTF8 (" + result + ")";
  107. return result;
  108. }
  109. String alignFunctionCallParams (const String& call, const StringArray& parameters, const int maxLineLength)
  110. {
  111. String result, currentLine (call);
  112. for (int i = 0; i < parameters.size(); ++i)
  113. {
  114. if (currentLine.length() >= maxLineLength)
  115. {
  116. result += currentLine.trimEnd() + newLine;
  117. currentLine = String::repeatedString (" ", call.length()) + parameters[i];
  118. }
  119. else
  120. {
  121. currentLine += parameters[i];
  122. }
  123. if (i < parameters.size() - 1)
  124. currentLine << ", ";
  125. }
  126. return result + currentLine.trimEnd() + ")";
  127. }
  128. String floatLiteral (double value, int numDecPlaces)
  129. {
  130. String s (value, numDecPlaces);
  131. if (s.containsChar ('.'))
  132. s << 'f';
  133. else
  134. s << ".0f";
  135. return s;
  136. }
  137. String boolLiteral (bool value)
  138. {
  139. return value ? "true" : "false";
  140. }
  141. String colourToCode (Colour col)
  142. {
  143. const Colour colours[] =
  144. {
  145. #define COL(col) Colours::col,
  146. #include "jucer_Colours.h"
  147. #undef COL
  148. Colours::transparentBlack
  149. };
  150. static const char* colourNames[] =
  151. {
  152. #define COL(col) #col,
  153. #include "jucer_Colours.h"
  154. #undef COL
  155. nullptr
  156. };
  157. for (int i = 0; i < numElementsInArray (colourNames) - 1; ++i)
  158. if (col == colours[i])
  159. return "Colours::" + String (colourNames[i]);
  160. return "Colour (0x" + build_tools::hexString8Digits ((int) col.getARGB()) + ')';
  161. }
  162. String justificationToCode (Justification justification)
  163. {
  164. switch (justification.getFlags())
  165. {
  166. case Justification::centred: return "Justification::centred";
  167. case Justification::centredLeft: return "Justification::centredLeft";
  168. case Justification::centredRight: return "Justification::centredRight";
  169. case Justification::centredTop: return "Justification::centredTop";
  170. case Justification::centredBottom: return "Justification::centredBottom";
  171. case Justification::topLeft: return "Justification::topLeft";
  172. case Justification::topRight: return "Justification::topRight";
  173. case Justification::bottomLeft: return "Justification::bottomLeft";
  174. case Justification::bottomRight: return "Justification::bottomRight";
  175. case Justification::left: return "Justification::left";
  176. case Justification::right: return "Justification::right";
  177. case Justification::horizontallyCentred: return "Justification::horizontallyCentred";
  178. case Justification::top: return "Justification::top";
  179. case Justification::bottom: return "Justification::bottom";
  180. case Justification::verticallyCentred: return "Justification::verticallyCentred";
  181. case Justification::horizontallyJustified: return "Justification::horizontallyJustified";
  182. default: break;
  183. }
  184. jassertfalse;
  185. return "Justification (" + String (justification.getFlags()) + ")";
  186. }
  187. //==============================================================================
  188. String getLeadingWhitespace (String line)
  189. {
  190. line = line.removeCharacters (line.endsWith ("\r\n") ? "\r\n" : "\n");
  191. auto endOfLeadingWS = line.getCharPointer().findEndOfWhitespace();
  192. return String (line.getCharPointer(), endOfLeadingWS);
  193. }
  194. int getBraceCount (String::CharPointerType line)
  195. {
  196. int braces = 0;
  197. for (;;)
  198. {
  199. const juce_wchar c = line.getAndAdvance();
  200. if (c == 0) break;
  201. else if (c == '{') ++braces;
  202. else if (c == '}') --braces;
  203. else if (c == '/') { if (*line == '/') break; }
  204. else if (c == '"' || c == '\'') { while (! (line.isEmpty() || line.getAndAdvance() == c)) {} }
  205. }
  206. return braces;
  207. }
  208. bool getIndentForCurrentBlock (CodeDocument::Position pos, const String& tab,
  209. String& blockIndent, String& lastLineIndent)
  210. {
  211. int braceCount = 0;
  212. bool indentFound = false;
  213. while (pos.getLineNumber() > 0)
  214. {
  215. pos = pos.movedByLines (-1);
  216. auto line = pos.getLineText();
  217. auto trimmedLine = line.trimStart();
  218. braceCount += getBraceCount (trimmedLine.getCharPointer());
  219. if (braceCount > 0)
  220. {
  221. blockIndent = getLeadingWhitespace (line);
  222. if (! indentFound)
  223. lastLineIndent = blockIndent + tab;
  224. return true;
  225. }
  226. if ((! indentFound) && trimmedLine.isNotEmpty())
  227. {
  228. indentFound = true;
  229. lastLineIndent = getLeadingWhitespace (line);
  230. }
  231. }
  232. return false;
  233. }
  234. }