| 30 | 30 | import static com.keenwrite.io.FileType.UNKNOWN; |
| 31 | 31 | import static com.keenwrite.io.MediaType.TEXT_PROPERTIES; |
| 32 | | import static com.keenwrite.io.MediaType.valueFrom; |
| 33 | | import static com.keenwrite.predicates.PredicateFactory.createFileTypePredicate; |
| 34 | | |
| 35 | | /** |
| 36 | | * Provides a context for configuring a chain of {@link Processor} instances. |
| 37 | | */ |
| 38 | | public final class ProcessorContext { |
| 39 | | |
| 40 | | private final Mutator mMutator; |
| 41 | | |
| 42 | | /** |
| 43 | | * Determines the file type from the path extension. This should only be |
| 44 | | * called when it is known that the file type won't be a definition file |
| 45 | | * (e.g., YAML or other definition source), but rather an editable file |
| 46 | | * (e.g., Markdown, R Markdown, etc.). |
| 47 | | * |
| 48 | | * @param path The path with a file name extension. |
| 49 | | * @return The FileType for the given path. |
| 50 | | */ |
| 51 | | private static FileType lookup( final Path path ) { |
| 52 | | assert path != null; |
| 53 | | |
| 54 | | final var prefix = GLOB_PREFIX_FILE; |
| 55 | | final var keys = sSettings.getKeys( prefix ); |
| 56 | | |
| 57 | | var found = false; |
| 58 | | var fileType = UNKNOWN; |
| 59 | | |
| 60 | | while( keys.hasNext() && !found ) { |
| 61 | | final var key = keys.next(); |
| 62 | | final var patterns = sSettings.getStringSettingList( key ); |
| 63 | | final var predicate = createFileTypePredicate( patterns ); |
| 64 | | |
| 65 | | if( predicate.test( path.toFile() ) ) { |
| 66 | | // Remove the EXTENSIONS_PREFIX to get the file name extension mapped |
| 67 | | // to a standard name (as defined in the settings.properties file). |
| 68 | | final String suffix = key.replace( prefix + '.', "" ); |
| 69 | | fileType = FileType.from( suffix ); |
| 70 | | found = true; |
| 71 | | } |
| 72 | | } |
| 73 | | |
| 74 | | return fileType; |
| 75 | | } |
| 76 | | |
| 77 | | public boolean isExportFormat( final ExportFormat exportFormat ) { |
| 78 | | return mMutator.mExportFormat == exportFormat; |
| 79 | | } |
| 80 | | |
| 81 | | /** |
| 82 | | * Responsible for populating the instance variables required by the |
| 83 | | * context. |
| 84 | | */ |
| 85 | | public static class Mutator { |
| 86 | | private Path mSourcePath; |
| 87 | | private Path mTargetPath; |
| 88 | | private ExportFormat mExportFormat; |
| 89 | | private Supplier<Boolean> mConcatenate = () -> true; |
| 90 | | private Supplier<String> mChapters = () -> ""; |
| 91 | | |
| 92 | | private Supplier<Path> mThemesDir = USER_DIRECTORY::toPath; |
| 93 | | private Supplier<Locale> mLocale = () -> Locale.ENGLISH; |
| 94 | | |
| 95 | | private Supplier<Map<String, String>> mDefinitions = HashMap::new; |
| 96 | | private Supplier<Map<String, String>> mMetadata = HashMap::new; |
| 97 | | private Supplier<Caret> mCaret = () -> Caret.builder().build(); |
| 98 | | |
| 99 | | private Supplier<Path> mFontsDir = () -> getFontDirectory().toPath(); |
| 100 | | |
| 101 | | private Supplier<Path> mImagesDir = USER_DIRECTORY::toPath; |
| 102 | | private Supplier<String> mImageServer = () -> DIAGRAM_SERVER_NAME; |
| 103 | | private Supplier<String> mImageOrder = () -> PERSIST_IMAGES_DEFAULT; |
| 104 | | |
| 105 | | private Supplier<Path> mCachesPath = USER_CACHE_DIR::toPath; |
| 106 | | |
| 107 | | private Supplier<String> mSigilBegan = () -> DEF_DELIM_BEGAN_DEFAULT; |
| 108 | | private Supplier<String> mSigilEnded = () -> DEF_DELIM_ENDED_DEFAULT; |
| 109 | | |
| 110 | | private Supplier<Path> mRWorkingDir = USER_DIRECTORY::toPath; |
| 111 | | private Supplier<String> mRScript = () -> ""; |
| 112 | | |
| 113 | | private Supplier<Boolean> mCurlQuotes = () -> true; |
| 114 | | private Supplier<Boolean> mAutoRemove = () -> true; |
| 115 | | |
| 116 | | public void setSourcePath( final Path sourcePath ) { |
| 117 | | assert sourcePath != null; |
| 118 | | mSourcePath = sourcePath; |
| 119 | | } |
| 120 | | |
| 121 | | public void setTargetPath( final Path outputPath ) { |
| 122 | | assert outputPath != null; |
| 123 | | mTargetPath = outputPath; |
| 124 | | } |
| 125 | | |
| 126 | | public void setTargetPath( final File targetPath ) { |
| 127 | | assert targetPath != null; |
| 128 | | setTargetPath( targetPath.toPath() ); |
| 129 | | } |
| 130 | | |
| 131 | | public void setThemesDir( final Supplier<Path> themesDir ) { |
| 132 | | assert themesDir != null; |
| 133 | | mThemesDir = themesDir; |
| 134 | | } |
| 135 | | |
| 136 | | public void setCachesDir( final Supplier<File> cachesDir ) { |
| 137 | | assert cachesDir != null; |
| 138 | | |
| 139 | | mCachesPath = () -> { |
| 140 | | final var dir = cachesDir.get(); |
| 141 | | |
| 142 | | return (dir == null ? USER_DATA_DIR.toFile() : dir).toPath(); |
| 143 | | }; |
| 144 | | } |
| 145 | | |
| 146 | | public void setImagesDir( final Supplier<File> imagesDir ) { |
| 147 | | assert imagesDir != null; |
| 148 | | |
| 149 | | mImagesDir = () -> { |
| 150 | | final var dir = imagesDir.get(); |
| 151 | | |
| 152 | | return (dir == null ? USER_DIRECTORY : dir).toPath(); |
| 153 | | }; |
| 154 | | } |
| 155 | | |
| 156 | | public void setImageOrder( final Supplier<String> imageOrder ) { |
| 157 | | assert imageOrder != null; |
| 158 | | mImageOrder = imageOrder; |
| 159 | | } |
| 160 | | |
| 161 | | public void setImageServer( final Supplier<String> imageServer ) { |
| 162 | | assert imageServer != null; |
| 163 | | mImageServer = imageServer; |
| 164 | | } |
| 165 | | |
| 166 | | public void setFontsDir( final Supplier<File> fontsDir ) { |
| 167 | | assert fontsDir != null; |
| 168 | | mFontsDir = () -> { |
| 169 | | final var dir = fontsDir.get(); |
| 170 | | |
| 171 | | return (dir == null ? USER_DIRECTORY : dir).toPath(); |
| 172 | | }; |
| 173 | | } |
| 174 | | |
| 175 | | public void setExportFormat( final ExportFormat exportFormat ) { |
| 176 | | assert exportFormat != null; |
| 177 | | mExportFormat = exportFormat; |
| 178 | | } |
| 179 | | |
| 180 | | public void setConcatenate( final Supplier<Boolean> concatenate ) { |
| 181 | | mConcatenate = concatenate; |
| 182 | | } |
| 183 | | |
| 184 | | public void setChapters( final Supplier<String> chapters ) { |
| 185 | | mChapters = chapters; |
| 186 | | } |
| 187 | | |
| 188 | | public void setLocale( final Supplier<Locale> locale ) { |
| 189 | | assert locale != null; |
| 190 | | mLocale = locale; |
| 191 | | } |
| 192 | | |
| 193 | | /** |
| 194 | | * Sets the list of fully interpolated key-value pairs to use when |
| 195 | | * substituting variable names back into the document as variable values. |
| 196 | | * This uses a {@link Callable} reference so that GUI and command-line |
| 197 | | * usage can insert their respective behaviours. That is, this method |
| 198 | | * prevents coupling the GUI to the CLI. |
| 199 | | * |
| 200 | | * @param supplier Defines how to retrieve the definitions. |
| 201 | | */ |
| 202 | | public void setDefinitions( final Supplier<Map<String, String>> supplier ) { |
| 203 | | assert supplier != null; |
| 204 | | mDefinitions = supplier; |
| 205 | | } |
| 206 | | |
| 207 | | public void setMetadata( final Supplier<Map<String, String>> metadata ) { |
| 208 | | assert metadata != null; |
| 209 | | mMetadata = metadata.get() == null ? HashMap::new : metadata; |
| 210 | | } |
| 211 | | |
| 212 | | /** |
| 213 | | * Sets the source for deriving the {@link Caret}. Typically, this is |
| 214 | | * the text editor that has focus. |
| 215 | | * |
| 216 | | * @param caret The source for the currently active caret. |
| 217 | | */ |
| 218 | | public void setCaret( final Supplier<Caret> caret ) { |
| 219 | | assert caret != null; |
| 220 | | mCaret = caret; |
| 221 | | } |
| 222 | | |
| 223 | | public void setSigilBegan( final Supplier<String> sigilBegan ) { |
| 224 | | assert sigilBegan != null; |
| 225 | | mSigilBegan = sigilBegan; |
| 226 | | } |
| 227 | | |
| 228 | | public void setSigilEnded( final Supplier<String> sigilEnded ) { |
| 229 | | assert sigilEnded != null; |
| 230 | | mSigilEnded = sigilEnded; |
| 231 | | } |
| 232 | | |
| 233 | | public void setRWorkingDir( final Supplier<Path> rWorkingDir ) { |
| 234 | | assert rWorkingDir != null; |
| 235 | | |
| 236 | | mRWorkingDir = rWorkingDir; |
| 237 | | } |
| 238 | | |
| 239 | | public void setRScript( final Supplier<String> rScript ) { |
| 240 | | assert rScript != null; |
| 241 | | mRScript = rScript; |
| 242 | | } |
| 243 | | |
| 244 | | public void setCurlQuotes( final Supplier<Boolean> curlQuotes ) { |
| 245 | | assert curlQuotes != null; |
| 246 | | mCurlQuotes = curlQuotes; |
| 247 | | } |
| 248 | | |
| 249 | | public void setAutoRemove( final Supplier<Boolean> autoRemove ) { |
| 250 | | assert autoRemove != null; |
| 251 | | mAutoRemove = autoRemove; |
| 252 | | } |
| 253 | | |
| 254 | | private boolean isExportFormat( final ExportFormat format ) { |
| 255 | | return mExportFormat == format; |
| 256 | | } |
| 257 | | } |
| 258 | | |
| 259 | | public static GenericBuilder<Mutator, ProcessorContext> builder() { |
| 260 | | return GenericBuilder.of( Mutator::new, ProcessorContext::new ); |
| 261 | | } |
| 262 | | |
| 263 | | /** |
| 264 | | * Creates a new context for use by the {@link ProcessorFactory} when |
| 265 | | * instantiating new {@link Processor} instances. Although all the |
| 266 | | * parameters are required, not all {@link Processor} instances will use |
| 267 | | * all parameters. |
| 268 | | */ |
| 269 | | private ProcessorContext( final Mutator mutator ) { |
| 270 | | assert mutator != null; |
| 271 | | |
| 272 | | mMutator = mutator; |
| 273 | | } |
| 274 | | |
| 275 | | public Path getSourcePath() { |
| 276 | | return mMutator.mSourcePath; |
| 277 | | } |
| 278 | | |
| 279 | | /** |
| 280 | | * Answers what type of input document is to be processed. |
| 281 | | * |
| 282 | | * @return The input document's {@link MediaType}. |
| 283 | | */ |
| 284 | | public MediaType getSourceType() { |
| 285 | | return MediaTypeExtension.fromPath( mMutator.mSourcePath ); |
| 286 | | } |
| 287 | | |
| 288 | | /** |
| 289 | | * Fully qualified file name to use when exporting (e.g., document.pdf). |
| 290 | | * |
| 291 | | * @return Full path to a file name. |
| 292 | | */ |
| 293 | | public Path getTargetPath() { |
| 294 | | return mMutator.mTargetPath; |
| 295 | | } |
| 296 | | |
| 297 | | public ExportFormat getExportFormat() { |
| 298 | | return mMutator.mExportFormat; |
| 299 | | } |
| 300 | | |
| 301 | | public Locale getLocale() { |
| 302 | | return mMutator.mLocale.get(); |
| 303 | | } |
| 304 | | |
| 305 | | /** |
| 306 | | * Returns the variable map of definitions, without interpolation. |
| 307 | | * |
| 308 | | * @return A map to help dereference variables. |
| 309 | | */ |
| 310 | | public Map<String, String> getDefinitions() { |
| 311 | | return mMutator.mDefinitions.get(); |
| 312 | | } |
| 313 | | |
| 314 | | /** |
| 315 | | * Returns the variable map of definitions, with interpolation. |
| 316 | | * |
| 317 | | * @return A map to help dereference variables. |
| 318 | | */ |
| 319 | | public InterpolatingMap getInterpolatedDefinitions() { |
| 320 | | return new InterpolatingMap( |
| 321 | | createDefinitionKeyOperator(), getDefinitions() |
| 322 | | ).interpolate(); |
| 323 | | } |
| 324 | | |
| 325 | | public Map<String, String> getMetadata() { |
| 326 | | return mMutator.mMetadata.get(); |
| 327 | | } |
| 328 | | |
| 329 | | /** |
| 330 | | * Returns the current caret position in the document being edited and is |
| 331 | | * always up-to-date. |
| 332 | | * |
| 333 | | * @return Caret position in the document. |
| 334 | | */ |
| 335 | | public Supplier<Caret> getCaret() { |
| 336 | | return mMutator.mCaret; |
| 337 | | } |
| 338 | | |
| 339 | | /** |
| 340 | | * Returns the directory that contains the file being edited. When |
| 341 | | * {@link Constants#DOCUMENT_DEFAULT} is created, the parent path is |
| 342 | | * {@code null}. This will get absolute path to the file before trying to |
| 343 | | * get te parent path, which should always be a valid path. In the unlikely |
| 344 | | * event that the base path cannot be determined by the path alone, the |
| 345 | | * default user directory is returned. This is necessary for the creation |
| 346 | | * of new files. |
| 347 | | * |
| 348 | | * @return Path to the directory containing a file being edited, or the |
| 349 | | * default user directory if the base path cannot be determined. |
| 350 | | */ |
| 351 | | public Path getBaseDir() { |
| 352 | | final var path = getSourcePath().toAbsolutePath().getParent(); |
| 353 | | return path == null ? DEFAULT_DIRECTORY : path; |
| 354 | | } |
| 355 | | |
| 356 | | FileType getSourceFileType() { |
| 357 | | return lookup( getSourcePath() ); |
| 358 | | } |
| 359 | | |
| 360 | | public Path getThemesDir() { |
| 361 | | return mMutator.mThemesDir.get(); |
| 362 | | } |
| 363 | | |
| 364 | | public Path getImagesDir() { |
| 365 | | return mMutator.mImagesDir.get(); |
| 366 | | } |
| 367 | | |
| 368 | | public Path getCachesPath() { |
| 369 | | return mMutator.mCachesPath.get(); |
| 370 | | } |
| 371 | | |
| 372 | | public Iterable<String> getImageOrder() { |
| 373 | | assert mMutator.mImageOrder != null; |
| 374 | | |
| 375 | | final var order = mMutator.mImageOrder.get(); |
| 376 | | final var token = order.contains( "," ) ? ',' : ' '; |
| 377 | | |
| 378 | | return Splitter.on( token ).split( token + order ); |
| 379 | | } |
| 380 | | |
| 381 | | public String getImageServer() { |
| 382 | | return mMutator.mImageServer.get(); |
| 383 | | } |
| 384 | | |
| 385 | | public Path getFontsDir() { |
| 386 | | return mMutator.mFontsDir.get(); |
| 32 | import static com.keenwrite.predicates.PredicateFactory.createFileTypePredicate; |
| 33 | |
| 34 | /** |
| 35 | * Provides a context for configuring a chain of {@link Processor} instances. |
| 36 | */ |
| 37 | public final class ProcessorContext { |
| 38 | |
| 39 | private final Mutator mMutator; |
| 40 | |
| 41 | /** |
| 42 | * Determines the file type from the path extension. This should only be |
| 43 | * called when it is known that the file type won't be a definition file |
| 44 | * (e.g., YAML or other definition source), but rather an editable file |
| 45 | * (e.g., Markdown, R Markdown, etc.). |
| 46 | * |
| 47 | * @param path The path with a file name extension. |
| 48 | * @return The FileType for the given path. |
| 49 | */ |
| 50 | private static FileType lookup( final Path path ) { |
| 51 | assert path != null; |
| 52 | |
| 53 | final var prefix = GLOB_PREFIX_FILE; |
| 54 | final var keys = sSettings.getKeys( prefix ); |
| 55 | |
| 56 | var found = false; |
| 57 | var fileType = UNKNOWN; |
| 58 | |
| 59 | while( keys.hasNext() && !found ) { |
| 60 | final var key = keys.next(); |
| 61 | final var patterns = sSettings.getStringSettingList( key ); |
| 62 | final var predicate = createFileTypePredicate( patterns ); |
| 63 | |
| 64 | if( predicate.test( path.toFile() ) ) { |
| 65 | // Remove the EXTENSIONS_PREFIX to get the file name extension mapped |
| 66 | // to a standard name (as defined in the settings.properties file). |
| 67 | final String suffix = key.replace( prefix + '.', "" ); |
| 68 | fileType = FileType.from( suffix ); |
| 69 | found = true; |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | return fileType; |
| 74 | } |
| 75 | |
| 76 | public boolean isExportFormat( final ExportFormat exportFormat ) { |
| 77 | return mMutator.mExportFormat == exportFormat; |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Responsible for populating the instance variables required by the |
| 82 | * context. |
| 83 | */ |
| 84 | public static class Mutator { |
| 85 | private Path mSourcePath; |
| 86 | private Path mTargetPath; |
| 87 | private ExportFormat mExportFormat; |
| 88 | private Supplier<Boolean> mConcatenate = () -> true; |
| 89 | private Supplier<String> mChapters = () -> ""; |
| 90 | |
| 91 | private Supplier<Path> mThemeDir = USER_DIRECTORY::toPath; |
| 92 | private Supplier<Locale> mLocale = () -> Locale.ENGLISH; |
| 93 | |
| 94 | private Supplier<Map<String, String>> mDefinitions = HashMap::new; |
| 95 | private Supplier<Map<String, String>> mMetadata = HashMap::new; |
| 96 | private Supplier<Caret> mCaret = () -> Caret.builder().build(); |
| 97 | |
| 98 | private Supplier<Path> mFontDir = () -> getFontDirectory().toPath(); |
| 99 | |
| 100 | private Supplier<Path> mImageDir = USER_DIRECTORY::toPath; |
| 101 | private Supplier<String> mImageServer = () -> DIAGRAM_SERVER_NAME; |
| 102 | private Supplier<String> mImageOrder = () -> PERSIST_IMAGES_DEFAULT; |
| 103 | |
| 104 | private Supplier<Path> mCacheDir = USER_CACHE_DIR::toPath; |
| 105 | |
| 106 | private Supplier<String> mSigilBegan = () -> DEF_DELIM_BEGAN_DEFAULT; |
| 107 | private Supplier<String> mSigilEnded = () -> DEF_DELIM_ENDED_DEFAULT; |
| 108 | |
| 109 | private Supplier<Path> mRWorkingDir = USER_DIRECTORY::toPath; |
| 110 | private Supplier<String> mRScript = () -> ""; |
| 111 | |
| 112 | private Supplier<Boolean> mCurlQuotes = () -> true; |
| 113 | private Supplier<Boolean> mAutoRemove = () -> true; |
| 114 | |
| 115 | public void setSourcePath( final Path sourcePath ) { |
| 116 | assert sourcePath != null; |
| 117 | mSourcePath = sourcePath; |
| 118 | } |
| 119 | |
| 120 | public void setTargetPath( final Path outputPath ) { |
| 121 | assert outputPath != null; |
| 122 | mTargetPath = outputPath; |
| 123 | } |
| 124 | |
| 125 | public void setThemeDir( final Supplier<Path> themeDir ) { |
| 126 | assert themeDir != null; |
| 127 | mThemeDir = themeDir; |
| 128 | } |
| 129 | |
| 130 | public void setCacheDir( final Supplier<File> cacheDir ) { |
| 131 | assert cacheDir != null; |
| 132 | |
| 133 | mCacheDir = () -> { |
| 134 | final var dir = cacheDir.get(); |
| 135 | |
| 136 | return (dir == null ? USER_DATA_DIR.toFile() : dir).toPath(); |
| 137 | }; |
| 138 | } |
| 139 | |
| 140 | public void setImageDir( final Supplier<File> imageDir ) { |
| 141 | assert imageDir != null; |
| 142 | |
| 143 | mImageDir = () -> { |
| 144 | final var dir = imageDir.get(); |
| 145 | |
| 146 | return (dir == null ? USER_DIRECTORY : dir).toPath(); |
| 147 | }; |
| 148 | } |
| 149 | |
| 150 | public void setImageOrder( final Supplier<String> imageOrder ) { |
| 151 | assert imageOrder != null; |
| 152 | mImageOrder = imageOrder; |
| 153 | } |
| 154 | |
| 155 | public void setImageServer( final Supplier<String> imageServer ) { |
| 156 | assert imageServer != null; |
| 157 | mImageServer = imageServer; |
| 158 | } |
| 159 | |
| 160 | public void setFontDir( final Supplier<File> fontDir ) { |
| 161 | assert fontDir != null; |
| 162 | mFontDir = () -> { |
| 163 | final var dir = fontDir.get(); |
| 164 | |
| 165 | return (dir == null ? USER_DIRECTORY : dir).toPath(); |
| 166 | }; |
| 167 | } |
| 168 | |
| 169 | public void setExportFormat( final ExportFormat exportFormat ) { |
| 170 | assert exportFormat != null; |
| 171 | mExportFormat = exportFormat; |
| 172 | } |
| 173 | |
| 174 | public void setConcatenate( final Supplier<Boolean> concatenate ) { |
| 175 | mConcatenate = concatenate; |
| 176 | } |
| 177 | |
| 178 | public void setChapters( final Supplier<String> chapters ) { |
| 179 | mChapters = chapters; |
| 180 | } |
| 181 | |
| 182 | public void setLocale( final Supplier<Locale> locale ) { |
| 183 | assert locale != null; |
| 184 | mLocale = locale; |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Sets the list of fully interpolated key-value pairs to use when |
| 189 | * substituting variable names back into the document as variable values. |
| 190 | * This uses a {@link Callable} reference so that GUI and command-line |
| 191 | * usage can insert their respective behaviours. That is, this method |
| 192 | * prevents coupling the GUI to the CLI. |
| 193 | * |
| 194 | * @param supplier Defines how to retrieve the definitions. |
| 195 | */ |
| 196 | public void setDefinitions( final Supplier<Map<String, String>> supplier ) { |
| 197 | assert supplier != null; |
| 198 | mDefinitions = supplier; |
| 199 | } |
| 200 | |
| 201 | public void setMetadata( final Supplier<Map<String, String>> metadata ) { |
| 202 | assert metadata != null; |
| 203 | mMetadata = metadata.get() == null ? HashMap::new : metadata; |
| 204 | } |
| 205 | |
| 206 | /** |
| 207 | * Sets the source for deriving the {@link Caret}. Typically, this is |
| 208 | * the text editor that has focus. |
| 209 | * |
| 210 | * @param caret The source for the currently active caret. |
| 211 | */ |
| 212 | public void setCaret( final Supplier<Caret> caret ) { |
| 213 | assert caret != null; |
| 214 | mCaret = caret; |
| 215 | } |
| 216 | |
| 217 | public void setSigilBegan( final Supplier<String> sigilBegan ) { |
| 218 | assert sigilBegan != null; |
| 219 | mSigilBegan = sigilBegan; |
| 220 | } |
| 221 | |
| 222 | public void setSigilEnded( final Supplier<String> sigilEnded ) { |
| 223 | assert sigilEnded != null; |
| 224 | mSigilEnded = sigilEnded; |
| 225 | } |
| 226 | |
| 227 | public void setRWorkingDir( final Supplier<Path> rWorkingDir ) { |
| 228 | assert rWorkingDir != null; |
| 229 | |
| 230 | mRWorkingDir = rWorkingDir; |
| 231 | } |
| 232 | |
| 233 | public void setRScript( final Supplier<String> rScript ) { |
| 234 | assert rScript != null; |
| 235 | mRScript = rScript; |
| 236 | } |
| 237 | |
| 238 | public void setCurlQuotes( final Supplier<Boolean> curlQuotes ) { |
| 239 | assert curlQuotes != null; |
| 240 | mCurlQuotes = curlQuotes; |
| 241 | } |
| 242 | |
| 243 | public void setAutoRemove( final Supplier<Boolean> autoRemove ) { |
| 244 | assert autoRemove != null; |
| 245 | mAutoRemove = autoRemove; |
| 246 | } |
| 247 | |
| 248 | private boolean isExportFormat( final ExportFormat format ) { |
| 249 | return mExportFormat == format; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | public static GenericBuilder<Mutator, ProcessorContext> builder() { |
| 254 | return GenericBuilder.of( Mutator::new, ProcessorContext::new ); |
| 255 | } |
| 256 | |
| 257 | /** |
| 258 | * Creates a new context for use by the {@link ProcessorFactory} when |
| 259 | * instantiating new {@link Processor} instances. Although all the |
| 260 | * parameters are required, not all {@link Processor} instances will use |
| 261 | * all parameters. |
| 262 | */ |
| 263 | private ProcessorContext( final Mutator mutator ) { |
| 264 | assert mutator != null; |
| 265 | |
| 266 | mMutator = mutator; |
| 267 | } |
| 268 | |
| 269 | public Path getSourcePath() { |
| 270 | return mMutator.mSourcePath; |
| 271 | } |
| 272 | |
| 273 | /** |
| 274 | * Answers what type of input document is to be processed. |
| 275 | * |
| 276 | * @return The input document's {@link MediaType}. |
| 277 | */ |
| 278 | public MediaType getSourceType() { |
| 279 | return MediaTypeExtension.fromPath( mMutator.mSourcePath ); |
| 280 | } |
| 281 | |
| 282 | /** |
| 283 | * Fully qualified file name to use when exporting (e.g., document.pdf). |
| 284 | * |
| 285 | * @return Full path to a file name. |
| 286 | */ |
| 287 | public Path getTargetPath() { |
| 288 | return mMutator.mTargetPath; |
| 289 | } |
| 290 | |
| 291 | public ExportFormat getExportFormat() { |
| 292 | return mMutator.mExportFormat; |
| 293 | } |
| 294 | |
| 295 | public Locale getLocale() { |
| 296 | return mMutator.mLocale.get(); |
| 297 | } |
| 298 | |
| 299 | /** |
| 300 | * Returns the variable map of definitions, without interpolation. |
| 301 | * |
| 302 | * @return A map to help dereference variables. |
| 303 | */ |
| 304 | public Map<String, String> getDefinitions() { |
| 305 | return mMutator.mDefinitions.get(); |
| 306 | } |
| 307 | |
| 308 | /** |
| 309 | * Returns the variable map of definitions, with interpolation. |
| 310 | * |
| 311 | * @return A map to help dereference variables. |
| 312 | */ |
| 313 | public InterpolatingMap getInterpolatedDefinitions() { |
| 314 | return new InterpolatingMap( |
| 315 | createDefinitionKeyOperator(), getDefinitions() |
| 316 | ).interpolate(); |
| 317 | } |
| 318 | |
| 319 | public Map<String, String> getMetadata() { |
| 320 | return mMutator.mMetadata.get(); |
| 321 | } |
| 322 | |
| 323 | /** |
| 324 | * Returns the current caret position in the document being edited and is |
| 325 | * always up-to-date. |
| 326 | * |
| 327 | * @return Caret position in the document. |
| 328 | */ |
| 329 | public Supplier<Caret> getCaret() { |
| 330 | return mMutator.mCaret; |
| 331 | } |
| 332 | |
| 333 | /** |
| 334 | * Returns the directory that contains the file being edited. When |
| 335 | * {@link Constants#DOCUMENT_DEFAULT} is created, the parent path is |
| 336 | * {@code null}. This will get absolute path to the file before trying to |
| 337 | * get te parent path, which should always be a valid path. In the unlikely |
| 338 | * event that the base path cannot be determined by the path alone, the |
| 339 | * default user directory is returned. This is necessary for the creation |
| 340 | * of new files. |
| 341 | * |
| 342 | * @return Path to the directory containing a file being edited, or the |
| 343 | * default user directory if the base path cannot be determined. |
| 344 | */ |
| 345 | public Path getBaseDir() { |
| 346 | final var path = getSourcePath().toAbsolutePath().getParent(); |
| 347 | return path == null ? DEFAULT_DIRECTORY : path; |
| 348 | } |
| 349 | |
| 350 | FileType getSourceFileType() { |
| 351 | return lookup( getSourcePath() ); |
| 352 | } |
| 353 | |
| 354 | public Path getThemeDir() { |
| 355 | return mMutator.mThemeDir.get(); |
| 356 | } |
| 357 | |
| 358 | public Path getImageDir() { |
| 359 | return mMutator.mImageDir.get(); |
| 360 | } |
| 361 | |
| 362 | public Path getCacheDir() { |
| 363 | return mMutator.mCacheDir.get(); |
| 364 | } |
| 365 | |
| 366 | public Iterable<String> getImageOrder() { |
| 367 | assert mMutator.mImageOrder != null; |
| 368 | |
| 369 | final var order = mMutator.mImageOrder.get(); |
| 370 | final var token = order.contains( "," ) ? ',' : ' '; |
| 371 | |
| 372 | return Splitter.on( token ).split( token + order ); |
| 373 | } |
| 374 | |
| 375 | public String getImageServer() { |
| 376 | return mMutator.mImageServer.get(); |
| 377 | } |
| 378 | |
| 379 | public Path getFontDir() { |
| 380 | return mMutator.mFontDir.get(); |
| 387 | 381 | } |
| 388 | 382 | |