diff --git a/app/src/main/java/net/gsantner/markor/format/todotxt/TodoTxtActionButtons.java b/app/src/main/java/net/gsantner/markor/format/todotxt/TodoTxtActionButtons.java index 4c51992032..b6651d8cf9 100644 --- a/app/src/main/java/net/gsantner/markor/format/todotxt/TodoTxtActionButtons.java +++ b/app/src/main/java/net/gsantner/markor/format/todotxt/TodoTxtActionButtons.java @@ -21,6 +21,7 @@ import net.gsantner.markor.R; import net.gsantner.markor.format.ActionButtonBase; +import net.gsantner.markor.format.FormatRegistry; import net.gsantner.markor.frontend.MarkorDialogFactory; import net.gsantner.markor.frontend.textview.TextViewUtils; import net.gsantner.markor.model.Document; @@ -242,7 +243,7 @@ public void archiveDoneTasks() { doneContents.append(TodoTxtTask.tasksToString(move)).append("\n"); // Write to done file - if (new Document(doneFile).saveContent(getActivity(), doneContents.toString())) { + if (new Document(doneFile, FormatRegistry.FORMAT_TODOTXT).saveContent(getActivity(), doneContents.toString())) { final String tasksString = TodoTxtTask.tasksToString(keep); _hlEditor.setText(tasksString); TextViewUtils.setSelectionFromOffsets(_hlEditor, offsets); @@ -514,4 +515,4 @@ public void onCreate(final Bundle savedInstanceState) { } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextSyntaxHighlighter.java b/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextSyntaxHighlighter.java index c9d441815e..f0893d3d21 100644 --- a/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextSyntaxHighlighter.java +++ b/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextSyntaxHighlighter.java @@ -41,7 +41,6 @@ public class WikitextSyntaxHighlighter extends SyntaxHighlighterBase { public final static Pattern CHECKLIST_LEFT_ARROW = Pattern.compile("(?<=(\\n|^))\t*(\\[)(<)(])(?= )"); public final static Pattern SUBSCRIPT = Pattern.compile("(_\\{(?!~)(.+?)\\})"); public final static Pattern SUPERSCRIPT = Pattern.compile("(\\^\\{(?!~)(.+?)\\})"); - public final static Pattern ZIMHEADER_CONTENT_TYPE_ONLY = Pattern.compile("^\\s*Content-Type:\\s*text/x-zim-wiki"); public final static Pattern ZIMHEADER = Pattern.compile( "^Content-Type: text/x-zim-wiki(\r\n|\r|\n)" + "Wiki-Format: zim \\d+\\.\\d+(\r\n|\r|\n)" + diff --git a/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextTextConverter.java b/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextTextConverter.java index 11ccb3a3e7..597f4cac48 100644 --- a/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextTextConverter.java +++ b/app/src/main/java/net/gsantner/markor/format/wikitext/WikitextTextConverter.java @@ -36,6 +36,8 @@ */ @SuppressWarnings("WeakerAccess") public class WikitextTextConverter extends TextConverterBase { + private static final Pattern ZIMHEADER_CONTENT_TYPE_ONLY = Pattern.compile("^\\s*Content-Type:\\s*text/x-zim-wiki"); + // Zim Source View plugin: {{{code: lang="..." ...\n...\n}}} private static final Pattern CODE_BLOCK_SOURCE_VIEW = Pattern.compile( "(?ms)^\\{\\{\\{code:([^\\r\\n]*)(?:\\r\\n?|\\n)(.*?)^\\}\\}\\}[ \\t]*$"); @@ -270,7 +272,7 @@ private String convertImage(final File file, final Context context, final String protected boolean isFileOutOfThisFormat(final File file, final String name, final String ext) { if (ext.equals(".txt")) { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - return WikitextSyntaxHighlighter.ZIMHEADER_CONTENT_TYPE_ONLY.matcher(reader.readLine()).find(); + return ZIMHEADER_CONTENT_TYPE_ONLY.matcher(reader.readLine()).find(); } catch (Exception ignored) { } } diff --git a/app/src/main/java/net/gsantner/markor/frontend/NewFileDialog.java b/app/src/main/java/net/gsantner/markor/frontend/NewFileDialog.java index f27cc7f916..431636aa65 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/NewFileDialog.java +++ b/app/src/main/java/net/gsantner/markor/frontend/NewFileDialog.java @@ -306,7 +306,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { final File file = new File(basedir, fileName); // Most of the logic we want is in the document class so we just reuse it - final Document document = new Document(file); + final Document document = new Document(file, fmt.format); // These are done even if the file isn't created final String titleFormat = formatEdit.getText().toString().trim(); diff --git a/app/src/main/java/net/gsantner/markor/model/Document.java b/app/src/main/java/net/gsantner/markor/model/Document.java index 6482b72102..2fac011455 100644 --- a/app/src/main/java/net/gsantner/markor/model/Document.java +++ b/app/src/main/java/net/gsantner/markor/model/Document.java @@ -71,10 +71,7 @@ public class Document implements Serializable { private int _lastLength = -1; public Document(@NonNull final File f) { - path = GsFileUtils.getPath(f); - file = new File(path); - title = GsFileUtils.getFilenameWithoutExtension(file); - extension = GsFileUtils.getFilenameExtension(file); + this(f, FormatRegistry.FORMAT_UNKNOWN); // Set initial format for (final FormatRegistry.Format format : FormatRegistry.FORMATS) { @@ -85,6 +82,17 @@ public Document(@NonNull final File f) { } } + /** + * Create a document with a known format, skipping automatic format detection. + */ + public Document(@NonNull final File f, @StringRes final int format) { + path = GsFileUtils.getPath(f); + file = new File(path); + title = GsFileUtils.getFilenameWithoutExtension(file); + extension = GsFileUtils.getFilenameExtension(file); + setFormat(format); + } + private void initModTimePref() { // We do not do this in constructor as we want to init after deserialization too if (_modTimePref == null) { diff --git a/app/src/test/java/net/gsantner/markor/format/wikitext/WikitextFileTests.java b/app/src/test/java/net/gsantner/markor/format/wikitext/WikitextFileTests.java index 2f443f718b..5f71648284 100644 --- a/app/src/test/java/net/gsantner/markor/format/wikitext/WikitextFileTests.java +++ b/app/src/test/java/net/gsantner/markor/format/wikitext/WikitextFileTests.java @@ -57,6 +57,14 @@ public void zimHeaderAtBeginningOfTheFileShouldMatch() { assertThat(matcher.group()).isEqualTo("Content-Type: text/x-zim-wiki\nWiki-Format: zim 0.4\nCreation-Date: 2019-03-31T14:48:06+02:00"); } + @Test + public void zimHeaderWithNegativeTimezoneOffsetShouldMatch() { + pattern = WikitextSyntaxHighlighter.ZIMHEADER; + Matcher matcher = pattern.matcher("Content-Type: text/x-zim-wiki\nWiki-Format: zim 0.4\nCreation-Date: 2019-03-31T14:48:06-07:00\nOther content..."); + assertThat(matcher.find()).isTrue(); + assertThat(matcher.group()).isEqualTo("Content-Type: text/x-zim-wiki\nWiki-Format: zim 0.4\nCreation-Date: 2019-03-31T14:48:06-07:00"); + } + @Test public void zimHeaderNotAtBeginningOfTheFileShouldNotMatch() { pattern = WikitextSyntaxHighlighter.ZIMHEADER; diff --git a/app/src/test/java/net/gsantner/markor/model/DocumentConstructionTests.java b/app/src/test/java/net/gsantner/markor/model/DocumentConstructionTests.java new file mode 100644 index 0000000000..1758b42497 --- /dev/null +++ b/app/src/test/java/net/gsantner/markor/model/DocumentConstructionTests.java @@ -0,0 +1,25 @@ +/*####################################################### + * + * SPDX-FileCopyrightText: 2026 Harshad Vedartham + * SPDX-License-Identifier: Apache-2.0 + * +#########################################################*/ +package net.gsantner.markor.model; + +import static org.assertj.core.api.Assertions.assertThat; + +import net.gsantner.markor.format.FormatRegistry; + +import org.junit.Test; + +import java.io.File; + +public class DocumentConstructionTests { + + @Test + public void knownFormatConstructorSetsFormatForAmbiguousFilename() { + final Document document = new Document(new File("archive.txt"), FormatRegistry.FORMAT_TODOTXT); + + assertThat(document.getFormat()).isEqualTo(FormatRegistry.FORMAT_TODOTXT); + } +}