SEXP create(const json::Value& value, Protect* pProtect) { // call embedded create function based on type if (value.type() == json::StringType) { return create(value.get_str(), pProtect); } else if (value.type() == json::IntegerType) { return create(value.get_int(), pProtect); } else if (value.type() == json::RealType) { return create(value.get_real(), pProtect); } else if (value.type() == json::BooleanType) { return create(value.get_bool(), pProtect); } else if (value.type() == json::ArrayType) { return create(value.get_array(), pProtect); } else if (value.type() == json::ObjectType) { return create(value.get_obj(), pProtect); } else if (value.is_null()) { return R_NilValue; } else { return R_NilValue; } }
Error saveDocumentCore(const std::string& contents, const json::Value& jsonPath, const json::Value& jsonType, const json::Value& jsonEncoding, const json::Value& jsonFoldSpec, const json::Value& jsonChunkOutput, boost::shared_ptr<SourceDocument> pDoc) { // check whether we have a path and if we do get/resolve its value std::string oldPath, path; FilePath fullDocPath; bool hasPath = json::isType<std::string>(jsonPath); if (hasPath) { oldPath = pDoc->path(); path = jsonPath.get_str(); fullDocPath = module_context::resolveAliasedPath(path); } // update dirty state: dirty if there was no path AND the new contents // are different from the old contents (and was thus a content autosave // as distinct from a fold-spec or scroll-position/selection autosave) pDoc->setDirty(!hasPath && (contents != pDoc->contents())); bool hasType = json::isType<std::string>(jsonType); if (hasType) { pDoc->setType(jsonType.get_str()); } Error error; bool hasEncoding = json::isType<std::string>(jsonEncoding); if (hasEncoding) { pDoc->setEncoding(jsonEncoding.get_str()); } bool hasFoldSpec = json::isType<std::string>(jsonFoldSpec); if (hasFoldSpec) { pDoc->setFolds(jsonFoldSpec.get_str()); } // note that it's entirely possible for the chunk output to be null if the // document is unrendered (in which case we want to leave the chunk output // as-is) bool hasChunkOutput = json::isType<json::Array>(jsonChunkOutput); if (hasChunkOutput && pDoc->isRMarkdownDocument()) { error = rmarkdown::notebook::setChunkDefs(pDoc, jsonChunkOutput.get_array()); if (error) LOG_ERROR(error); } // handle document (varies depending upon whether we have a path) if (hasPath) { std::string encoded; error = r::util::iconvstr(contents, "UTF-8", pDoc->encoding(), false, &encoded); if (error) { error = r::util::iconvstr(contents, "UTF-8", pDoc->encoding(), true, &encoded); if (error) return error; module_context::consoleWriteError( "Not all of the characters in " + path + " could be encoded using " + pDoc->encoding() + ". To save using a different encoding, choose \"File | " "Save with Encoding...\" from the main menu."); } // note whether the file existed prior to writing bool newFile = !fullDocPath.exists(); // write the contents to the file error = writeStringToFile(fullDocPath, encoded, module_context::lineEndings(fullDocPath)); if (error) return error ; // set the new path and contents for the document error = pDoc->setPathAndContents(path); if (error) return error ; // enque file changed event if we need to if (!module_context::isDirectoryMonitored(fullDocPath.parent())) { using core::system::FileChangeEvent; FileChangeEvent changeEvent(newFile ? FileChangeEvent::FileAdded : FileChangeEvent::FileModified, FileInfo(fullDocPath)); module_context::enqueFileChangedEvent(changeEvent); } // notify other server modules of the file save module_context::events().onSourceEditorFileSaved(fullDocPath); // save could change the extended type of the file so check it detectExtendedType(pDoc); // if we changed the path, notify other modules if (oldPath != pDoc->path()) { source_database::events().onDocRenamed(oldPath, pDoc); } } // always update the contents so it holds the original UTF-8 data pDoc->setContents(contents); return Success(); }