Compare commits

...

6 Commits

Author SHA1 Message Date
Natty 63537c8e71
Basic inline tag parsing 2023-10-02 19:23:59 +02:00
Natty b750524c41
Created a project for the MMM parser 2023-10-02 19:23:52 +02:00
Natty a8636947b9
Version unification
ci/woodpecker/push/ociImagePush Pipeline was successful Details
2023-10-02 19:11:35 +02:00
Natty be08be61c6
Frontend: Removed blinking indicators 2023-10-02 19:05:30 +02:00
Natty c58bc2994d
Updated dev hostname in Caddyfile 2023-10-02 19:05:10 +02:00
Natty fc0ec19afb
Frontend: Localization cleanup 2023-10-02 19:04:47 +02:00
18 changed files with 558 additions and 127 deletions

View File

@ -1,4 +1,4 @@
nattyarch.local { magnetar-dev.local {
log { log {
} }

47
Cargo.lock generated
View File

@ -411,6 +411,12 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "bytecount"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.4.3"
@ -511,7 +517,7 @@ dependencies = [
[[package]] [[package]]
name = "ck" name = "ck"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"sea-orm", "sea-orm",
"serde", "serde",
@ -788,7 +794,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]] [[package]]
name = "ext_calckey_model_migration" name = "ext_calckey_model_migration"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"sea-orm-migration", "sea-orm-migration",
"tokio", "tokio",
@ -1375,7 +1381,7 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]] [[package]]
name = "magnetar" name = "magnetar"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"axum", "axum",
"cached", "cached",
@ -1407,7 +1413,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_calckey_fe" name = "magnetar_calckey_fe"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"axum", "axum",
"chrono", "chrono",
@ -1431,7 +1437,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_calckey_model" name = "magnetar_calckey_model"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"chrono", "chrono",
"ck", "ck",
@ -1453,7 +1459,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_common" name = "magnetar_common"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"magnetar_core", "magnetar_core",
"percent-encoding", "percent-encoding",
@ -1464,7 +1470,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_core" name = "magnetar_core"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
@ -1472,7 +1478,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_nodeinfo" name = "magnetar_nodeinfo"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
@ -1480,7 +1486,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_sdk" name = "magnetar_sdk"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"chrono", "chrono",
"http", "http",
@ -1493,7 +1499,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_sdk_macros" name = "magnetar_sdk_macros"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.28", "syn 2.0.28",
@ -1501,7 +1507,7 @@ dependencies = [
[[package]] [[package]]
name = "magnetar_webfinger" name = "magnetar_webfinger"
version = "0.2.0" version = "0.2.1-alpha"
dependencies = [ dependencies = [
"magnetar_core", "magnetar_core",
"serde", "serde",
@ -1603,6 +1609,14 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "mmm_parser"
version = "0.2.0"
dependencies = [
"nom",
"nom_locate",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.3" version = "7.1.3"
@ -1613,6 +1627,17 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "nom_locate"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3"
dependencies = [
"bytecount",
"memchr",
"nom",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"

View File

@ -14,11 +14,12 @@ members = [
"fe_calckey", "fe_calckey",
"magnetar_common", "magnetar_common",
"magnetar_sdk", "magnetar_sdk",
"magnetar_mmm_parser",
"core" "core"
] ]
[workspace.package] [workspace.package]
version = "0.2.0" version = "0.2.1-alpha"
edition = "2021" edition = "2021"
[workspace.dependencies] [workspace.dependencies]
@ -36,6 +37,8 @@ hyper = "0.14"
js-sys = "0.3" js-sys = "0.3"
log = "0.4" log = "0.4"
miette = "5.9" miette = "5.9"
nom = "7"
nom_locate = "4"
percent-encoding = "2.2" percent-encoding = "2.2"
redis = "0.23" redis = "0.23"
reqwest = "0.11" reqwest = "0.11"

View File

@ -163,7 +163,6 @@ function close() {
left: 32px; left: 32px;
color: var(--indicator); color: var(--indicator);
font-size: 8px; font-size: 8px;
animation: blink 1s infinite;
@media (max-width: 500px) { @media (max-width: 500px) {
top: 16px; top: 16px;

View File

@ -483,7 +483,6 @@ onBeforeUnmount(() => {
left: 13px; left: 13px;
color: var(--indicator); color: var(--indicator);
font-size: 12px; font-size: 12px;
animation: blink 1s infinite;
} }
} }

View File

@ -142,7 +142,6 @@ definePageMetadata({
&.ph-circle ph-fill { &.ph-circle ph-fill {
color: var(--indicator); color: var(--indicator);
animation: blink 1s infinite;
} }
&.ph-check { &.ph-check {

View File

@ -1,6 +1,6 @@
<template> <template>
<form class="mk-setup" @submit.prevent="submit()"> <form class="mk-setup" @submit.prevent="submit()">
<h1>Welcome to Calckey!</h1> <h1>Welcome to Magnetar!</h1>
<div class="_formRoot"> <div class="_formRoot">
<p>{{ i18n.ts.intro }}</p> <p>{{ i18n.ts.intro }}</p>
<MkInput <MkInput

View File

@ -691,18 +691,6 @@ hr {
transform: scale(0.9); transform: scale(0.9);
} }
@keyframes blink {
0% {
opacity: 1;
}
70% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes tada { @keyframes tada {
from { from {
transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1);

View File

@ -341,7 +341,6 @@ function more() {
left: 20px; left: 20px;
color: var(--navIndicator); color: var(--navIndicator);
font-size: 8px; font-size: 8px;
animation: blink 1s infinite;
} }
> .text { > .text {

View File

@ -406,7 +406,6 @@ function more(ev: MouseEvent) {
left: 20px; left: 20px;
color: var(--navIndicator); color: var(--navIndicator);
font-size: 8px; font-size: 8px;
animation: blink 1s infinite;
} }
> .text { > .text {
@ -589,7 +588,6 @@ function more(ev: MouseEvent) {
left: 24px; left: 24px;
color: var(--navIndicator); color: var(--navIndicator);
font-size: 8px; font-size: 8px;
animation: blink 1s infinite;
} }
&:hover, &:hover,

View File

@ -544,7 +544,6 @@ async function deleteProfile() {
left: 0; left: 0;
color: var(--indicator); color: var(--indicator);
font-size: 16px; font-size: 16px;
animation: blink 1s infinite;
} }
&:first-child { &:first-child {

View File

@ -663,7 +663,6 @@ console.log(mainRouter.currentRoute.value.name);
left: 0; left: 0;
color: var(--indicator); color: var(--indicator);
font-size: 16px; font-size: 16px;
animation: blink 1s infinite;
} }
} }
@ -684,7 +683,6 @@ console.log(mainRouter.currentRoute.value.name);
left: 0; left: 0;
color: var(--indicator); color: var(--indicator);
font-size: 16px; font-size: 16px;
animation: blink 1s infinite;
} }
&:first-child { &:first-child {

View File

@ -1,22 +1,22 @@
_lang_: "Čeština" _lang_: "Čeština"
headlineMisskey: "Síť propojená poznámkami" headlineMisskey: "Otevřená a decentralizovaná sociální platforma, navždy zdarma"
introMisskey: "Vítejte! Calckey je otevřený a decentralizovaný microblogový servis.\n\ introMisskey: "Vítej! Magnetar je otevřená a decentralizovaná sociální platforma.\n\
\"Poznámkami\" můžete sdílet co se zrovna děje se všemi ve Vašem okolí. \U0001F4E1\ \"Příspěvky\" můžeš sdílet, co se zrovna děje kolem tebe. \U0001F4E1\
\nPomocí \"reakcí\" můžete sdílet své názory a pocity na ostatní poznámky. \U0001F44D\ \nPomocí \"reakcí\" můžeš sdílet své názory a reakce na příspěvky jiných. \U0001F44D\
\nPojďte objevovat nový svět! \U0001F680" \nPojď objevovat nový svět! \U0001F680"
monthAndDay: "{day}. {month}." monthAndDay: "{day}. {month}."
search: "Vyhledávání" search: "Vyhledávání"
notifications: "Oznámení" notifications: "Oznámení"
username: "Uživatelské jméno" username: "Uživatelské jméno"
password: "Heslo" password: "Heslo"
forgotPassword: "Zapomenuté heslo" forgotPassword: "Zapomenuté heslo"
fetchingAsApObject: "Načítám data z Fediversu" fetchingAsApObject: "Načítám data z Fedi"
ok: "Potvrdit" ok: "Potvrdit"
gotIt: "Rozumím!" gotIt: "Rozumím!"
cancel: "Zrušit" cancel: "Zrušit"
enterUsername: "Zadej uživatelské jméno" enterUsername: "Zadej uživatelské jméno"
renotedBy: "{user} přeposla/a" renotedBy: "{user} přeposla/a"
noNotes: "Žádné poznámky" noNotes: "Žádné příspěvky"
noNotifications: "Žádná oznámení" noNotifications: "Žádná oznámení"
instance: "Instance" instance: "Instance"
settings: "Nastavení" settings: "Nastavení"
@ -46,8 +46,8 @@ copyContent: "Zkopírovat obsah"
copyLink: "Kopírovat odkaz" copyLink: "Kopírovat odkaz"
delete: "Smazat" delete: "Smazat"
deleteAndEdit: "Smazat a upravit" deleteAndEdit: "Smazat a upravit"
deleteAndEditConfirm: "Jste si jistí že chcete smazat tuto poznámku a editovat ji?\ deleteAndEditConfirm: "Chceš opravdu smazat tento příspěvek a upravit ho?\
\ Ztratíte tím všechny reakce, sdílení a odpovědi na ni." \ Ztratíš tím všechny reakce, sdílení a odpovědi na něj."
addToList: "Přidat do seznamu" addToList: "Přidat do seznamu"
sendMessage: "Odeslat zprávu" sendMessage: "Odeslat zprávu"
copyUsername: "Kopírovat uživatelské jméno" copyUsername: "Kopírovat uživatelské jméno"
@ -56,7 +56,7 @@ reply: "Odpovědět"
loadMore: "Zobrazit více" loadMore: "Zobrazit více"
showMore: "Zobrazit více" showMore: "Zobrazit více"
showLess: "Zavřít" showLess: "Zavřít"
youGotNewFollower: "Máte nového následovníka" youGotNewFollower: "Máš nového sledujícího"
receiveFollowRequest: "Žádost o sledování přijata" receiveFollowRequest: "Žádost o sledování přijata"
followRequestAccepted: "Žádost o sledování přijata" followRequestAccepted: "Žádost o sledování přijata"
mention: "Zmínění" mention: "Zmínění"
@ -66,16 +66,16 @@ import: "Importovat"
export: "Exportovat" export: "Exportovat"
files: "Soubor(ů)" files: "Soubor(ů)"
download: "Stáhnout" download: "Stáhnout"
driveFileDeleteConfirm: "Opravdu chcete smazat soubor \"{name}\"? Soubor bude odstraněn\ driveFileDeleteConfirm: "Opravdu chceš smazat soubor \"{name}\"? Soubor bude odstraněn\
\ ze všech příspěvků, které ji obsahují jako přílohu." \ ze všech příspěvků, které jej obsahují jako přílohu."
unfollowConfirm: "Jste si jisti že už nechcete sledovat {name}?" unfollowConfirm: "Opravdu již nechceš sledovat {name}?"
exportRequested: "Požádali jste o export. To může chvíli trvat. Přidáme ho na váš\ exportRequested: "Požádal/a jsi o export. To může chvíli trvat. Přidáme ho na tvůj\
\ Disk až bude dokončen." \ Disk až bude dokončen."
importRequested: "Požádali jste o export. To může chvilku trvat." importRequested: "Požádal/a jsi o export. To může chvilku trvat."
lists: "Seznamy" lists: "Seznamy"
noLists: "Nemáte žádné seznamy" noLists: "Nemáš žádné seznamy"
note: "Poznámka" note: "Příspěvek"
notes: "Poznámky" notes: "Příspěvky"
following: "Sledovaní" following: "Sledovaní"
followers: "Sledující" followers: "Sledující"
followsYou: "Sledují vás" followsYou: "Sledují vás"
@ -86,8 +86,8 @@ error: "Chyba"
somethingHappened: "Jejda. Něco se nepovedlo." somethingHappened: "Jejda. Něco se nepovedlo."
retry: "Opakovat" retry: "Opakovat"
pageLoadError: "Nepodařilo se načíst stránku" pageLoadError: "Nepodařilo se načíst stránku"
serverIsDead: "Server neodpovídá. Počkejte chvíli a zkuste to znovu." serverIsDead: "Server neodpovídá. Zkus to prosím znovu později."
youShouldUpgradeClient: "Pro zobrazení této stránky obnovte stránku pro aktualizaci\ youShouldUpgradeClient: "Pro zobrazení této stránky obnov stránku pro aktualizaci\
\ klienta." \ klienta."
enterListName: "Jméno seznamu" enterListName: "Jméno seznamu"
privacy: "Soukromí" privacy: "Soukromí"
@ -105,16 +105,16 @@ renoted: "Přeposláno"
cantRenote: "Tento příspěvek nelze přeposlat." cantRenote: "Tento příspěvek nelze přeposlat."
cantReRenote: "Odpověď nemůže být odstraněna." cantReRenote: "Odpověď nemůže být odstraněna."
quote: "Citovat" quote: "Citovat"
pinnedNote: "Připnutá poznámka" pinnedNote: "Připnutý příspěvek"
pinned: "Připnout" pinned: "Připnout"
you: "Vy" you: "Ty"
clickToShow: "Klikněte pro zobrazení" clickToShow: "Klikněte pro zobrazení"
sensitive: "NSFW" sensitive: "NSFW"
add: "Přidat" add: "Přidat"
reaction: "Reakce" reaction: "Reakce"
reactionSettingDescription2: "Přetažením změníte pořadí, kliknutím smažete, zmáčkněte\ reactionSettingDescription2: "Přetažením změníš pořadí, kliknutím smažeš, zmáčkni\
\ \"+\" k přidání" \ \"+\" k přidání"
rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky" rememberNoteVisibility: "Zapamatovat nastavení zobrazení příspěvků"
attachCancel: "Odstranit přílohu" attachCancel: "Odstranit přílohu"
markAsSensitive: "Označit jako NSFW" markAsSensitive: "Označit jako NSFW"
unmarkAsSensitive: "Odznačit jako NSFW" unmarkAsSensitive: "Odznačit jako NSFW"
@ -124,14 +124,14 @@ unmute: "Odmlčet"
block: "Zablokovat" block: "Zablokovat"
unblock: "Odblokovat" unblock: "Odblokovat"
suspend: "Zmrazit" suspend: "Zmrazit"
unsuspend: "Odmrazit" unsuspend: "Zrušit zmrazení"
blockConfirm: "Jste si jistí že chcete zablokovat tento účet?" blockConfirm: "Opravdu zablokovat tento účet?"
unblockConfirm: "Jste si jistí že chcete odblokovat tento účet?" unblockConfirm: "Opravdu odblokovat tento účet?"
suspendConfirm: "Jste si jistí že chcete suspendovat tenhle účet?" suspendConfirm: "Opravdu zmrazit tenhle účet?"
unsuspendConfirm: "Jste si jistí že chcete obnovit tenhle účet?" unsuspendConfirm: "Opravdu obnovit tenhle účet?"
selectList: "Vybrat seznam" selectList: "Vybrat seznam"
selectAntenna: "Vyberte Anténu" selectAntenna: "Vyber Anténu"
selectWidget: "Zvolte widget" selectWidget: "Zvol widget"
editWidgets: "Upravit widget" editWidgets: "Upravit widget"
editWidgetsExit: "Hotovo" editWidgetsExit: "Hotovo"
customEmojis: "Vlastní emoji" customEmojis: "Vlastní emoji"
@ -150,11 +150,11 @@ flagAsBotDescription: "Pokud je tento účet kontrolován programem zaškrtněte
\ To označí tento účet jako bot pro ostatní vývojáře a zabrání tak nekonečným interakcím\ \ To označí tento účet jako bot pro ostatní vývojáře a zabrání tak nekonečným interakcím\
\ s ostatními boty a upraví Calckey systém aby se choval k tomuhle účtu jako bot." \ s ostatními boty a upraví Calckey systém aby se choval k tomuhle účtu jako bot."
flagAsCat: "Tenhle účet je kočka" flagAsCat: "Tenhle účet je kočka"
flagAsCatDescription: "Vyberte tuto možnost aby tento účet byl označen jako kočka." flagAsCatDescription: "Vyber tuto možnost, aby tento účet byl označen jako kočka."
flagShowTimelineReplies: "Zobrazovat odpovědi na časové ose" flagShowTimelineReplies: "Zobrazovat odpovědi na časové ose"
flagShowTimelineRepliesDescription: "Je-li zapnuto, zobrazí odpovědi uživatelů na\ flagShowTimelineRepliesDescription: "Je-li zapnuto, zobrazí odpovědi uživatelů na\
\ poznámky jiných uživatelů na vaší časové ose." \ příspěvky jiných uživatelů na tvé časové ose."
autoAcceptFollowed: "Automaticky akceptovat následování od účtů které sledujete" autoAcceptFollowed: "Automaticky přijmout sledování od účtů, které sleduješ"
addAccount: "Přidat účet" addAccount: "Přidat účet"
loginFailed: "Přihlášení se nezdařilo." loginFailed: "Přihlášení se nezdařilo."
showOnRemote: "Více na původním profilu" showOnRemote: "Více na původním profilu"
@ -163,8 +163,8 @@ wallpaper: "Obrázek na pozadí"
setWallpaper: "Nastavení obrázku na pozadí" setWallpaper: "Nastavení obrázku na pozadí"
removeWallpaper: "Odstranit pozadí" removeWallpaper: "Odstranit pozadí"
searchWith: "Hledat: {q}" searchWith: "Hledat: {q}"
youHaveNoLists: "Nemáte žádné seznamy" youHaveNoLists: "Nemáš žádné seznamy"
followConfirm: "Jste si jisti, že chcete sledovat {name}?" followConfirm: "Chceš sledovat {name}?"
proxyAccount: "Proxy účet" proxyAccount: "Proxy účet"
proxyAccountDescription: "Proxy účet je účet, který za určitých podmínek sleduje uživatele\ proxyAccountDescription: "Proxy účet je účet, který za určitých podmínek sleduje uživatele\
\ na dálku vaším jménem. Například když uživatel zařadí vzdáleného uživatele do\ \ na dálku vaším jménem. Například když uživatel zařadí vzdáleného uživatele do\
@ -198,26 +198,26 @@ disk: "Disk"
instanceInfo: "Informace o instanci" instanceInfo: "Informace o instanci"
statistics: "Statistiky" statistics: "Statistiky"
clearQueue: "Vyčistit frontu" clearQueue: "Vyčistit frontu"
clearQueueConfirmTitle: "Jste si jisti že zrušit všechny úlohy ve frontě?" clearQueueConfirmTitle: "Opravdu zrušit všechny úlohy ve frontě?"
clearCachedFiles: "Vyprázdnit mezipaměť" clearCachedFiles: "Vyprázdnit mezipaměť"
blockedInstances: "Blokované instance" blockedInstances: "Blokované instance"
noUsers: "Žádní uživatelé" noUsers: "Žádní uživatelé"
editProfile: "Upravit můj profil" editProfile: "Upravit můj profil"
pinLimitExceeded: "Nemůžete připnout další poznámky." pinLimitExceeded: "Nemůžeš připnout další příspěvky."
intro: "Instalace Calckey byla dokončena! Prosím vytvořte admina." intro: "Instalace Magnetaru byla dokončena! Prosím vytvoř administrátorský účet."
done: "Hotovo" done: "Hotovo"
processing: "Zpracovávám" processing: "Zpracovávám"
preview: "Náhled" preview: "Náhled"
default: "Výchozí" default: "Výchozí"
noCustomEmojis: "Bez Emoji" noCustomEmojis: "Bez Emoji"
blocked: "Blokováno" blocked: "Blokováno"
suspended: "Suspendováno" suspended: "Zmraženo"
all: "Vše" all: "Vše"
subscribing: "Odebíráte" subscribing: "Odebíráš"
publishing: "Publikuji" publishing: "Publikuji"
notResponding: "Neodpovídá" notResponding: "Neodpovídá"
instanceFollowing: "Následovníci na instanci" instanceFollowing: "Sledovaní na instanci"
instanceFollowers: "Následovníci na instanci" instanceFollowers: "Sledující na instanci"
instanceUsers: "Uživatelé této instance" instanceUsers: "Uživatelé této instance"
changePassword: "Změnit heslo" changePassword: "Změnit heslo"
security: "Zabezpečení" security: "Zabezpečení"
@ -227,15 +227,15 @@ newPassword: "Nové heslo"
newPasswordRetype: "Nové heslo (znovu)" newPasswordRetype: "Nové heslo (znovu)"
attachFile: "Přiložit soubor" attachFile: "Přiložit soubor"
more: "Více!" more: "Více!"
featured: "Oblíbené poznámky" featured: "Oblíbené příspěvky"
usernameOrUserId: "Uživatelské jméno nebo uživatelské id" usernameOrUserId: "Uživatelské jméno nebo uživatelské id"
noSuchUser: "Uživatel nebyl nalezen" noSuchUser: "Uživatel nebyl nalezen"
announcements: "Oznámení" announcements: "Oznámení"
imageUrl: "URL obrázku" imageUrl: "URL obrázku"
remove: "Smazat" remove: "Smazat"
removed: "Smazáno" removed: "Smazáno"
removeAreYouSure: "Jste si jistí že chcete smazat \"{x}\"?" removeAreYouSure: "Opravdu chceš odebrat \"{x}\"?"
deleteAreYouSure: "Jste si jistí že chcete smazat \"{x}\"?" deleteAreYouSure: "Opravdu chceš smazat \"{x}\"?"
resetAreYouSure: "Opravdu resetovat?" resetAreYouSure: "Opravdu resetovat?"
saved: "Uloženo" saved: "Uloženo"
messaging: "Zprávy" messaging: "Zprávy"
@ -243,7 +243,7 @@ upload: "Nahrát soubory"
fromDrive: "Z disku" fromDrive: "Z disku"
fromUrl: "Z URL" fromUrl: "Z URL"
uploadFromUrl: "Nahrát z URL adresy" uploadFromUrl: "Nahrát z URL adresy"
uploadFromUrlDescription: "URL adresa souboru, který chcete nahrát" uploadFromUrlDescription: "URL adresa souboru, který chceš nahrát"
uploadFromUrlMayTakeTime: "Může trvat nějakou dobu, dokud nebude dokončeno nahrávání." uploadFromUrlMayTakeTime: "Může trvat nějakou dobu, dokud nebude dokončeno nahrávání."
explore: "Objevovat" explore: "Objevovat"
messageRead: "Přečtené" messageRead: "Přečtené"
@ -254,7 +254,7 @@ agreeTo: "Souhlasím s {0}"
tos: "Podmínky užívání" tos: "Podmínky užívání"
start: "Začít" start: "Začít"
home: "Domů" home: "Domů"
remoteUserCaution: "Tyto informace nemusí být aktuální jelikož uživatel je ze vzdálené\ remoteUserCaution: "Tyto informace nemusí být aktuální jelikož uživatel je z jiné\
\ instance." \ instance."
activity: "Aktivita" activity: "Aktivita"
images: "Obrázky" images: "Obrázky"
@ -269,7 +269,7 @@ light: "Světlý"
dark: "Tmavý" dark: "Tmavý"
lightThemes: "Světlý vzhled" lightThemes: "Světlý vzhled"
darkThemes: "Tmavý vzhled" darkThemes: "Tmavý vzhled"
syncDeviceDarkMode: "Synchronizovat tmavý vzhled s nastavením Vašeho systému" syncDeviceDarkMode: "Synchronizovat tmavý vzhled s nastavením systému"
drive: "Úložiště" drive: "Úložiště"
fileName: "Název souboru" fileName: "Název souboru"
selectFile: "Vybrat soubor" selectFile: "Vybrat soubor"
@ -284,8 +284,8 @@ deleteFolder: "Odstranit složku"
addFile: "Přidat soubor" addFile: "Přidat soubor"
emptyFolder: "Tato složka je prázdná" emptyFolder: "Tato složka je prázdná"
unableToDelete: "Nelze smazat" unableToDelete: "Nelze smazat"
inputNewFileName: "Zadejte nový název" inputNewFileName: "Zadej nový název"
inputNewFolderName: "Zadejte název nové složky" inputNewFolderName: "Zadej název nové složky"
copyUrl: "Kopírovat URL" copyUrl: "Kopírovat URL"
rename: "Přejmenovat" rename: "Přejmenovat"
avatar: "Avatar" avatar: "Avatar"
@ -325,7 +325,7 @@ bannerUrl: "Baner URL"
backgroundImageUrl: "Adresa URL obrázku pozadí" backgroundImageUrl: "Adresa URL obrázku pozadí"
basicInfo: "Základní informace" basicInfo: "Základní informace"
pinnedUsers: "Připnutí uživatelé" pinnedUsers: "Připnutí uživatelé"
pinnedNotes: "Připnutá poznámka" pinnedNotes: "Připnuté příspěvky"
hcaptcha: "hCaptcha" hcaptcha: "hCaptcha"
enableHcaptcha: "Aktivovat hCaptchu" enableHcaptcha: "Aktivovat hCaptchu"
hcaptchaSiteKey: "Klíč stránky" hcaptchaSiteKey: "Klíč stránky"
@ -341,7 +341,7 @@ antennaSource: "Zdroj Antény"
enableServiceworker: "Povolit ServiceWorker" enableServiceworker: "Povolit ServiceWorker"
caseSensitive: "Rozlišuje malá a velká písmena" caseSensitive: "Rozlišuje malá a velká písmena"
connectedTo: "Následující účty jsou připojeny" connectedTo: "Následující účty jsou připojeny"
notesAndReplies: "Poznámky a odpovědi" notesAndReplies: "Příspěvky a odpovědi"
withFiles: "Včetně souborů" withFiles: "Včetně souborů"
popularUsers: "Populární uživatelé" popularUsers: "Populární uživatelé"
recentlyUpdatedUsers: "Nedávno aktívni uživatelé" recentlyUpdatedUsers: "Nedávno aktívni uživatelé"
@ -351,7 +351,7 @@ about: "Informace"
aboutMisskey: "O Magnetaru" aboutMisskey: "O Magnetaru"
administrator: "Administrátor" administrator: "Administrátor"
token: "Token" token: "Token"
twoStepAuthentication: "Dvoufaktorová autentikace" twoStepAuthentication: "Dvoufaktorová autentifikace"
moderator: "Moderátor" moderator: "Moderátor"
nUsersMentioned: "{n} uživatelů zmínilo" nUsersMentioned: "{n} uživatelů zmínilo"
securityKey: "Bezpečnostní klíč" securityKey: "Bezpečnostní klíč"
@ -371,7 +371,7 @@ markAsReadAllNotifications: "Označit všechna oznámení za přečtená"
markAsReadAllUnreadNotes: "Označit všechny příspěvky za přečtené" markAsReadAllUnreadNotes: "Označit všechny příspěvky za přečtené"
markAsReadAllTalkMessages: "Označit všechny zprávy za přečtené" markAsReadAllTalkMessages: "Označit všechny zprávy za přečtené"
help: "Nápověda" help: "Nápověda"
inputMessageHere: "Sem zadejte zprávu" inputMessageHere: "Sem zadej zprávu"
close: "Zavřít" close: "Zavřít"
group: "Skupina" group: "Skupina"
groups: "Skupiny" groups: "Skupiny"
@ -386,15 +386,15 @@ title: "Titulek"
text: "Text" text: "Text"
enable: "Povolit" enable: "Povolit"
next: "Další" next: "Další"
retype: "Zadejte znovu" retype: "Zadej znovu"
noteOf: "{user} poznámky" noteOf: "Příspěvky od {user}"
inviteToGroup: "Pozvat do skupiny" inviteToGroup: "Pozvat do skupiny"
quoteAttached: "Citace" quoteAttached: "Citace"
quoteQuestion: "Přiložit jako citaci?" quoteQuestion: "Přiložit jako citaci?"
noMessagesYet: "Zatím tu nejsou žádné zprávy" noMessagesYet: "Zatím tu nejsou žádné zprávy"
newMessageExists: "Máte novou zprávu" newMessageExists: "Máte novou zprávu"
onlyOneFileCanBeAttached: "Ke zprávě můžete přiložit jenom jeden soubor" onlyOneFileCanBeAttached: "Ke zprávě můžeš přiložit jenom jeden soubor"
signinRequired: "Přihlašte se, prosím" signinRequired: "Přihlaš se pro pokračování"
invitations: "Pozvat" invitations: "Pozvat"
invitationCode: "Kód pozvánky" invitationCode: "Kód pozvánky"
checking: "Ověřuji" checking: "Ověřuji"
@ -409,8 +409,8 @@ strongPassword: "Silné heslo"
passwordMatched: "Hesla se schodují" passwordMatched: "Hesla se schodují"
passwordNotMatched: "Hesla se neschodují" passwordNotMatched: "Hesla se neschodují"
signinWith: "Přihlásit se s {x}" signinWith: "Přihlásit se s {x}"
signinFailed: "Nelze se přihlásit. Zkontrolujte prosím své uživatelské jméno a heslo." signinFailed: "Nelze se přihlásit. Zkontroluj prosím své uživatelské jméno a heslo."
tapSecurityKey: "Ťukněte na bezpečnostní klíč" tapSecurityKey: "Klepni na bezpečnostní klíč"
or: "Nebo" or: "Nebo"
language: "Jazyk" language: "Jazyk"
uiLanguage: "Jazyk uživatelského rozhraní" uiLanguage: "Jazyk uživatelského rozhraní"
@ -418,7 +418,7 @@ groupInvited: "Pozvat do skupiny"
aboutX: "O {x}" aboutX: "O {x}"
useOsNativeEmojis: "Použití nativních emoji operačního systému" useOsNativeEmojis: "Použití nativních emoji operačního systému"
youHaveNoGroups: "Nemáte žádné skupiny" youHaveNoGroups: "Nemáte žádné skupiny"
joinOrCreateGroup: "Můžete požádat o pozvání do stávající skupiny nebo vytvořit novou." joinOrCreateGroup: "Můžeš požádat o pozvání do stávající skupiny nebo vytvořit novou."
noHistory: "Žádná historie" noHistory: "Žádná historie"
signinHistory: "Historie přihlášení" signinHistory: "Historie přihlášení"
category: "Kategorie" category: "Kategorie"
@ -471,8 +471,8 @@ output: "Výstup"
script: "Skript" script: "Skript"
updateRemoteUser: "Aktualizovat informace o vzdáleném účtu" updateRemoteUser: "Aktualizovat informace o vzdáleném účtu"
deleteAllFiles: "Smazat všechny soubory" deleteAllFiles: "Smazat všechny soubory"
deleteAllFilesConfirm: "Jste si jistí že chcete smazat všechny soubory?" deleteAllFilesConfirm: "Ópravdu chceš smazat všechny soubory?"
userSuspended: "Tomuto uživateli byl pozastaven účet." userSuspended: "Tomuto uživateli byl zmražen účet."
menu: "Menu" menu: "Menu"
divider: "Dělící čára" divider: "Dělící čára"
addItem: "Přidat položku" addItem: "Přidat položku"
@ -504,7 +504,7 @@ smtpHost: "Hostitel"
smtpPort: "Port" smtpPort: "Port"
smtpUser: "Uživatelské jméno" smtpUser: "Uživatelské jméno"
smtpPass: "Heslo" smtpPass: "Heslo"
smtpSecureInfo: "Toto vypněte pokud používáte STARTTLS" smtpSecureInfo: "Toto vypni pokud používáš STARTTLS"
testEmail: "Otestovat doručení emailů" testEmail: "Otestovat doručení emailů"
makeActive: "Aktivovat" makeActive: "Aktivovat"
display: "Zobrazit" display: "Zobrazit"
@ -533,7 +533,7 @@ optional: "Volitelné"
yes: "Ano" yes: "Ano"
no: "Ne" no: "Ne"
notSet: "Není nastaveno" notSet: "Není nastaveno"
emailVerified: "Váš e-mail byl ověřen" emailVerified: "Tvůj e-mail byl ověřen"
contact: "Kontakt" contact: "Kontakt"
useSystemFont: "Použít výchozí font systému" useSystemFont: "Použít výchozí font systému"
clips: "Útržky" clips: "Útržky"
@ -546,7 +546,7 @@ wide: "Široké"
narrow: "Úzké" narrow: "Úzké"
clearCache: "Vyprázdnit mezipaměť" clearCache: "Vyprázdnit mezipaměť"
nUsers: "{n} užívatelů" nUsers: "{n} užívatelů"
nNotes: "{n} poznámek" nNotes: "{n} příspěvků"
myTheme: "Moje vzhledy" myTheme: "Moje vzhledy"
backgroundColor: "Pozadí" backgroundColor: "Pozadí"
accentColor: "Akcent" accentColor: "Akcent"
@ -620,7 +620,7 @@ recentNDays: "Posledních {n} dnů"
recommended: "Doporučeno" recommended: "Doporučeno"
deleteAccount: "Odstranit účet" deleteAccount: "Odstranit účet"
document: "Dokumentace" document: "Dokumentace"
logoutConfirm: "Opravdu se chcete odhlásit?" logoutConfirm: "Opravdu se chceš odhlásit?"
pleaseSelect: "Vybrat možnost" pleaseSelect: "Vybrat možnost"
reverse: "Otočit" reverse: "Otočit"
colored: "Barevné" colored: "Barevné"
@ -690,7 +690,7 @@ _theme:
renote: "Přeposlat" renote: "Přeposlat"
divider: "Dělící čára" divider: "Dělící čára"
_sfx: _sfx:
note: "Poznámky" note: "Příspěvky"
notification: "Oznámení" notification: "Oznámení"
chat: "Zprávy" chat: "Zprávy"
_ago: _ago:
@ -732,7 +732,7 @@ _cw:
hide: "Skrýt" hide: "Skrýt"
show: "Zobrazit více" show: "Zobrazit více"
_poll: _poll:
noMore: "Více už přidat nemůžete" noMore: "Více už přidat nemůžeš"
infinite: "Nikdy" infinite: "Nikdy"
deadlineDate: "Datum ukončení" deadlineDate: "Datum ukončení"
deadlineTime: "Hodin" deadlineTime: "Hodin"
@ -742,16 +742,21 @@ _visibility:
followers: "Sledující" followers: "Sledující"
_postForm: _postForm:
_placeholders: _placeholders:
f: "Čekám, až něco napíšete..." a: "Jak je?"
b: "Co se aktuálně děje?"
c: "Co máš teď na mysli?"
d: "O čem cheš psát?"
e: "Začni psát..."
f: "Obsah příspěvku..."
_profile: _profile:
name: "Jméno" name: "Jméno"
username: "Uživatelské jméno" username: "Uživatelské jméno"
description: "O mně" description: "O mně"
youCanIncludeHashtags: "V popisku o Vás můžete použít i hastagy." youCanIncludeHashtags: "V popisku o sobě můžeš použít i hastagy."
metadata: "Doplňující informace" metadata: "Doplňující informace"
metadataContent: "Obsah" metadataContent: "Obsah"
_exportOrImport: _exportOrImport:
allNotes: "Všechny poznámky" allNotes: "Všechny příspěvky"
followingList: "Sledovaní" followingList: "Sledovaní"
muteList: "Ztlumit" muteList: "Ztlumit"
blockingList: "Zablokovat" blockingList: "Zablokovat"
@ -761,7 +766,7 @@ _charts:
apRequest: "Požadavek" apRequest: "Požadavek"
usersTotal: "Celkem uživatelů" usersTotal: "Celkem uživatelů"
activeUsers: "Aktivní uživatelé" activeUsers: "Aktivní uživatelé"
notesTotal: "Celkový počet poznámek" notesTotal: "Celkový počet příspěvků"
_timelines: _timelines:
home: "Domů" home: "Domů"
global: "Globální" global: "Globální"
@ -772,7 +777,7 @@ _pages:
updated: "Stránka byla úspěšně aktualizována" updated: "Stránka byla úspěšně aktualizována"
deleted: "Stránka byla úspěšně smazána" deleted: "Stránka byla úspěšně smazána"
pageSetting: "Nastavení stránky" pageSetting: "Nastavení stránky"
invalidNameText: "Ujistěte se že jméno stránky je vyplněno" invalidNameText: "Ujisti se, že jméno stránky je vyplněno"
contents: "Obsah" contents: "Obsah"
fontSerif: "Serif" fontSerif: "Serif"
fontSansSerif: "Sans Serif" fontSansSerif: "Sans Serif"
@ -927,7 +932,7 @@ _pages:
number: "Číselná hodnota" number: "Číselná hodnota"
array: "Seznamy" array: "Seznamy"
_notification: _notification:
youWereFollowed: "Máte nového následovníka" youWereFollowed: "Máš nového sledujícího"
youWereInvitedToGroup: "Pozvat do skupiny" youWereInvitedToGroup: "Pozvat do skupiny"
_types: _types:
all: "Vše" all: "Vše"
@ -948,7 +953,7 @@ _deck:
list: "Seznamy" list: "Seznamy"
mentions: "Zmínění" mentions: "Zmínění"
bookmarks: "Záložky uživatelů" bookmarks: "Záložky uživatelů"
noteDeleteConfirm: Chcete opravdu smazat tento příspěvek? noteDeleteConfirm: Chceš opravdu smazat tento příspěvek?
defaultValueIs: 'Výchozí: {value}' defaultValueIs: 'Výchozí: {value}'
lookup: Hledat lookup: Hledat
keepOriginalUploading: Ponechat originální obrázek keepOriginalUploading: Ponechat originální obrázek
@ -958,7 +963,7 @@ reloadConfirm: Znovu načíst časovou osu?
driveCapacityPerRemoteAccount: Místo na disku pro vzdálené uživatele driveCapacityPerRemoteAccount: Místo na disku pro vzdálené uživatele
silenceThisInstance: Ztlumit tuto instance silenceThisInstance: Ztlumit tuto instance
silencedInstances: Ztlumené instance silencedInstances: Ztlumené instance
blockedInstancesDescription: Zadejte seznam domén instancí, jež chcete blokovat. Uvedené blockedInstancesDescription: Zadej seznam domén instancí, které chceš blokovat. Uvedené
instance nebudou moci s touto instancí komunikovat. instance nebudou moci s touto instancí komunikovat.
hiddenTags: Skryté hashtagy hiddenTags: Skryté hashtagy
noInstances: Nejsou zde žádné instance noInstances: Nejsou zde žádné instance
@ -966,27 +971,27 @@ silenced: Ztlumené
disablingTimelinesInfo: Administrátoři a moderátoři budou vždy mít přístup ke všem disablingTimelinesInfo: Administrátoři a moderátoři budou vždy mít přístup ke všem
časovým osám, i pokud jsou vypnuté. časovým osám, i pokud jsou vypnuté.
deleted: Vymazáno deleted: Vymazáno
editNote: Upravit poznámku editNote: Upravit příspěvek
edited: 'Upraveno dne {date} {time}' edited: 'Upraveno dne {date} {time}'
silencedInstancesDescription: Vypište hostnames instancí, které chcete ztlumit. Účty silencedInstancesDescription: Vypiš domény instancí, které chceš ztlumit. Účty
v uvedených instancích jsou považovány za "ztlumené", mohou pouze zadávat požadavky v uvedených instancích jsou považovány za "ztlumené", mohou pouze zadávat požadavky
na sledování a nemohou zmiňovat místní účty, pokud nejsou sledovány. Na blokované na sledování a nemohou zmiňovat místní účty, pokud nejsou sledovány. Na blokované
instance toto nebude mít vliv. instance toto nebude mít vliv.
hiddenTagsDescription: 'Vypište hashtagy (bez #), které chcete skrýt před trendy a hiddenTagsDescription: 'Vypiš hashtagy (bez #), které chceš skrýt před trendy a
prozkoumat. Skryté hashtagy jsou stále zjistitelné jinými způsoby. Blokované případy stránkou Prozkoumat. Skryté hashtagy jsou stále zjistitelné jinými způsoby. Blokované případy
nejsou ovlivněny, i když jsou zde uvedeny.' nejsou ovlivněny, i když jsou zde uvedeny.'
circularReferenceFolder: Cílová složka je podsložka přesouvané složky. circularReferenceFolder: Cílová složka je podsložka přesouvané složky.
whenServerDisconnected: Při ztrátě spojení se serverem whenServerDisconnected: Při ztrátě spojení se serverem
pinnedUsersDescription: Uveďte uživatelská jména uživatelů připnutých na stránce "Procházet", pinnedUsersDescription: Uveďte uživatelská jména uživatelů připnutých na stránce "Procházet",
jedno na řádek. jedno na řádek.
pinnedPagesDescription: Zadejte cesty ke stránkám, které chcete připnout na horní pinnedPagesDescription: Zadej cesty ke stránkám, které chceš připnout na horní
stránku této instance, oddělené zlomy řádků. stránku této instance, oddělené zlomy řádků.
pageLoadErrorDescription: Toto je obvykle způsobeno chybami sítě nebo mezipaměti prohlížeče. pageLoadErrorDescription: Toto je obvykle způsobeno chybami sítě nebo mezipaměti prohlížeče.
Zkuste vymazat mezipaměť a po chvíli čekání to zkuste znovu. Zkuste vymazat mezipaměť a po chvíli čekání to zkuste znovu.
emptyDrive: Váš disk je prázdný emptyDrive: Váš disk je prázdný
inputNewDescription: Zadejte nový popisek inputNewDescription: Zadejte nový popisek
hasChildFilesOrFolders: Složka nemůže být smazána, protože není prázdná. hasChildFilesOrFolders: Složka nemůže být smazána, protože není prázdná.
noThankYou: Ne, děkuji noThankYou: Ne, díky
addInstance: Přidat instance addInstance: Přidat instance
selectInstance: Vybrat si instance selectInstance: Vybrat si instance
blockedUsers: Zablokovaní uživatelé blockedUsers: Zablokovaní uživatelé
@ -995,7 +1000,7 @@ noJobs: Žádné úlohy
federating: Federace federating: Federace
clearQueueConfirmText: Nedoručené příspěvky, které zůstanou ve frontě, nebudou federovány. clearQueueConfirmText: Nedoručené příspěvky, které zůstanou ve frontě, nebudou federovány.
Obvykle tato operace není potřeba. Obvykle tato operace není potřeba.
clearCachedFilesConfirm: Chcete opravdu vymazat mezipaměť všech vzdálených souborů? clearCachedFilesConfirm: Chceš opravdu vymazat mezipaměť všech vzdálených souborů?
accountMoved: 'Uživatel/ka se přesunul/a na nový účet:' accountMoved: 'Uživatel/ka se přesunul/a na nový účet:'
keepOriginalUploadingDescription: Ponechá originálně nahraný obrázek tak, jak je. keepOriginalUploadingDescription: Ponechá originálně nahraný obrázek tak, jak je.
Pokud vypnuto, verze pro zobrazení na webu bude vygenerována při nahrání. Pokud vypnuto, verze pro zobrazení na webu bude vygenerována při nahrání.
@ -1010,5 +1015,5 @@ reactionSetting: Reakce, které se mají zobrazit v seznamu reakcí
renoteMute: Ztlumit přeposílání renoteMute: Ztlumit přeposílání
renoteUnmute: Zrušit ztlumení přeposílání renoteUnmute: Zrušit ztlumení přeposílání
flagSpeakAsCat: Mluvit jako kočka flagSpeakAsCat: Mluvit jako kočka
flagSpeakAsCatDescription: Vaše příspěvky budou v kočičím režimu nyanifikovány. flagSpeakAsCatDescription: Tvoje příspěvky budou v kočičím režimu nyanifikovány.
controlPanel: "Ovládací panel" controlPanel: "Ovládací panel"

View File

@ -1,11 +1,11 @@
_lang_: "English" _lang_: "English"
headlineMisskey: "An open source, decentralized social media platform that's free headlineMisskey: "An open source, decentralized social media platform that's free
forever! 🚀" forever! 🚀"
introMisskey: "Welcome! Calckey is an open source, decentralized social media platform introMisskey: "Welcome! Magnetar is an open source, decentralized social media platform
that's free forever! 🚀" that's free forever! 🚀"
monthAndDay: "{month}/{day}" monthAndDay: "{month}/{day}"
search: "Search" search: "Search"
searchPlaceholder: "Search Calckey" searchPlaceholder: "Search the Fediverse"
notifications: "Notifications" notifications: "Notifications"
username: "Username" username: "Username"
password: "Password" password: "Password"
@ -905,7 +905,7 @@ hashtags: "Hashtags"
troubleshooting: "Troubleshooting" troubleshooting: "Troubleshooting"
useBlurEffect: "Use blur effects in the UI" useBlurEffect: "Use blur effects in the UI"
learnMore: "Learn more" learnMore: "Learn more"
misskeyUpdated: "Calckey has been updated!" misskeyUpdated: "Magnetar has been updated!"
whatIsNew: "Show changes" whatIsNew: "Show changes"
translate: "Translate" translate: "Translate"
translatedFrom: "Translated from {x}" translatedFrom: "Translated from {x}"
@ -1459,7 +1459,7 @@ _filters:
followingOnly: "Following only" followingOnly: "Following only"
followersOnly: "Followers only" followersOnly: "Followers only"
_tutorial: _tutorial:
title: "How to use Calckey" title: "How to use Magnetar"
step1_1: "Welcome!" step1_1: "Welcome!"
step1_2: "Let's get you set up. You'll be up and running in no time!" step1_2: "Let's get you set up. You'll be up and running in no time!"
step2_1: "First, please fill out your profile." step2_1: "First, please fill out your profile."

View File

@ -1,6 +1,6 @@
{ {
"name": "calckey", "name": "calckey-magnetar",
"version": "14.0.0-alpha+magnetar-0.2.0", "version": "0.2.1-alpha",
"codename": "aqua", "codename": "aqua",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -0,0 +1,9 @@
[package]
name = "mmm_parser"
version.workspace = true
edition.workspace = true
license = "MIT OR Apache-2.0"
[dependencies]
nom = { workspace = true }
nom_locate = { workspace = true }

View File

@ -0,0 +1,5 @@
# MMM
Magnetar {marinated, modified} Markdown?
#TODO: Finish docs

View File

@ -0,0 +1,405 @@
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete;
use nom::character::complete::{anychar, line_ending, not_line_ending, tab};
use nom::combinator::{fail, not, opt};
use nom::error::ErrorKind;
use nom::multi::{many1, separated_list1};
use nom::sequence::tuple;
use nom::{IResult, Offset, Slice};
use nom_locate::LocatedSpan;
use std::borrow::Cow;
enum Token<'a> {
PlainText(Cow<'a, str>),
Sequence(Vec<Token<'a>>),
Quote(Box<Token<'a>>),
Small(Box<Token<'a>>),
Big(Box<Token<'a>>),
BoldItalic(Box<Token<'a>>),
Bold(Box<Token<'a>>),
Italic(Box<Token<'a>>),
Center(Box<Token<'a>>),
Strikethrough(Box<Token<'a>>),
PlainTag(Cow<'a, str>),
InlineCode(Cow<'a, str>),
InlineMath(Cow<'a, str>),
}
impl Token<'_> {
fn owned(&self) -> Token<'static> {
match self {
Token::PlainText(text) => Token::PlainText(Cow::Owned(text.clone().into_owned())),
Token::Sequence(tokens) => Token::Sequence(tokens.iter().map(Token::owned).collect()),
Token::Quote(inner) => Token::Quote(Box::new(inner.owned())),
Token::Small(inner) => Token::Small(Box::new(inner.owned())),
Token::Big(inner) => Token::Big(Box::new(inner.owned())),
Token::BoldItalic(inner) => Token::BoldItalic(Box::new(inner.owned())),
Token::Bold(inner) => Token::Bold(Box::new(inner.owned())),
Token::Italic(inner) => Token::Italic(Box::new(inner.owned())),
Token::Center(inner) => Token::Center(Box::new(inner.owned())),
Token::Strikethrough(inner) => Token::Strikethrough(Box::new(inner.owned())),
Token::PlainTag(tag) => Token::PlainTag(Cow::Owned(tag.clone().into_owned())),
Token::InlineCode(code) => Token::InlineCode(Cow::Owned(code.clone().into_owned())),
Token::InlineMath(math) => Token::InlineMath(Cow::Owned(math.clone().into_owned())),
}
}
}
type Span<'a> = LocatedSpan<&'a str>;
trait SliceOffset {
fn up_to(&self, other: &Self) -> Self;
fn fragment_between<'a>(&self, other: &Self) -> &'a str
where
Self: 'a;
}
impl SliceOffset for Span<'_> {
fn up_to(&self, other: &Self) -> Self {
self.slice(..self.offset(other))
}
fn fragment_between<'a>(&self, other: &Self) -> &'a str
where
Self: 'a,
{
self.up_to(other).into_fragment()
}
}
const fn boxing_sequence<'a>(
func: impl Fn(Box<Token<'a>>) -> Token<'a>,
) -> impl Fn(Vec<Token<'a>>) -> Token<'a> {
move |tokens| func(Box::new(Token::Sequence(tokens)))
}
const fn collect_char_sequence<'a>(
func: impl Fn(Cow<'a, str>) -> Token<'a>,
) -> impl Fn(Vec<char>) -> Token<'a> {
move |chars| func(Cow::Owned(chars.into_iter().collect()))
}
fn spliced<'a>(
segments: &[Span<'a>],
func: impl Fn(Span) -> IResult<Span, Token>,
parent: Span<'a>,
) -> IResult<Span<'a>, Token<'static>, nom::error::Error<Span<'a>>> {
let combined = segments
.iter()
.copied()
.map(Span::into_fragment)
.collect::<String>();
let cum_offset_combined = segments
.iter()
.scan(0, |acc, &x| {
*acc += x.len();
Some(*acc)
})
.collect::<Vec<_>>();
let current_seg = |input: Span| {
cum_offset_combined
.iter()
.enumerate()
.filter(|(_, &o)| o >= input.location_offset())
.map(|(i, o)| (segments[i], o))
.last()
};
type NE<E> = nom::Err<E>;
type NomError<'x> = nom::error::Error<Span<'x>>;
let quote_span = Span::new(&combined);
let (input, inner) = match func(quote_span) {
Ok((input, token)) => (input, token.owned()),
Err(e) => {
return match e {
NE::Error(e) => {
let offset_new = e.input.location_offset();
if let Some((seg_parent, offset_seg_new)) = current_seg(e.input) {
let offset = offset_new - offset_seg_new;
let offset_orig = offset + seg_parent.location_offset();
Err(NE::Error(NomError::new(
Span::new(&parent.into_fragment()[offset_orig..]),
e.code,
)))
} else {
// ???
Err(NE::Failure(NomError::new(parent, ErrorKind::Fail)))
}
}
NE::Failure(e) => Err(NE::Error(NomError::new(parent, e.code))),
NE::Incomplete(i) => Err(NE::Incomplete(i)),
};
}
};
let out = if let Some((seg_parent, offset_seg_new)) = current_seg(input) {
let offset = input.location_offset() - offset_seg_new;
let offset_orig = offset + seg_parent.location_offset();
parent.slice(offset_orig..)
} else {
parent
};
Ok((out, Token::Quote(Box::new(inner.owned()))))
}
fn space(input: Span) -> IResult<Span, Token> {
let start = input;
let (input, _) = alt((complete::char('\u{0020}'), complete::char('\u{3000}'), tab))(input)?;
Ok((
input,
Token::PlainText(start.fragment_between(&input).into()),
))
}
struct Context;
impl Context {
const fn partial<'a>(
&self,
func: impl Fn(&Self, Span<'a>) -> IResult<Span<'a>, Token<'a>> + 'static,
) -> impl Fn(Span<'a>) -> IResult<Span<'a>, Token<'a>> + '_ {
move |input| func(self, input)
}
fn root<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
let (input, token) = alt((self.partial(Self::tag_quote),))(input)?;
Ok((input, token))
}
fn inline<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
let (input, token) = alt((self.partial(Self::tag_small), self.partial(Self::text)))(input)?;
Ok((input, token))
}
fn tag_quote<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
let (input, leading_spaces) = tuple((opt(line_ending), opt(line_ending)))(input)?;
if let (None, None) = leading_spaces {
if input.get_column() != 0 {
return fail(input);
}
}
let quote_line = |input| tuple((tag(">"), opt(space), not_line_ending))(input);
let orig_input = input;
let (input, lines) = separated_list1(line_ending, quote_line)(input)?;
let quote_lines = lines
.into_iter()
.map(|(_, _, text)| text)
.collect::<Vec<_>>();
if quote_lines.len() == 1
&& quote_lines
.iter()
.map(Span::fragment)
.copied()
.any(&str::is_empty)
{
return fail(input);
}
let (_, inner) = spliced(&quote_lines, space, orig_input)?;
let (input, _) = tuple((opt(line_ending), opt(line_ending)))(input)?;
Ok((input, Token::Quote(Box::new(inner))))
}
const fn tag_delimited<'a, 'b: 'a, T>(
&'a self,
start: &'b str,
end: &'b str,
escape: bool,
matcher_inner: impl Fn(Span<'b>) -> IResult<Span<'b>, T> + 'a,
mapper: impl Fn(Vec<T>) -> Token<'b> + 'a,
) -> impl Fn(Span<'b>) -> IResult<Span<'b>, Token<'b>> + '_ {
move |input| {
let opening_tag = &tag(start);
let closing_tag = &tag(end);
if escape {
if let Ok((input_escaped, (_, mark))) = tuple((tag("\\"), opening_tag))(input) {
return Ok((input_escaped, Token::PlainText(Cow::Borrowed(&mark))));
}
}
let begin = input;
let (post_open, _) = opening_tag(input)?;
let res = tuple((
many1(tuple((not(closing_tag), &matcher_inner))),
closing_tag,
))(post_open);
if let Err(nom::Err::Error(nom::error::Error { .. })) = res {
return Ok((
post_open,
Token::PlainText(begin.fragment_between(&post_open).into()),
));
}
let (input, (inner, _)) = res?;
let inner = inner.into_iter().map(|(_, t)| t).collect::<Vec<_>>();
Ok((input, mapper(inner)))
}
}
fn tag_small<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"<small>",
"</small>",
false,
self.partial(Self::inline),
boxing_sequence(Token::Small),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_bold_italic_asterisk<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"***",
"***",
true,
self.partial(Self::inline),
boxing_sequence(Token::BoldItalic),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_bold_italic_underscore<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"___",
"___",
true,
self.partial(Self::inline),
boxing_sequence(Token::BoldItalic),
)(input)
}
fn tag_bold<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"<b>",
"</b>",
false,
self.partial(Self::inline),
boxing_sequence(Token::Bold),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_bold_asterisk<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"**",
"**",
true,
self.partial(Self::inline),
boxing_sequence(Token::Bold),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_bold_underscore<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"__",
"__",
true,
self.partial(Self::inline),
boxing_sequence(Token::Bold),
)(input)
}
fn tag_italic<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"<i>",
"</i>",
false,
self.partial(Self::inline),
boxing_sequence(Token::Italic),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_italic_asterisk<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"*",
"*",
true,
self.partial(Self::inline),
boxing_sequence(Token::Italic),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_italic_underscore<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"_",
"_",
true,
self.partial(Self::inline),
boxing_sequence(Token::Italic),
)(input)
}
fn tag_strikethrough<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"<s>",
"</s>",
false,
self.partial(Self::inline),
boxing_sequence(Token::Strikethrough),
)(input)
}
// TODO: CommonMark flanking rules
fn tag_strikethrough_tilde<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"~~",
"~~",
true,
move |input| {
tuple((not_line_ending, self.partial(Self::inline)))(input).map(|(i, t)| (i, t.1))
},
boxing_sequence(Token::Strikethrough),
)(input)
}
fn tag_inline_code<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"`",
"",
true,
move |input| {
tuple((not(alt((tag("`"), tag("´"), line_ending))), anychar))(input)
.map(|(i, (_skip, c))| (i, c))
},
collect_char_sequence(Token::InlineCode),
)(input)
}
fn tag_inline_math<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
self.tag_delimited(
"\\(",
"\\)",
false,
move |input| tuple((not_line_ending, anychar))(input).map(|(i, (_skip, c))| (i, c)),
collect_char_sequence(Token::InlineMath),
)(input)
}
fn text<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
let before = input;
let (input, _) = anychar(input)?;
Ok((
input,
Token::PlainText(before.fragment_between(&input).into()),
))
}
}