@@ -66,16 +66,10 @@ void SourceCodeDocument::reloadInternal() | |||
auto fileContent = getFile().loadFileAsString(); | |||
auto lineFeed = [&]() -> const char* | |||
{ | |||
if (fileContent.contains ("\r\n")) | |||
return "\r\n"; | |||
if (fileContent.contains ("\n")) | |||
return "\n"; | |||
auto lineFeed = getLineFeedForFile (fileContent); | |||
return project->getProjectLineFeed().toRawUTF8(); | |||
}(); | |||
if (lineFeed.isEmpty()) | |||
lineFeed = project->getProjectLineFeed(); | |||
codeDoc->setNewLineCharacters (lineFeed); | |||
@@ -98,7 +98,7 @@ void JucerDocument::timerCallback() | |||
stopTimer(); | |||
beginTransaction(); | |||
flushChangesToDocuments (nullptr); | |||
flushChangesToDocuments (nullptr, false); | |||
} | |||
} | |||
@@ -513,23 +513,7 @@ bool JucerDocument::findTemplateFiles (String& headerContent, String& cppContent | |||
return true; | |||
} | |||
static String fixLineEndings (const String& s, const char* lineFeed) | |||
{ | |||
StringArray lines; | |||
lines.addLines (s); | |||
for (int i = 0; i < lines.size(); ++i) | |||
lines.set (i, lines[i].trimEnd()); | |||
while (lines.size() > 0 && lines [lines.size() - 1].trim().isEmpty()) | |||
lines.remove (lines.size() - 1); | |||
lines.add (String()); | |||
return lines.joinIntoString (lineFeed); | |||
} | |||
bool JucerDocument::flushChangesToDocuments (Project* project) | |||
bool JucerDocument::flushChangesToDocuments (Project* project, bool isInitial) | |||
{ | |||
String headerTemplate, cppTemplate; | |||
if (! findTemplateFiles (headerTemplate, cppTemplate)) | |||
@@ -554,10 +538,20 @@ bool JucerDocument::flushChangesToDocuments (Project* project) | |||
generated.applyToCode (cppTemplate, headerFile.withFileExtension (".cpp"), | |||
existingCpp, project); | |||
auto* lineFeed = project->getProjectLineFeed().toRawUTF8(); | |||
if (isInitial) | |||
{ | |||
jassert (project != nullptr); | |||
auto lineFeed = project->getProjectLineFeed(); | |||
headerTemplate = fixLineEndings (headerTemplate, lineFeed); | |||
cppTemplate = fixLineEndings (cppTemplate, lineFeed); | |||
headerTemplate = replaceLineFeeds (headerTemplate, lineFeed); | |||
cppTemplate = replaceLineFeeds (cppTemplate, lineFeed); | |||
} | |||
else | |||
{ | |||
headerTemplate = replaceLineFeeds (headerTemplate, getLineFeedForFile (existingHeader)); | |||
cppTemplate = replaceLineFeeds (cppTemplate, getLineFeedForFile (existingCpp)); | |||
} | |||
if (header->getCodeDocument().getAllContent() != headerTemplate) | |||
header->getCodeDocument().replaceAllContent (headerTemplate); | |||
@@ -780,7 +774,7 @@ struct NewGUIComponentWizard : public NewFileWizard::Type | |||
{ | |||
jucerDoc->setClassName (newFile.getFileNameWithoutExtension()); | |||
jucerDoc->flushChangesToDocuments (&project); | |||
jucerDoc->flushChangesToDocuments (&project, true); | |||
jucerDoc.reset(); | |||
cpp->save(); | |||
@@ -58,7 +58,7 @@ public: | |||
File getCppFile() const { return cpp->getFile(); } | |||
File getHeaderFile() const { return getCppFile().withFileExtension (".h"); } | |||
bool flushChangesToDocuments (Project*); | |||
bool flushChangesToDocuments (Project*, bool); | |||
bool reloadFromDocument(); | |||
//============================================================================== | |||
@@ -253,6 +253,8 @@ public: | |||
void writeFile (const File& gradleProjectFolder, const String& filePath, const String& fileContent) const | |||
{ | |||
MemoryOutputStream outStream; | |||
outStream.setNewLineString ("\n"); | |||
outStream << fileContent; | |||
overwriteFileIfDifferentOrThrow (gradleProjectFolder.getChildFile (filePath), outStream); | |||
} | |||
@@ -260,6 +262,8 @@ public: | |||
void writeBinaryFile (const File& gradleProjectFolder, const String& filePath, const char* binaryData, const int binarySize) const | |||
{ | |||
MemoryOutputStream outStream; | |||
outStream.setNewLineString ("\n"); | |||
outStream.write (binaryData, static_cast<size_t> (binarySize)); | |||
overwriteFileIfDifferentOrThrow (gradleProjectFolder.getChildFile (filePath), outStream); | |||
} | |||
@@ -350,6 +354,7 @@ private: | |||
void writeCmakeFile (const File& file) const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << "# Automatically generated makefile, created by the Projucer" << newLine | |||
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Projucer project!" << newLine | |||
@@ -544,6 +549,7 @@ private: | |||
String getProjectBuildGradleFileContent() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << "buildscript {" << newLine; | |||
mo << " repositories {" << newLine; | |||
@@ -581,6 +587,8 @@ private: | |||
String getAppBuildGradleFileContent (const OwnedArray<LibraryModule>& modules) const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << "apply plugin: 'com.android." << (isLibrary() ? "library" : "application") << "'" << newLine << newLine; | |||
mo << "android {" << newLine; | |||
@@ -610,6 +618,7 @@ private: | |||
String getAndroidProductFlavours() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << " flavorDimensions \"default\"" << newLine; | |||
mo << " productFlavors {" << newLine; | |||
@@ -653,6 +662,7 @@ private: | |||
String getAndroidSigningConfig() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
auto keyStoreFilePath = androidKeyStore.get().toString().replace ("${user.home}", "${System.properties['user.home']}") | |||
.replace ("/", "${File.separator}"); | |||
@@ -680,6 +690,7 @@ private: | |||
auto targetSdkVersion = static_cast<int> (androidTargetSDK.get()); | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << " defaultConfig {" << newLine; | |||
@@ -710,6 +721,7 @@ private: | |||
String getAndroidBuildTypes() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << " buildTypes {" << newLine; | |||
@@ -740,6 +752,7 @@ private: | |||
String getAndroidVariantFilter() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << " variantFilter { variant ->" << newLine; | |||
mo << " def names = variant.flavors*.name" << newLine; | |||
@@ -762,6 +775,7 @@ private: | |||
String getAndroidRepositories() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
auto repositories = StringArray::fromLines (androidRepositories.get().toString()); | |||
@@ -778,6 +792,8 @@ private: | |||
String getAndroidDependencies() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << " dependencies {" << newLine; | |||
for (auto& d : StringArray::fromLines (androidDependencies.get().toString())) | |||
@@ -800,6 +816,7 @@ private: | |||
String getApplyPlugins() const | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
if (androidEnableRemoteNotifications.get()) | |||
mo << "apply plugin: 'com.google.gms.google-services'" << newLine; | |||
@@ -834,6 +851,8 @@ private: | |||
} | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
mo << " sourceSets {" << newLine; | |||
mo << getSourceSetStringFor ("main.java.srcDirs", javaSourceSets); | |||
mo << newLine; | |||
@@ -888,7 +907,7 @@ private: | |||
s << "]" << newLine; | |||
return s; | |||
return replaceLineFeeds (s, "\n"); | |||
} | |||
//============================================================================== | |||
@@ -899,7 +918,7 @@ private: | |||
props << "ndk.dir=" << sanitisePath (getAppSettings().getStoredPath (Ids::androidNDKPath, TargetOS::getThisOS()).get().toString()) << newLine | |||
<< "sdk.dir=" << sanitisePath (getAppSettings().getStoredPath (Ids::androidSDKPath, TargetOS::getThisOS()).get().toString()) << newLine; | |||
return props; | |||
return replaceLineFeeds (props, "\n"); | |||
} | |||
String getGradleWrapperPropertiesFileContent() const | |||
@@ -1186,7 +1205,9 @@ private: | |||
createDirectoryOrThrow (file.getParentDirectory()); | |||
PNGImageFormat png; | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
if (! png.writeImageToStream (im, mo)) | |||
throw SaveError ("Can't generate Android icon file"); | |||
@@ -169,6 +169,7 @@ public: | |||
void create (const OwnedArray<LibraryModule>&) const override | |||
{ | |||
MemoryOutputStream out; | |||
out.setNewLineString ("\n"); | |||
out << "# Automatically generated CMakeLists, created by the Projucer" << newLine | |||
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Projucer project!" << newLine | |||
@@ -198,7 +199,9 @@ public: | |||
MemoryBlock existingContent; | |||
getTargetFolder().getChildFile ("CMakeLists.txt").loadFileAsData (existingContent); | |||
MemoryOutputStream out (existingContent, true); | |||
out.setNewLineString ("\n"); | |||
out << "###############################################################################" << newLine | |||
<< "# " << exporter->getName() << newLine | |||
@@ -150,7 +150,7 @@ public: | |||
XmlElement xml ("CodeBlocks_project_file"); | |||
addVersion (xml); | |||
createProject (*xml.createNewChildElement ("Project")); | |||
writeXmlOrThrow (xml, cbpFile, "UTF-8", 10); | |||
writeXmlOrThrow (xml, cbpFile, "UTF-8", 10, true); | |||
} | |||
//============================================================================== | |||
@@ -422,6 +422,8 @@ public: | |||
void create (const OwnedArray<LibraryModule>&) const override | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString ("\n"); | |||
writeMakefile (mo); | |||
overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo); | |||
@@ -443,18 +443,12 @@ protected: | |||
static void writeXmlOrThrow (const XmlElement& xml, const File& file, const String& encoding, int maxCharsPerLine, bool useUnixNewLines = false) | |||
{ | |||
MemoryOutputStream mo; | |||
xml.writeToStream (mo, String(), false, true, encoding, maxCharsPerLine); | |||
if (useUnixNewLines) | |||
{ | |||
MemoryOutputStream mo2; | |||
mo2 << mo.toString().replace ("\r\n", "\n"); | |||
overwriteFileIfDifferentOrThrow (file, mo2); | |||
} | |||
else | |||
{ | |||
overwriteFileIfDifferentOrThrow (file, mo); | |||
} | |||
mo.setNewLineString ("\n"); | |||
xml.writeToStream (mo, String(), false, true, encoding, maxCharsPerLine); | |||
overwriteFileIfDifferentOrThrow (file, mo); | |||
} | |||
static Image rescaleImageForIcon (Drawable&, int iconSize); | |||
@@ -136,6 +136,7 @@ void ProjectSaver::writePluginCharacteristicsFile() | |||
} | |||
MemoryOutputStream mem; | |||
mem.setNewLineString (projectLineFeed); | |||
mem << "//==============================================================================" << newLine | |||
<< "// Audio plugin settings.." << newLine | |||
@@ -76,6 +76,8 @@ public: | |||
return thread.result; | |||
} | |||
projectLineFeed = project.getProjectLineFeed(); | |||
auto appConfigUserContent = loadUserContentFromAppConfig(); | |||
auto oldFile = project.getFile(); | |||
@@ -269,6 +271,7 @@ private: | |||
File appConfigFile; | |||
bool hasBinaryData = false; | |||
String projectLineFeed = "\r\n"; | |||
// Recursively clears out any files in a folder that we didn't create, but avoids | |||
// any folders containing hidden files that might be used by version-control systems. | |||
@@ -325,6 +328,8 @@ private: | |||
if (xml != nullptr) | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString (projectLineFeed); | |||
xml->writeToStream (mo, String()); | |||
replaceFileIfDifferent (projectFile, mo); | |||
} | |||
@@ -367,7 +372,7 @@ private: | |||
userContent.add ({}); | |||
} | |||
return userContent.joinIntoString (newLine) + newLine; | |||
return userContent.joinIntoString (projectLineFeed) + projectLineFeed; | |||
} | |||
void checkModuleValidity (OwnedArray<LibraryModule>& modules) | |||
@@ -516,6 +521,8 @@ private: | |||
appConfigFile = getAppConfigFile(); | |||
MemoryOutputStream mem; | |||
mem.setNewLineString (projectLineFeed); | |||
writeAppConfig (mem, modules, userContent); | |||
saveGeneratedFile (project.getAppConfigFilename(), mem); | |||
} | |||
@@ -570,6 +577,8 @@ private: | |||
void writeAppHeader (const OwnedArray<LibraryModule>& modules) | |||
{ | |||
MemoryOutputStream mem; | |||
mem.setNewLineString (projectLineFeed); | |||
writeAppHeader (mem, modules); | |||
saveGeneratedFile (project.getJuceSourceHFilename(), mem); | |||
} | |||
@@ -581,6 +590,7 @@ private: | |||
for (auto& cu : module->getAllCompileUnits()) | |||
{ | |||
MemoryOutputStream mem; | |||
mem.setNewLineString (projectLineFeed); | |||
writeAutoGenWarningComment (mem); | |||
@@ -650,6 +660,8 @@ private: | |||
void writeReadmeFile() | |||
{ | |||
MemoryOutputStream out; | |||
out.setNewLineString (projectLineFeed); | |||
out << newLine | |||
<< " Important Note!!" << newLine | |||
<< " ================" << newLine | |||
@@ -676,7 +688,8 @@ private: | |||
void writeUnityScriptFile() | |||
{ | |||
String unityScriptContents (BinaryData::jucer_UnityPluginGUIScript_cs); | |||
auto unityScriptContents = replaceLineFeeds (BinaryData::jucer_UnityPluginGUIScript_cs, | |||
projectLineFeed); | |||
auto projectName = Project::addUnityPluginPrefixIfNecessary (project.getProjectNameString()); | |||
@@ -96,23 +96,20 @@ int64 ResourceFile::getTotalDataSize() const | |||
return total; | |||
} | |||
static String getComment() | |||
static void writeComment (MemoryOutputStream& mo) | |||
{ | |||
String comment; | |||
comment << newLine << newLine | |||
<< " This is an auto-generated file: Any edits you make may be overwritten!" << newLine | |||
<< newLine | |||
<< "*/" << newLine | |||
<< newLine; | |||
return comment; | |||
mo << newLine << newLine | |||
<< " This is an auto-generated file: Any edits you make may be overwritten!" << newLine | |||
<< newLine | |||
<< "*/" << newLine | |||
<< newLine; | |||
} | |||
Result ResourceFile::writeHeader (MemoryOutputStream& header) | |||
{ | |||
header << "/* =========================================================================================" | |||
<< getComment() | |||
<< "#pragma once" << newLine | |||
header << "/* ========================================================================================="; | |||
writeComment (header); | |||
header << "#pragma once" << newLine | |||
<< newLine | |||
<< "namespace " << className << newLine | |||
<< "{" << newLine; | |||
@@ -167,9 +164,9 @@ Result ResourceFile::writeCpp (MemoryOutputStream& cpp, const File& headerFile, | |||
{ | |||
bool isFirstFile = (i == 0); | |||
cpp << "/* ==================================== " << resourceFileIdentifierString << " ====================================" | |||
<< getComment() | |||
<< "namespace " << className << newLine | |||
cpp << "/* ==================================== " << resourceFileIdentifierString << " ===================================="; | |||
writeComment (cpp); | |||
cpp << "namespace " << className << newLine | |||
<< "{" << newLine; | |||
bool containsAnyImages = false; | |||
@@ -275,10 +272,14 @@ Result ResourceFile::writeCpp (MemoryOutputStream& cpp, const File& headerFile, | |||
Result ResourceFile::write (Array<File>& filesCreated, const int maxFileSize) | |||
{ | |||
auto projectLineFeed = project.getProjectLineFeed(); | |||
auto headerFile = project.getBinaryDataHeaderFile(); | |||
{ | |||
MemoryOutputStream mo; | |||
mo.setNewLineString (projectLineFeed); | |||
auto r = writeHeader (mo); | |||
if (r.failed()) | |||
@@ -298,6 +299,7 @@ Result ResourceFile::write (Array<File>& filesCreated, const int maxFileSize) | |||
auto cpp = project.getBinaryDataCppFile (fileIndex); | |||
MemoryOutputStream mo; | |||
mo.setNewLineString (projectLineFeed); | |||
auto r = writeCpp (mo, headerFile, i, maxFileSize); | |||
@@ -39,6 +39,32 @@ String joinLinesIntoSourceFile (StringArray& lines) | |||
return lines.joinIntoString (getPreferredLineFeed()) + getPreferredLineFeed(); | |||
} | |||
String replaceLineFeeds (const String& content, const String& lineFeed) | |||
{ | |||
StringArray lines; | |||
lines.addLines (content); | |||
return lines.joinIntoString (lineFeed); | |||
} | |||
String getLineFeedForFile (const String& fileContent) | |||
{ | |||
auto t = fileContent.getCharPointer(); | |||
while (! t.isEmpty()) | |||
{ | |||
switch (t.getAndAdvance()) | |||
{ | |||
case 0: break; | |||
case '\n': return "\n"; | |||
case '\r': if (*t == '\n') return "\r\n"; | |||
default: continue; | |||
} | |||
} | |||
return {}; | |||
} | |||
String trimCommentCharsFromStartOfLine (const String& line) | |||
{ | |||
return line.trimStart().trimCharactersAtStart ("*/").trimStart(); | |||
@@ -30,6 +30,8 @@ | |||
//============================================================================== | |||
const char* getPreferredLineFeed(); | |||
String joinLinesIntoSourceFile (StringArray& lines); | |||
String replaceLineFeeds (const String& content, const String& lineFeed); | |||
String getLineFeedForFile (const String& fileContent); | |||
var parseJUCEHeaderMetadata (const File&); | |||
@@ -32,22 +32,14 @@ NewFileWizard::Type* createGUIComponentWizard(); | |||
//============================================================================== | |||
namespace | |||
{ | |||
String addPreferredProjectLineFeed (const String& content, const String& lineFeed) | |||
{ | |||
if (lineFeed != "\r\n") | |||
return content.replace ("\r\n", lineFeed); | |||
return content; | |||
} | |||
static String fillInBasicTemplateFields (const File& file, const Project::Item& item, const char* templateName) | |||
{ | |||
return addPreferredProjectLineFeed (item.project.getFileTemplate (templateName) | |||
.replace ("%%filename%%", file.getFileName(), false) | |||
.replace ("%%date%%", Time::getCurrentTime().toString (true, true, true), false) | |||
.replace ("%%author%%", SystemStats::getFullUserName(), false) | |||
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (file.withFileExtension (".h"), file)), | |||
item.project.getProjectLineFeed()); | |||
return replaceLineFeeds (item.project.getFileTemplate (templateName) | |||
.replace ("%%filename%%", file.getFileName(), false) | |||
.replace ("%%date%%", Time::getCurrentTime().toString (true, true, true), false) | |||
.replace ("%%author%%", SystemStats::getFullUserName(), false) | |||
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (file.withFileExtension (".h"), file)), | |||
item.project.getProjectLineFeed()); | |||
} | |||
static bool fillInNewCppFileTemplate (const File& file, const Project::Item& item, const char* templateName) | |||
@@ -180,7 +172,7 @@ public: | |||
.replace ("%%component_class%%", className) | |||
.replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (parent.project.getAppIncludeFile(), newFile)); | |||
addPreferredProjectLineFeed (content, parent.project.getProjectLineFeed()); | |||
content = replaceLineFeeds (content, parent.project.getProjectLineFeed()); | |||
if (FileHelpers::overwriteFileWithNewDataIfDifferent (newFile, content)) | |||
{ | |||