diff --git a/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp b/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp index 1777411b3a..eac6d815bb 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp +++ b/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp @@ -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); diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp index c5b0568e26..b1e1355ac7 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp @@ -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(); diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h index 16146c426d..f10edb6491 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h @@ -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(); //============================================================================== diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h index bae55a30bf..f9de4806ba 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h @@ -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 (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& 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 (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"); diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h index 1c5136952d..32b99c2107 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h @@ -169,6 +169,7 @@ public: void create (const OwnedArray&) 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 diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h index a3ca3500c2..970889a87e 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h @@ -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); } //============================================================================== diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h index c0e8e58a99..e247e47c4c 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h @@ -422,6 +422,8 @@ public: void create (const OwnedArray&) const override { MemoryOutputStream mo; + mo.setNewLineString ("\n"); + writeMakefile (mo); overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo); diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h index b7d4cb3671..9961f15af9 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h @@ -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); diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp index da1459d6fc..76b4b82072 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp @@ -136,6 +136,7 @@ void ProjectSaver::writePluginCharacteristicsFile() } MemoryOutputStream mem; + mem.setNewLineString (projectLineFeed); mem << "//==============================================================================" << newLine << "// Audio plugin settings.." << newLine diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h index 8f12b3a2f1..789dfff642 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h @@ -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& 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& 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()); diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ResourceFile.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ResourceFile.cpp index 1dcd54e902..7fa0252a90 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ResourceFile.cpp +++ b/extras/Projucer/Source/ProjectSaving/jucer_ResourceFile.cpp @@ -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& 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& filesCreated, const int maxFileSize) auto cpp = project.getBinaryDataCppFile (fileIndex); MemoryOutputStream mo; + mo.setNewLineString (projectLineFeed); auto r = writeCpp (mo, headerFile, i, maxFileSize); diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp index 8312884aba..a74f7770cd 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp +++ b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp @@ -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(); diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h index 9f7f471014..f96b5ce18b 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h @@ -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&); diff --git a/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp b/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp index 6701246916..70a84940d7 100644 --- a/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp +++ b/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp @@ -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)) {