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.

302 lines
10KB

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