diff --git a/.gitignore b/.gitignore
index 62f0d4ded..5b07c278d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ doc/
temp/
logs/
*.min.json
+.claude/settings.local.json
diff --git a/src/main/filesystem/markdown.js b/src/main/filesystem/markdown.js
index 38420578e..241d33cdd 100644
--- a/src/main/filesystem/markdown.js
+++ b/src/main/filesystem/markdown.js
@@ -74,13 +74,15 @@ export const writeMarkdownFile = (pathname, content, options) => {
* @param {string} preferredEol The preferred EOL.
* @param {boolean} autoGuessEncoding Whether we should try to auto guess encoding.
* @param {*} trimTrailingNewline The trim trailing newline option.
+ * @param {boolean} autoNormalizeMarkdownOnOpen Whether to automatically normalize line endings and detect trailing newlines on open.
* @returns {IMarkdownDocumentRaw} Returns a raw markdown document.
*/
export const loadMarkdownFile = async (
pathname,
preferredEol,
autoGuessEncoding = true,
- trimTrailingNewline = 2
+ trimTrailingNewline = 2,
+ autoNormalizeMarkdownOnOpen = false
) => {
// TODO: Use streams to not buffer the file multiple times and only guess
// encoding on the first 256/512 bytes.
@@ -108,33 +110,50 @@ export const loadMarkdownFile = async (
}
let adjustLineEndingOnSave = false
- if (isMixedLineEndings || isUnknownEnding || lineEnding !== 'lf') {
- adjustLineEndingOnSave = lineEnding !== 'lf'
- // Convert to LF for internal use.
- markdown = convertLineEndings(markdown, 'lf')
- }
- // Detect final newline
- if (trimTrailingNewline === 2) {
- if (!markdown) {
- // Use default value
- trimTrailingNewline = 3
- } else {
- const lastIndex = markdown.length - 1
- if (lastIndex >= 1 && markdown[lastIndex] === '\n' && markdown[lastIndex - 1] === '\n') {
- // Disabled
- trimTrailingNewline = 2
- } else if (markdown[lastIndex] === '\n') {
- // Ensure single trailing newline
- trimTrailingNewline = 1
+ // Only auto-normalize if the preference is enabled
+ if (autoNormalizeMarkdownOnOpen) {
+ if (isMixedLineEndings || isUnknownEnding || lineEnding !== 'lf') {
+ adjustLineEndingOnSave = lineEnding !== 'lf'
+ // Convert to LF for internal use.
+ markdown = convertLineEndings(markdown, 'lf')
+ }
+
+ // Detect final newline
+ if (trimTrailingNewline === 2) {
+ if (!markdown) {
+ // Use default value
+ trimTrailingNewline = 3
} else {
- // Trim trailing newlines
- trimTrailingNewline = 0
+ const lastIndex = markdown.length - 1
+ if (lastIndex >= 1 && markdown[lastIndex] === '\n' && markdown[lastIndex - 1] === '\n') {
+ // Disabled
+ trimTrailingNewline = 2
+ } else if (markdown[lastIndex] === '\n') {
+ // Ensure single trailing newline
+ trimTrailingNewline = 1
+ } else {
+ // Trim trailing newlines
+ trimTrailingNewline = 0
+ }
}
}
+ } else {
+ // When not auto-normalizing, preserve the original line ending format
+ // but still convert to LF internally for the editor (required by MarkText)
+ if (lineEnding !== 'lf') {
+ adjustLineEndingOnSave = true
+ markdown = convertLineEndings(markdown, 'lf')
+ }
+ // When not auto-normalizing and trimTrailingNewline is set to auto-detect (2),
+ // we should use "disabled" (3) to preserve the file exactly as-is
+ if (trimTrailingNewline === 2) {
+ trimTrailingNewline = 3
+ }
}
const filename = path.basename(pathname)
+
return {
// document information
markdown,
diff --git a/src/main/filesystem/watcher.js b/src/main/filesystem/watcher.js
index 7789865a9..422c2bbca 100644
--- a/src/main/filesystem/watcher.js
+++ b/src/main/filesystem/watcher.js
@@ -18,7 +18,7 @@ const EVENT_NAME = {
file: 'mt::update-file'
}
-const add = async (win, pathname, type, endOfLine, autoGuessEncoding, trimTrailingNewline) => {
+const add = async (win, pathname, type, endOfLine, autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen) => {
const stats = await fsPromises.stat(pathname)
const birthTime = stats.birthtime
const isMarkdown = hasMarkdownExtension(pathname)
@@ -37,7 +37,8 @@ const add = async (win, pathname, type, endOfLine, autoGuessEncoding, trimTraili
pathname,
endOfLine,
autoGuessEncoding,
- trimTrailingNewline
+ trimTrailingNewline,
+ autoNormalizeMarkdownOnOpen
)
file.data = data
} catch (err) {
@@ -66,7 +67,7 @@ const unlink = (win, pathname, type) => {
})
}
-const change = async (win, pathname, type, endOfLine, autoGuessEncoding, trimTrailingNewline) => {
+const change = async (win, pathname, type, endOfLine, autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen) => {
// No need to update the tree view if the file content has changed.
if (type === 'dir') return
@@ -79,7 +80,8 @@ const change = async (win, pathname, type, endOfLine, autoGuessEncoding, trimTra
pathname,
endOfLine,
autoGuessEncoding,
- trimTrailingNewline
+ trimTrailingNewline,
+ autoNormalizeMarkdownOnOpen
)
const file = {
pathname,
@@ -194,16 +196,16 @@ class Watcher {
if (!await this._shouldIgnoreEvent(win.id, pathname, type, usePolling)) {
const { _preferences } = this
const eol = _preferences.getPreferredEol()
- const { autoGuessEncoding, trimTrailingNewline } = _preferences.getAll()
- add(win, pathname, type, eol, autoGuessEncoding, trimTrailingNewline)
+ const { autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen } = _preferences.getAll()
+ add(win, pathname, type, eol, autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen)
}
})
.on('change', async pathname => {
if (!await this._shouldIgnoreEvent(win.id, pathname, type, usePolling)) {
const { _preferences } = this
const eol = _preferences.getPreferredEol()
- const { autoGuessEncoding, trimTrailingNewline } = _preferences.getAll()
- change(win, pathname, type, eol, autoGuessEncoding, trimTrailingNewline)
+ const { autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen } = _preferences.getAll()
+ change(win, pathname, type, eol, autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen)
}
})
.on('unlink', pathname => unlink(win, pathname, type))
diff --git a/src/main/preferences/schema.json b/src/main/preferences/schema.json
index 7e3df710d..85c87c931 100644
--- a/src/main/preferences/schema.json
+++ b/src/main/preferences/schema.json
@@ -230,6 +230,11 @@
"type": "boolean",
"default": false
},
+ "autoNormalizeMarkdownOnOpen": {
+ "description": "Editor--Automatically normalize line endings and detect trailing newline settings when opening files. When disabled, files are opened as-is and only normalized when saved.",
+ "type": "boolean",
+ "default": false
+ },
"preferLooseListItem": {
"description": "Markdown--The preferred list type",
"type": "boolean",
diff --git a/src/main/windows/editor.js b/src/main/windows/editor.js
index a97a11eb4..e88056d60 100644
--- a/src/main/windows/editor.js
+++ b/src/main/windows/editor.js
@@ -258,10 +258,10 @@ class EditorWindow extends BaseWindow {
const { browserWindow } = this
const { preferences } = this._accessor
const eol = preferences.getPreferredEol()
- const { autoGuessEncoding, trimTrailingNewline } = preferences.getAll()
+ const { autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen } = preferences.getAll()
for (const { filePath, options, selected } of fileList) {
- loadMarkdownFile(filePath, eol, autoGuessEncoding, trimTrailingNewline)
+ loadMarkdownFile(filePath, eol, autoGuessEncoding, trimTrailingNewline, autoNormalizeMarkdownOnOpen)
.then((rawDocument) => {
if (this.lifecycle === WindowLifecycle.READY) {
this._doOpenTab(rawDocument, options, selected)
diff --git a/src/renderer/src/prefComponents/editor/index.vue b/src/renderer/src/prefComponents/editor/index.vue
index b69e62e88..53d257dc1 100644
--- a/src/renderer/src/prefComponents/editor/index.vue
+++ b/src/renderer/src/prefComponents/editor/index.vue
@@ -159,6 +159,11 @@
:bool="autoCheck"
:on-change="(value) => onSelectChange('autoCheck', value)"
>
+
{
diff --git a/static/locales/de.json b/static/locales/de.json
index e61d48f1f..4bd453ffe 100644
--- a/static/locales/de.json
+++ b/static/locales/de.json
@@ -379,6 +379,7 @@
"items": {
"autoSave": "Den bearbeiteten Inhalt automatisch speichern",
"autoSaveDelay": "Die Zeit in ms nach einer Änderung, bis die Datei gespeichert wird",
+ "autoNormalizeMarkdownOnOpen": "Zeilenenden beim Öffnen automatisch normalisieren und Einstellungen für nachfolgende Zeilenumbrüche erkennen. Bei Deaktivierung werden Dateien unverändert geöffnet und nur beim Speichern normalisiert",
"titleBarStyle": "Der Titelleisten-Stil (nur Windows und Linux-System)",
"openFilesInNewWindow": "Dateien in einem neuen Fenster öffnen",
"openFolderInNewWindow": "Ordner über Menü in einem neuen Fenster öffnen",
diff --git a/static/locales/en.json b/static/locales/en.json
index 43bcaae3b..ce2625c7c 100644
--- a/static/locales/en.json
+++ b/static/locales/en.json
@@ -556,6 +556,7 @@
"hideQuickInsertHint": "Hide quick insert hint",
"hideLinkPopup": "Hide link popup",
"autoCheck": "Auto check",
+ "autoNormalizeMarkdownOnOpen": "Auto-normalize line endings on open",
"wrapCodeBlocks": "Wrap code blocks"
}
},
diff --git a/static/locales/es.json b/static/locales/es.json
index 3dbfac28c..8b6b4a038 100644
--- a/static/locales/es.json
+++ b/static/locales/es.json
@@ -379,6 +379,7 @@
"items": {
"autoSave": "Guardar automáticamente el contenido que se está editando",
"autoSaveDelay": "El tiempo en ms después de un cambio que se guarda el archivo",
+ "autoNormalizeMarkdownOnOpen": "Normalizar automáticamente los finales de línea y detectar la configuración de salto de línea final al abrir archivos. Cuando está deshabilitado, los archivos se abren tal cual y solo se normalizan al guardar",
"titleBarStyle": "El estilo de la barra de título (solo sistema Windows y Linux)",
"openFilesInNewWindow": "Abrir archivos en una nueva ventana",
"openFolderInNewWindow": "Abrir carpeta vía menú en una nueva ventana",
diff --git a/static/locales/fr.json b/static/locales/fr.json
index e63b9eee8..dde7c8c2d 100644
--- a/static/locales/fr.json
+++ b/static/locales/fr.json
@@ -380,6 +380,7 @@
"items": {
"autoSave": "Sauvegarder automatiquement le contenu en cours d'édition",
"autoSaveDelay": "Le temps en ms après un changement avant que le fichier soit sauvegardé",
+ "autoNormalizeMarkdownOnOpen": "Normaliser automatiquement les fins de ligne et détecter les paramètres de saut de ligne final lors de l'ouverture des fichiers. Lorsque désactivé, les fichiers sont ouverts tels quels et normalisés uniquement lors de l'enregistrement",
"titleBarStyle": "Le style de la barre de titre (systèmes Windows et Linux uniquement)",
"openFilesInNewWindow": "Ouvrir les fichiers dans une nouvelle fenêtre",
"openFolderInNewWindow": "Ouvrir le dossier via le menu dans une nouvelle fenêtre",
diff --git a/static/locales/ja.json b/static/locales/ja.json
index 98a6d5404..7178be6d3 100644
--- a/static/locales/ja.json
+++ b/static/locales/ja.json
@@ -380,6 +380,7 @@
"items": {
"autoSave": "編集中のコンテンツを自動保存",
"autoSaveDelay": "変更後にファイルが保存されるまでの時間(ミリ秒)",
+ "autoNormalizeMarkdownOnOpen": "ファイルを開く際に行末を自動的に正規化し、末尾の改行設定を検出します。無効にすると、ファイルはそのまま開かれ、保存時にのみ正規化されます",
"titleBarStyle": "タイトルバーのスタイル(WindowsおよびLinuxシステムのみ)",
"openFilesInNewWindow": "新しいウィンドウでファイルを開く",
"openFolderInNewWindow": "メニューから新しいウィンドウでフォルダを開く",
diff --git a/static/locales/ko.json b/static/locales/ko.json
index 5a87df175..da8e64c5f 100644
--- a/static/locales/ko.json
+++ b/static/locales/ko.json
@@ -380,6 +380,7 @@
"items": {
"autoSave": "편집 중인 내용을 자동으로 저장",
"autoSaveDelay": "변경 후 파일이 저장되기까지의 시간(밀리초)",
+ "autoNormalizeMarkdownOnOpen": "파일을 열 때 줄 끝을 자동으로 정규화하고 후행 줄바꿈 설정을 감지합니다. 비활성화하면 파일이 그대로 열리고 저장할 때만 정규화됩니다",
"titleBarStyle": "제목 표시줄 스타일(Windows 및 Linux 시스템만)",
"openFilesInNewWindow": "새 창에서 파일 열기",
"openFolderInNewWindow": "메뉴를 통해 새 창에서 폴더 열기",
diff --git a/static/locales/pt.json b/static/locales/pt.json
index f25693e05..6cb086c7b 100644
--- a/static/locales/pt.json
+++ b/static/locales/pt.json
@@ -380,6 +380,7 @@
"items": {
"autoSave": "Salvar automaticamente o conteúdo sendo editado",
"autoSaveDelay": "O tempo em ms após uma mudança que o arquivo é salvo",
+ "autoNormalizeMarkdownOnOpen": "Normalizar automaticamente as terminações de linha e detectar as configurações de nova linha final ao abrir arquivos. Quando desabilitado, os arquivos são abertos como estão e normalizados apenas ao salvar",
"titleBarStyle": "O estilo da barra de título (apenas sistemas Windows e Linux)",
"openFilesInNewWindow": "Abrir arquivos em uma nova janela",
"openFolderInNewWindow": "Abrir pasta via menu em uma nova janela",
diff --git a/static/locales/zh-CN.json b/static/locales/zh-CN.json
index f3f83b146..6771f56e7 100644
--- a/static/locales/zh-CN.json
+++ b/static/locales/zh-CN.json
@@ -380,6 +380,7 @@
"items": {
"autoSave": "自动保存正在编辑的内容",
"autoSaveDelay": "文件保存前的延迟时间(毫秒)",
+ "autoNormalizeMarkdownOnOpen": "打开文件时自动规范化行尾并检测尾随换行符设置。禁用时,文件按原样打开,仅在保存时规范化",
"titleBarStyle": "标题栏样式(仅限 Windows 和 Linux 系统)",
"openFilesInNewWindow": "在新窗口中打开文件",
"openFolderInNewWindow": "通过菜单在新窗口中打开文件夹",
diff --git a/static/locales/zh-TW.json b/static/locales/zh-TW.json
index 0670d7c36..f0d0a3699 100644
--- a/static/locales/zh-TW.json
+++ b/static/locales/zh-TW.json
@@ -380,6 +380,7 @@
"items": {
"autoSave": "自動儲存正在編輯的內容",
"autoSaveDelay": "檔案儲存前的延遲時間(毫秒)",
+ "autoNormalizeMarkdownOnOpen": "開啟檔案時自動規範化行尾並檢測尾隨換行符設定。停用時,檔案按原樣開啟,僅在儲存時規範化",
"titleBarStyle": "標題欄樣式(僅限 Windows 和 Linux 系統)",
"openFilesInNewWindow": "在新視窗中開啟檔案",
"openFolderInNewWindow": "透過選單在新視窗中開啟資料夾",