🎨 Support auto-convert pasted URL to clickable link format (#17338)

* feat: auto-convert pasted URL to clickable link format (#17337)

Agent-Logs-Url: https://github.com/bytemain/siyuan/sessions/cdea999d-27c0-4260-a0b4-519e011e6667

Co-authored-by: bytemain <13938334+bytemain@users.noreply.github.com>

* fix: use angle bracket URL syntax for markdown link safety

Agent-Logs-Url: https://github.com/bytemain/siyuan/sessions/cdea999d-27c0-4260-a0b4-519e011e6667

Co-authored-by: bytemain <13938334+bytemain@users.noreply.github.com>

* feat: add pasteURLAutoConvert editor setting to control URL auto-linking

Agent-Logs-Url: https://github.com/bytemain/siyuan/sessions/1b722c05-e69f-4964-89bb-7f928d5adeb3

Co-authored-by: bytemain <13938334+bytemain@users.noreply.github.com>

* refactor: reuse setInlineMark for paste URL auto-convert, matching Ctrl+K link handler pattern

Agent-Logs-Url: https://github.com/bytemain/siyuan/sessions/332d1b44-cebe-45b2-833e-72d7e3253a3d

Co-authored-by: bytemain <13938334+bytemain@users.noreply.github.com>

* refactor: extract shared resolveLinkDest and genLinkText utility functions

Agent-Logs-Url: https://github.com/bytemain/siyuan/sessions/316f674d-3ce9-4b40-8711-08edb8af1aec

Co-authored-by: bytemain <13938334+bytemain@users.noreply.github.com>

* Disable automatic URL conversion on paste

* feat: add stripScheme option to genLinkText - keep scheme for paste, strip for Ctrl+K

Agent-Logs-Url: https://github.com/bytemain/siyuan/sessions/960eaf33-f873-4709-8e63-8d9b473de4ee

Co-authored-by: bytemain <13938334+bytemain@users.noreply.github.com>

* Improve link handling in paste function

Refactor link handling in paste function to update range after setting inline mark.

* Fix return statement in paste.ts

* style: fix json tag alignment in Editor struct

* Update app/src/mobile/settings/editor.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(Link): handle URI decoding more safely in genLinkText

Add try-catch block to prevent URI decoding errors and make decoding optional

* feat(editor): add auto URL to link conversion on paste

Implement automatic conversion of pasted URLs to clickable links when the pasteURLAutoConvert setting is enabled. This improves user experience by eliminating the manual step of creating links for pasted URLs. The functionality is extracted into a separate function for better code organization and reuse.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Jiacheng 2026-03-29 22:40:42 +08:00 committed by GitHub
parent 918d1bd9f9
commit 5b84279673
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 130 additions and 12 deletions

View file

@ -463,6 +463,8 @@
"switchDirect": "تغيير اتجاه المقارنة",
"onlySearchForDoc": "<code class='fn__code'>[[</code> للبحث عن المستندات فقط‬",
"onlySearchForDocTip": "بعد التمكين، ]] للبحث عن مراجع الكتلة فقط في أسماء المستندات",
"pasteURLAutoConvert": "تحويل عنوان URL الملصق تلقائيًا إلى رابط",
"pasteURLAutoConvertTip": "عند التمكين، سيؤدي لصق عنوان URL يبدأ بـ http:// أو https:// إلى تحويله تلقائيًا إلى رابط قابل للنقر",
"ocrResult": "‫نص نتيجة OCR",
"reOCR": "‫إعادة OCR",
"continueReview1": "متابعة المراجعة",

View file

@ -463,6 +463,8 @@
"switchDirect": "Vergleichsrichtung wechseln",
"onlySearchForDoc": "<code class='fn__code'>[[</code> nur Dokumente suchen",
"onlySearchForDocTip": "Nach der Aktivierung wird [[ oder 【【 verwendet, um nach Blockreferenzen nur in Dokumentnamen zu suchen",
"pasteURLAutoConvert": "Eingefügte URLs automatisch in Links umwandeln",
"pasteURLAutoConvertTip": "Wenn aktiviert, werden URLs, die mit http:// oder https:// beginnen, beim Einfügen automatisch in klickbare Links umgewandelt",
"ocrResult": "OCR-Ergebnistext",
"reOCR": "Re OCR",
"continueReview1": "Überprüfung fortsetzen",

View file

@ -463,6 +463,8 @@
"switchDirect": "Switch comparison direction",
"onlySearchForDoc": "<code class='fn__code'>[[</code> only search documents",
"onlySearchForDocTip": "When enabled, [[ or 【【 to search for block references only in doc names",
"pasteURLAutoConvert": "Auto-convert pasted URL to link",
"pasteURLAutoConvertTip": "When enabled, pasting a URL starting with http:// or https:// will automatically convert it to a clickable link",
"ocrResult": "OCR result text",
"reOCR": "Re OCR",
"continueReview1": "Continue Review",

View file

@ -463,6 +463,8 @@
"switchDirect": "Cambiar dirección de comparación",
"onlySearchForDoc": "<code class='fn__code'>[[</code> solo buscar documentos",
"onlySearchForDocTip": "Después de habilitar, [[ o 【【 para buscar referencias de bloque solo en nombres de documentos",
"pasteURLAutoConvert": "Convertir automáticamente la URL pegada en enlace",
"pasteURLAutoConvertTip": "Cuando está habilitado, pegar una URL que comience con http:// o https:// la convertirá automáticamente en un enlace clicable",
"ocrResult": "Texto de resultado de OCR",
"reOCR": "Re-OCR",
"continueReview1": "Continuar revisión",

View file

@ -463,6 +463,8 @@
"switchDirect": "Changer le sens de comparaison",
"onlySearchForDoc": "<code class='fn__code'>[[</code> rechercher uniquement les documents",
"onlySearchForDocTip": "Après l'activation, [[ ou 【【 pour rechercher des références de bloc uniquement dans les noms de documents",
"pasteURLAutoConvert": "Convertir automatiquement les URL collées en liens",
"pasteURLAutoConvertTip": "Lorsque cette option est activée, coller une URL commençant par http:// ou https:// la convertit automatiquement en lien cliquable",
"ocrResult": "Texte du résultat OCR",
"reOCR": "ReOCR",
"continueReview1": "Continuer la révision",

View file

@ -463,6 +463,8 @@
"switchDirect": "שנה כיוון השוואה",
"onlySearchForDoc": "<code class='fn__code'>[[</code> חפש רק מסמכים",
"onlySearchForDocTip": "לאחר הפעלה, חפש באמצעות [[ או 【【 רק התייחסויות בלוקים בשמות המסמכים",
"pasteURLAutoConvert": "המרה אוטומטית של כתובת URL מודבקת לקישור",
"pasteURLAutoConvertTip": "כאשר מופעל, הדבקת כתובת URL שמתחילה ב-http:// או https:// תמיר אותה אוטומטית לקישור לחיץ",
"ocrResult": "טקסט תוצאת OCR",
"reOCR": "OCR מחדש",
"continueReview1": "המשך סקירה",

View file

@ -463,6 +463,8 @@
"switchDirect": "Cambia direzione di confronto",
"onlySearchForDoc": "<code class='fn__code'>[[</code> cerca solo nei documenti",
"onlySearchForDocTip": "Dopo l'abilitazione, [[ o 【【 per cercare riferimenti di blocchi solo nei nomi dei documenti",
"pasteURLAutoConvert": "Converti automaticamente URL incollato in link",
"pasteURLAutoConvertTip": "Quando abilitato, incollando un URL che inizia con http:// o https:// verrà automaticamente convertito in un link cliccabile",
"ocrResult": "Risultato OCR",
"reOCR": "Ripeti OCR",
"continueReview1": "Continua la revisione",

View file

@ -463,6 +463,8 @@
"switchDirect": "比較方向の切り替え",
"onlySearchForDoc": "ドキュメント名のみを検索",
"onlySearchForDocTip": "<code class='fn__code'>[[</code> を使用したブロック参照の検索でドキュメント名のみを検索します",
"pasteURLAutoConvert": "貼り付けたURLを自動でリンクに変換",
"pasteURLAutoConvertTip": "有効にすると、http:// または https:// で始まるURLを貼り付けた際に自動的にクリック可能なリンクに変換します",
"ocrResult": "OCR 結果のテキスト",
"reOCR": "再 OCR",
"continueReview1": "復習を続ける",

View file

@ -463,6 +463,8 @@
"switchDirect": "비교 방향 전환",
"onlySearchForDoc": "<code class='fn__code'>[[</code> 문서만 검색",
"onlySearchForDocTip": "활성화하면 [[ 또는 【【 를 사용하여 블록 참조를 검색할 때 문서 이름만 검색합니다",
"pasteURLAutoConvert": "붙여넣은 URL을 자동으로 링크로 변환",
"pasteURLAutoConvertTip": "활성화하면 http:// 또는 https:// 로 시작하는 URL을 붙여넣을 때 자동으로 클릭 가능한 링크로 변환합니다",
"ocrResult": "OCR 결과 텍스트",
"reOCR": "다시 OCR",
"continueReview1": "복습 계속",

View file

@ -463,6 +463,8 @@
"switchDirect": "Zmień kierunek porównania",
"onlySearchForDoc": "<code class='fn__code'>[[</code> tylko szukaj dokumentów",
"onlySearchForDocTip": "Po włączeniu, [[ lub 【【 wyszuka odniesienia bloków tylko w nazwach dokumentów",
"pasteURLAutoConvert": "Automatycznie konwertuj wklejany URL na link",
"pasteURLAutoConvertTip": "Po włączeniu, wklejenie URL zaczynającego się od http:// lub https:// automatycznie przekształci go w klikalny link",
"ocrResult": "Tekst wyniku OCR",
"reOCR": "Re OCR",
"continueReview1": "Kontynuuj przegląd",

View file

@ -463,6 +463,8 @@
"switchDirect": "Alternar direção de comparação",
"onlySearchForDoc": "<code class='fn__code'>[[</code> apenas pesquisa documentos",
"onlySearchForDocTip": "Quando ativado, [[ ou 【【 para pesquisar referências de bloco apenas em nomes de documentos",
"pasteURLAutoConvert": "Converter automaticamente URL colada em link",
"pasteURLAutoConvertTip": "Quando ativado, colar uma URL que começa com http:// ou https:// a converte automaticamente em um link clicável",
"ocrResult": "Texto do resultado OCR",
"reOCR": "Refazer OCR",
"continueReview1": "Continuar Revisão",

View file

@ -463,6 +463,8 @@
"switchDirect": "Переключить направление сравнения",
"onlySearchForDoc": "<code class='fn__code'>[[</code> только искать документы",
"onlySearchForDocTip": "После включения [[ или 【【 искать ссылки на блоки только в названиях документов",
"pasteURLAutoConvert": "Автоматически преобразовывать вставленный URL в ссылку",
"pasteURLAutoConvertTip": "При включении вставка URL, начинающегося с http:// или https://, автоматически преобразует его в кликабельную ссылку",
"ocrResult": "Результаты OCR текста",
"reOCR": "Повторить OCR",
"continueReview1": "Продолжить просмотр",

View file

@ -463,6 +463,8 @@
"switchDirect": "Prepnúť smer porovnávania",
"onlySearchForDoc": "[[ hľadá iba v dokumentoch",
"onlySearchForDocTip": "Ak je povolené, hľadanie cez [[ sa obmedzí len na názvy dokumentov",
"pasteURLAutoConvert": "Automaticky previesť vloženú URL na odkaz",
"pasteURLAutoConvertTip": "Ak je povolené, vloženie URL začínajúcej na http:// alebo https:// ju automaticky prevedie na klikateľný odkaz",
"ocrResult": "Text výsledku OCR",
"reOCR": "Spustiť OCR znova",
"continueReview1": "Pokračovať v opakovaní",

View file

@ -463,6 +463,8 @@
"switchDirect": "Karşılaştırma yönünü değiştir",
"onlySearchForDoc": "<code class='fn__code'>[[</code> sadece belgelerde ara",
"onlySearchForDocTip": "Etkinleştirildiğinde [[ veya 【【 yalnızca belge adlarında blok referanslarını arar",
"pasteURLAutoConvert": "Yapıştırılan URL'yi otomatik olarak bağlantıya dönüştür",
"pasteURLAutoConvertTip": "Etkinleştirildiğinde, http:// veya https:// ile başlayan bir URL yapıştırıldığında otomatik olarak tıklanabilir bir bağlantıya dönüştürülür",
"ocrResult": "OCR sonuç metni",
"reOCR": "OCRyi yeniden çalıştır",
"continueReview1": "Gözden geçirmeye devam et",

View file

@ -463,6 +463,8 @@
"switchDirect": "交換對比方向",
"onlySearchForDoc": "<code class='fn__code'>[[</code> 僅搜索文檔",
"onlySearchForDocTip": "啟用後使用 [[ 或 【【 搜索塊引用時將只在文檔名中搜索",
"pasteURLAutoConvert": "貼上網址時自動轉為連結",
"pasteURLAutoConvertTip": "啟用後貼上 http:// 或 https:// 開頭的網址時將自動轉為可點擊的連結",
"ocrResult": "OCR 結果文字",
"reOCR": "重新 OCR",
"continueReview1": "繼續複習",

View file

@ -463,6 +463,8 @@
"switchDirect": "交换对比方向",
"onlySearchForDoc": "<code class='fn__code'>[[</code> 仅搜索文档",
"onlySearchForDocTip": "启用后使用 [[ 或 【【 搜索块引用时将只在文档名中搜索",
"pasteURLAutoConvert": "粘贴网址时自动转为链接",
"pasteURLAutoConvertTip": "启用后粘贴 http:// 或 https:// 开头的网址时将自动转为可点击的链接",
"ocrResult": "OCR 结果文本",
"reOCR": "重新 OCR",
"continueReview1": "继续复习",

View file

@ -125,6 +125,14 @@ export const editor = {
<span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="onlySearchForDoc" type="checkbox"${window.siyuan.config.editor.onlySearchForDoc ? " checked" : ""}/>
</label>
<label class="fn__flex b3-label">
<div class="fn__flex-1">
${window.siyuan.languages.pasteURLAutoConvert}
<div class="b3-label__text">${window.siyuan.languages.pasteURLAutoConvertTip}</div>
</div>
<span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="pasteURLAutoConvert" type="checkbox"${window.siyuan.config.editor.pasteURLAutoConvert ? " checked" : ""}/>
</label>
<label class="fn__flex b3-label">
<div class="fn__flex-1">
${window.siyuan.languages.md31}
@ -524,6 +532,7 @@ export const editor = {
spellcheckLanguages: window.siyuan.config.editor.spellcheckLanguages,
/// #endif
onlySearchForDoc: (editor.element.querySelector("#onlySearchForDoc") as HTMLInputElement).checked,
pasteURLAutoConvert: (editor.element.querySelector("#pasteURLAutoConvert") as HTMLInputElement).checked,
floatWindowMode,
floatWindowDelay,
plantUMLServePath: (editor.element.querySelector("#plantUMLServePath") as HTMLInputElement).value,

View file

@ -28,7 +28,8 @@ export const initConfigSearch = (element: HTMLElement, app: App) => {
"editorMarkdownInlineTag", "editorMarkdownInlineTagTip", "editorMarkdownInlineMath", "editorMarkdownInlineMathTip",
"editorMarkdownInlineStrikethrough", "editorMarkdownInlineStrikethroughTip", "editorMarkdownInlineMark", "editorMarkdownInlineMarkTip",
"allowHTMLBLockScript", "allowHTMLBLockScriptTip", "floatWindowDelay", "floatWindowDelayTip",
"backlinkContainChildren", "backlinkContainChildrenTip", "allowSVGScript", "allowSVGScriptTip"
"backlinkContainChildren", "backlinkContainChildrenTip", "allowSVGScript", "allowSVGScriptTip",
"pasteURLAutoConvert", "pasteURLAutoConvertTip"
]),
// 文档树

View file

@ -39,6 +39,7 @@ const setEditor = (modelMainElement: Element) => {
window.siyuan.config.editor.listItemDotNumberClickFocus = (modelMainElement.querySelector("#listItemDotNumberClickFocus") as HTMLInputElement).checked;
window.siyuan.config.editor.spellcheck = (modelMainElement.querySelector("#spellcheck") as HTMLInputElement).checked;
window.siyuan.config.editor.onlySearchForDoc = (modelMainElement.querySelector("#onlySearchForDoc") as HTMLInputElement).checked;
window.siyuan.config.editor.pasteURLAutoConvert = (modelMainElement.querySelector("#pasteURLAutoConvert") as HTMLInputElement).checked;
window.siyuan.config.editor.plantUMLServePath = (modelMainElement.querySelector("#plantUMLServePath") as HTMLInputElement).value;
window.siyuan.config.editor.katexMacros = (modelMainElement.querySelector("#katexMacros") as HTMLTextAreaElement).value;
window.siyuan.config.editor.codeLineWrap = (modelMainElement.querySelector("#codeLineWrap") as HTMLInputElement).checked;
@ -157,7 +158,15 @@ export const initEditor = () => {
<div class="b3-label__text">${window.siyuan.languages.onlySearchForDocTip}</div>
</div>
<span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="onlySearchForDoc" type="checkbox"${window.siyuan.config.editor.spellcheck ? " checked" : ""}/>
<input class="b3-switch fn__flex-center" id="onlySearchForDoc" type="checkbox"${window.siyuan.config.editor.onlySearchForDoc ? " checked" : ""}/>
</label>
<label class="fn__flex b3-label">
<div class="fn__flex-1">
${window.siyuan.languages.pasteURLAutoConvert}
<div class="b3-label__text">${window.siyuan.languages.pasteURLAutoConvertTip}</div>
</div>
<span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="pasteURLAutoConvert" type="checkbox"${window.siyuan.config.editor.pasteURLAutoConvert ? " checked" : ""}/>
</label>
<label class="fn__flex b3-label">
<div class="fn__flex-1">

View file

@ -3,6 +3,7 @@ import {linkMenu} from "../../menus/protyle";
import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest";
import {readClipboard} from "../util/compatibility";
import {Constants} from "../../constants";
import {genLinkText, resolveLinkDest} from "./util";
export class Link extends ToolbarItem {
public element: HTMLElement;
@ -44,7 +45,7 @@ export class Link extends ToolbarItem {
}
}
if (!dataHref) {
dataHref = protyle.lute.GetLinkDest(clipObject.textPlain);
dataHref = resolveLinkDest(clipObject.textPlain, protyle.lute);
}
if (!dataHref) {
// 360
@ -56,16 +57,9 @@ export class Link extends ToolbarItem {
}
}
}
// https://github.com/siyuan-note/siyuan/issues/12867
if (!dataHref && clipObject.textPlain.startsWith("assets/")) {
dataHref = clipObject.textPlain;
}
// https://github.com/siyuan-note/siyuan/issues/14704#issuecomment-2867555769 第一点 & https://github.com/siyuan-note/siyuan/issues/6798
if (dataHref && !dataText) {
dataText = decodeURIComponent(dataHref.replace("https://", "").replace("http://", ""));
if (dataHref.length > Constants.SIZE_LINK_TEXT_MAX) {
dataText = dataHref.substring(0, Constants.SIZE_LINK_TEXT_MAX) + "...";
}
dataText = genLinkText(dataHref, true, true);
showMenu = true;
}
}

View file

@ -209,6 +209,39 @@ export const toolbarKeyToMenu = (toolbar: Array<string | IMenuItem>) => {
return toolbarResult;
};
/**
* Detect a URL from text, handling the `assets/` prefix and `GetLinkDest`.
* Returns the resolved href, or an empty string if no URL was detected.
*/
export const resolveLinkDest = (text: string, lute: Lute): string => {
if (text.startsWith("assets/")) {
return text;
}
return lute.GetLinkDest(text);
};
/**
* Generate a display label for a link URL: decode, optionally strip protocol, and truncate.
* Shared between Ctrl+K link handler and paste URL auto-convert.
* @param stripScheme When true, removes https:// and http:// prefixes (used by Ctrl+K).
*/
export const genLinkText = (href: string, stripScheme: boolean = true, decodeURI: boolean = false): string => {
try {
let text = stripScheme
? href.replace("https://", "").replace("http://", "")
: href;
if (decodeURI) {
text = decodeURIComponent(text);
}
if (text.length > Constants.SIZE_LINK_TEXT_MAX) {
text = text.substring(0, Constants.SIZE_LINK_TEXT_MAX) + "...";
}
return text;
} catch {
return href;
}
};
export const copyTextByType = async (ids: string[],
type: "ref" | "blockEmbed" | "protocol" | "protocolMd" | "hPath" | "id" | "webURL") => {
let text = "";

View file

@ -17,6 +17,33 @@ import {getCalloutInfo, getContenteditableElement} from "../wysiwyg/getBlock";
import {clearBlockElement} from "./clear";
import {removeZWJ} from "./normalizeText";
import {base64ToURL} from "../../util/image";
import {resolveLinkDest, genLinkText} from "../toolbar/util";
const pasteAsLink = (text: string, protyle: IProtyle): boolean => {
if (!window.siyuan.config.editor.pasteURLAutoConvert) {
return false;
}
const trimmed = text.trim();
if (!trimmed || trimmed.includes("\n")) {
// TODO 暂不支持多行文本
return false;
}
const linkDest = resolveLinkDest(trimmed, protyle.lute);
if (!linkDest) {
return false;
}
const linkText = genLinkText(linkDest, false);
const linkNodes = protyle.toolbar.setInlineMark(protyle, "a", "range", {
type: "a",
color: linkDest + Constants.ZWSP + linkText
});
if (linkNodes && linkNodes.length > 0) {
const lastNode = linkNodes[linkNodes.length - 1];
protyle.toolbar.range.setStartAfter(lastNode);
protyle.toolbar.range.collapse(true);
}
return true;
};
export const getTextStar = (blockElement: HTMLElement, contentOnly = false) => {
const dataType = blockElement.dataset.type;
@ -418,6 +445,9 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven
return;
}
}
if (pasteAsLink(tempElement.textContent, protyle)) {
return;
}
let isBlock = false;
tempElement.querySelectorAll("[data-node-id]").forEach((e) => {
const newId = Lute.NewNodeID();
@ -584,7 +614,7 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven
return;
} else {
// https://github.com/siyuan-note/siyuan/issues/8475
const linkDest = textPlain.startsWith("assets/") ? textPlain : protyle.lute.GetLinkDest(textPlain);
const linkDest = resolveLinkDest(textPlain, protyle.lute);
if (linkDest) {
protyle.toolbar.setInlineMark(protyle, "a", "range", {
type: "a",
@ -594,6 +624,10 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven
}
}
}
// Auto-convert pasted URL to link format https://github.com/siyuan-note/siyuan/issues/17337
if (pasteAsLink(textPlain, protyle)) {
return;
}
let textPlainDom = protyle.lute.Md2BlockDOM(textPlain);
if (textPlainDom && textPlainDom.indexOf("data:image/") > -1) {
const tempElement = document.createElement("template");

View file

@ -495,6 +495,10 @@ declare namespace Config {
* PlantUML rendering service address
*/
plantUMLServePath: string;
/**
* Whether to auto-convert pasted URLs to links
*/
pasteURLAutoConvert: boolean;
/**
* Whether to enable read-only mode
*/

View file

@ -58,6 +58,7 @@ type Editor struct {
BacklinkSort *int `json:"backlinkSort"` // 反向链接排序方式
BackmentionSort *int `json:"backmentionSort"` // 反链提及排序方式
HeadingEmbedMode int `json:"headingEmbedMode"` // 标题嵌入块模式0显示标题与下方的块1仅显示标题2仅显示标题下方的块
PasteURLAutoConvert bool `json:"pasteURLAutoConvert"` // 粘贴网址时自动转为链接
Markdown *util.Markdown `json:"markdown"` // Markdown 配置
}
@ -100,6 +101,7 @@ func NewEditor() *Editor {
BacklinkSort: func() *int { v := util.SortModeUpdatedDESC; return &v }(),
BackmentionSort: func() *int { v := util.SortModeUpdatedDESC; return &v }(),
HeadingEmbedMode: 0,
PasteURLAutoConvert: false,
Markdown: util.MarkdownSettings,
}
}