mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-24 20:17:38 +08:00
add VarText utils
This commit is contained in:
parent
d180e7d04f
commit
2db56738f8
@ -11,7 +11,7 @@ ij_formatter_off_tag = @formatter:off
|
|||||||
ij_formatter_on_tag = @formatter:on
|
ij_formatter_on_tag = @formatter:on
|
||||||
ij_formatter_tags_enabled = true
|
ij_formatter_tags_enabled = true
|
||||||
ij_smart_tabs = false
|
ij_smart_tabs = false
|
||||||
ij_visual_guides =
|
ij_visual_guides = 95
|
||||||
ij_wrap_on_typing = false
|
ij_wrap_on_typing = false
|
||||||
|
|
||||||
[*.conf]
|
[*.conf]
|
||||||
@ -528,7 +528,7 @@ ij_scala_preserve_space_after_method_declaration_name = false
|
|||||||
ij_scala_reformat_on_compile = false
|
ij_scala_reformat_on_compile = false
|
||||||
ij_scala_replace_case_arrow_with_unicode_char = false
|
ij_scala_replace_case_arrow_with_unicode_char = false
|
||||||
ij_scala_replace_for_generator_arrow_with_unicode_char = false
|
ij_scala_replace_for_generator_arrow_with_unicode_char = false
|
||||||
ij_scala_replace_lambda_with_greek_letter = false
|
ij_scala_replace_lambda_with_greek_letter = true
|
||||||
ij_scala_replace_map_arrow_with_unicode_char = false
|
ij_scala_replace_map_arrow_with_unicode_char = false
|
||||||
ij_scala_scalafmt_config_path =
|
ij_scala_scalafmt_config_path =
|
||||||
ij_scala_scalafmt_fallback_to_default_settings = false
|
ij_scala_scalafmt_fallback_to_default_settings = false
|
||||||
@ -847,6 +847,7 @@ ij_typescript_union_types_wrap = on_every_item
|
|||||||
ij_typescript_use_chained_calls_group_indents = false
|
ij_typescript_use_chained_calls_group_indents = false
|
||||||
ij_typescript_use_double_quotes = true
|
ij_typescript_use_double_quotes = true
|
||||||
ij_typescript_use_explicit_js_extension = auto
|
ij_typescript_use_explicit_js_extension = auto
|
||||||
|
ij_typescript_use_import_type = auto
|
||||||
ij_typescript_use_path_mapping = always
|
ij_typescript_use_path_mapping = always
|
||||||
ij_typescript_use_public_modifier = false
|
ij_typescript_use_public_modifier = false
|
||||||
ij_typescript_use_semicolon_after_statement = true
|
ij_typescript_use_semicolon_after_statement = true
|
||||||
@ -1026,6 +1027,7 @@ ij_javascript_union_types_wrap = on_every_item
|
|||||||
ij_javascript_use_chained_calls_group_indents = false
|
ij_javascript_use_chained_calls_group_indents = false
|
||||||
ij_javascript_use_double_quotes = false
|
ij_javascript_use_double_quotes = false
|
||||||
ij_javascript_use_explicit_js_extension = auto
|
ij_javascript_use_explicit_js_extension = auto
|
||||||
|
ij_javascript_use_import_type = auto
|
||||||
ij_javascript_use_path_mapping = always
|
ij_javascript_use_path_mapping = always
|
||||||
ij_javascript_use_public_modifier = false
|
ij_javascript_use_public_modifier = false
|
||||||
ij_javascript_use_semicolon_after_statement = false
|
ij_javascript_use_semicolon_after_statement = false
|
||||||
@ -1319,7 +1321,7 @@ ij_kotlin_wrap_elvis_expressions = 1
|
|||||||
ij_kotlin_wrap_expression_body_functions = 1
|
ij_kotlin_wrap_expression_body_functions = 1
|
||||||
ij_kotlin_wrap_first_method_in_call_chain = false
|
ij_kotlin_wrap_first_method_in_call_chain = false
|
||||||
|
|
||||||
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.conf,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config,mcmod.info,meatball_from_mutton.json,pack.mcmeta}]
|
[{*.har,*.jsb2,*.jsb3,*.json,*.jsonc,*.postman_collection,*.postman_collection.json,*.postman_environment,*.postman_environment.json,.babelrc,.conf,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config,mcmod.info,meatball_from_mutton.json,pack.mcmeta}]
|
||||||
ij_smart_tabs = true
|
ij_smart_tabs = true
|
||||||
ij_json_array_wrapping = split_into_lines
|
ij_json_array_wrapping = split_into_lines
|
||||||
ij_json_keep_blank_lines_in_code = 0
|
ij_json_keep_blank_lines_in_code = 0
|
||||||
@ -1401,7 +1403,7 @@ ij_markdown_min_lines_between_paragraphs = 1
|
|||||||
ij_markdown_wrap_text_if_long = true
|
ij_markdown_wrap_text_if_long = true
|
||||||
ij_markdown_wrap_text_inside_blockquotes = true
|
ij_markdown_wrap_text_inside_blockquotes = true
|
||||||
|
|
||||||
[{*.pb,*.textproto}]
|
[{*.pb,*.textproto,*.txtpb}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
tab_width = 2
|
tab_width = 2
|
||||||
|
@ -13,6 +13,7 @@ import cc.sukazyo.cono.morny.util.schedule.Scheduler
|
|||||||
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis
|
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis
|
||||||
import cc.sukazyo.cono.morny.util.time.WatchDog
|
import cc.sukazyo.cono.morny.util.time.WatchDog
|
||||||
import cc.sukazyo.cono.morny.util.GivenContext
|
import cc.sukazyo.cono.morny.util.GivenContext
|
||||||
|
import cc.sukazyo.cono.morny.util.UseString.MString
|
||||||
import cc.sukazyo.cono.morny.util.UseThrowable.toLogString
|
import cc.sukazyo.cono.morny.util.UseThrowable.toLogString
|
||||||
import com.pengrad.telegrambot.TelegramBot
|
import com.pengrad.telegrambot.TelegramBot
|
||||||
import com.pengrad.telegrambot.request.GetMe
|
import com.pengrad.telegrambot.request.GetMe
|
||||||
@ -119,12 +120,12 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
|
|||||||
val externalContext: GivenContext = GivenContext()
|
val externalContext: GivenContext = GivenContext()
|
||||||
import cc.sukazyo.cono.morny.util.dataview.Table.format as fmtTable
|
import cc.sukazyo.cono.morny.util.dataview.Table.format as fmtTable
|
||||||
logger `info`
|
logger `info`
|
||||||
s"""The following Modules have been added to current Morny:
|
m"""The following Modules have been added to current Morny:
|
||||||
|${fmtTable(
|
|${fmtTable(
|
||||||
("Module ID" :: "Module Name" :: "Module Version" :: Nil)::Nil :::
|
"Module ID" :: "Module Name" :: "Module Version" :: Nil,
|
||||||
modules.map(f => f.id :: f.name :: f.version :: Nil)
|
modules.map(f => f.id :: f.name :: f.version :: Nil)*
|
||||||
).replaceAll("\n", "\n|")}
|
)}
|
||||||
|""".stripMargin
|
|"""
|
||||||
|
|
||||||
///>>> BLOCK START instance configure & startup stage 1
|
///>>> BLOCK START instance configure & startup stage 1
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package cc.sukazyo.cono.morny.core.bot.command
|
|||||||
import cc.sukazyo.cono.morny.core.{MornyCoeur, MornySystem}
|
import cc.sukazyo.cono.morny.core.{MornyCoeur, MornySystem}
|
||||||
import cc.sukazyo.cono.morny.core.bot.api.{ICommandAlias, ITelegramCommand}
|
import cc.sukazyo.cono.morny.core.bot.api.{ICommandAlias, ITelegramCommand}
|
||||||
import cc.sukazyo.cono.morny.core.bot.api.messages.{ErrorMessage, MessagingContext}
|
import cc.sukazyo.cono.morny.core.bot.api.messages.{ErrorMessage, MessagingContext}
|
||||||
|
import cc.sukazyo.cono.morny.core.Log.logger
|
||||||
import cc.sukazyo.cono.morny.data.MornyInformation.*
|
import cc.sukazyo.cono.morny.data.MornyInformation.*
|
||||||
import cc.sukazyo.cono.morny.data.TelegramStickers
|
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||||
import cc.sukazyo.cono.morny.reporter.MornyReport
|
import cc.sukazyo.cono.morny.reporter.MornyReport
|
||||||
@ -10,13 +11,14 @@ import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration}
|
|||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.unsafeExecute
|
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.unsafeExecute
|
||||||
|
import cc.sukazyo.cono.morny.util.var_text
|
||||||
|
import cc.sukazyo.cono.morny.util.var_text.VarText
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
import com.pengrad.telegrambot.model.request.ParseMode
|
import com.pengrad.telegrambot.model.request.ParseMode
|
||||||
import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker}
|
import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker}
|
||||||
import com.pengrad.telegrambot.TelegramBot
|
import com.pengrad.telegrambot.TelegramBot
|
||||||
|
|
||||||
import java.lang.System
|
import java.lang.System
|
||||||
// todo: maybe move some utils method outside
|
|
||||||
class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
||||||
private given TelegramBot = coeur.account
|
private given TelegramBot = coeur.account
|
||||||
|
|
||||||
@ -74,11 +76,19 @@ class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
cxt.bind_chat.id,
|
cxt.bind_chat.id,
|
||||||
getAboutPic
|
getAboutPic
|
||||||
).caption(
|
).caption(
|
||||||
s"""<b>Morny Cono</b>
|
// language=html
|
||||||
|
(VarText(
|
||||||
|
"""<b>Morny Cono</b>
|
||||||
|来自安妮的侍从小鼠。
|
|来自安妮的侍从小鼠。
|
||||||
|————————————————
|
|————————————————
|
||||||
|$getMornyAboutLinksHTML"""
|
|{about_links}""".stripMargin
|
||||||
.stripMargin
|
).render(
|
||||||
|
"about_links" -> getMornyAboutLinksHTML
|
||||||
|
) :: Nil)
|
||||||
|
.map( f =>
|
||||||
|
logger `trace` f
|
||||||
|
f
|
||||||
|
).head
|
||||||
).parseMode(ParseMode HTML).replyToMessageId(cxt.bind_message.messageId)
|
).parseMode(ParseMode HTML).replyToMessageId(cxt.bind_message.messageId)
|
||||||
.unsafeExecute
|
.unsafeExecute
|
||||||
|
|
||||||
@ -127,16 +137,26 @@ class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
val versionGitHTML = if (MornySystem.GIT_COMMIT nonEmpty) s"git $getVersionGitTagHTML" else ""
|
val versionGitHTML = if (MornySystem.GIT_COMMIT nonEmpty) s"git $getVersionGitTagHTML" else ""
|
||||||
SendMessage(
|
SendMessage(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
|
VarText(
|
||||||
// language=html
|
// language=html
|
||||||
s"""version:
|
"""version:
|
||||||
|- Morny <code>${h(MornySystem.CODENAME toUpperCase)}</code>
|
|- Morny <code>{version_codename}</code>
|
||||||
|- <code>${h(MornySystem.VERSION_BASE)}</code>$versionDeltaHTML${if (MornySystem.GIT_COMMIT nonEmpty) "\n- " + versionGitHTML else ""}
|
|- <code>{version_base}</code>{version_delta_html}{version_git_suffix}
|
||||||
|coeur md5_hash:
|
|coeur md5_hash:
|
||||||
|- <code>${h(MornySystem.getJarMD5)}</code>
|
|- <code>{md5}</code>
|
||||||
|coding timestamp:
|
|coding timestamp:
|
||||||
|- <code>${MornySystem.CODE_TIMESTAMP}</code>
|
|- <code>{time_millis}</code>
|
||||||
|- <code>${h(formatDate(MornySystem.CODE_TIMESTAMP, 0))} [UTC]</code>
|
|- <code>{time_utc} [UTC]</code>
|
||||||
|""".stripMargin
|
|""".stripMargin
|
||||||
|
).render(
|
||||||
|
"version_codename" -> h(MornySystem.CODENAME.toUpperCase),
|
||||||
|
"version_base" -> h(MornySystem.VERSION_BASE),
|
||||||
|
"version_delta_html" -> versionDeltaHTML,
|
||||||
|
"version_git_suffix" -> (if (MornySystem.GIT_COMMIT nonEmpty) "\n- " + versionGitHTML else ""),
|
||||||
|
"md5" -> h(MornySystem.getJarMD5),
|
||||||
|
"time_millis" -> MornySystem.CODE_TIMESTAMP,
|
||||||
|
"time_utc" -> h(formatDate(MornySystem.CODE_TIMESTAMP, 0)),
|
||||||
|
)
|
||||||
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||||
.unsafeExecute
|
.unsafeExecute
|
||||||
}
|
}
|
||||||
@ -145,27 +165,48 @@ class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
def sysprop (p: String): String = System.getProperty(p)
|
def sysprop (p: String): String = System.getProperty(p)
|
||||||
SendMessage(
|
SendMessage(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
|
VarText(
|
||||||
/* language=html */
|
/* language=html */
|
||||||
s"""system:
|
"""system:
|
||||||
|- <code>${h(if getRuntimeHostname nonEmpty then getRuntimeHostname.get else "<unknown-host>")}</code>
|
|- <code>{hostname}</code>
|
||||||
|- <code>${h(sysprop("os.name"))}</code> <code>${h(sysprop("os.arch"))}</code> <code>${h(sysprop("os.version"))}</code>
|
|- <code>{os.name}</code> <code>{os.arch}</code> <code>{os.version}</code>
|
||||||
|java runtime:
|
|java runtime:
|
||||||
|- <code>${h(sysprop("java.vm.vendor"))}.${h(sysprop("java.vm.name"))}</code>
|
|- <code>{java.vm.vendor}.{java.vm.name}</code>
|
||||||
|- <code>${h(sysprop("java.vm.version"))}</code>
|
|- <code>{java.vm.version}</code>
|
||||||
|vm memory:
|
|vm memory:
|
||||||
|- <code>${Runtime.getRuntime.totalMemory/1024/1024}</code> / <code>${Runtime.getRuntime.maxMemory/1024/1024}</code> MB
|
|- <code>{memory_used_mb}</code> / <code>{memory_available_mb}</code> MB
|
||||||
|- <code>${Runtime.getRuntime.availableProcessors}</code> cores
|
|- <code>{cpu_cores}</code> cores
|
||||||
|coeur version:
|
|coeur version:
|
||||||
|- $getVersionAllFullTagHTML
|
|- {version_full}
|
||||||
|- <code>${h(MornySystem.getJarMD5)}</code>
|
|- <code>{coeur_md5}</code>
|
||||||
|- <code>${h(formatDate(MornySystem.CODE_TIMESTAMP, 0))} [UTC]</code>
|
|- <code>{compile_time_utc} [UTC]</code>
|
||||||
|- [<code>${MornySystem.CODE_TIMESTAMP}</code>]
|
|- [<code>{compile_time_millis}</code>]
|
||||||
|continuous:
|
|continuous:
|
||||||
|- <code>${h(formatDuration(System.currentTimeMillis - coeur.coeurStartTimestamp))}</code>
|
|- <code>{running_duration}</code>
|
||||||
|- [<code>${System.currentTimeMillis - coeur.coeurStartTimestamp}</code>]
|
|- [<code>{running_duration_ms}</code>]
|
||||||
|- <code>${h(formatDate(coeur.coeurStartTimestamp, 0))}</code>
|
|- <code>{startup_time_utc}</code>
|
||||||
|- [<code>${coeur.coeurStartTimestamp}</code>]"""
|
|- [<code>{startup_time_millis}</code>]"""
|
||||||
.stripMargin
|
.stripMargin
|
||||||
|
).render(
|
||||||
|
"hostname" -> h(if getRuntimeHostname nonEmpty then getRuntimeHostname.get else "<unknown-host>"),
|
||||||
|
"os.name" -> h(sysprop("os.name")),
|
||||||
|
"os.arch" -> h(sysprop("os.arch")),
|
||||||
|
"os.version" -> h(sysprop("os.version")),
|
||||||
|
"java.vm.vendor" -> h(sysprop("java.vm.vendor")),
|
||||||
|
"java.vm.name" -> h(sysprop("java.vm.name")),
|
||||||
|
"java.vm.version" -> h(sysprop("java.vm.version")),
|
||||||
|
"memory_used_mb" -> (Runtime.getRuntime.totalMemory/1024/1024),
|
||||||
|
"memory_available_mb" -> (Runtime.getRuntime.maxMemory/1024/1024),
|
||||||
|
"cpu_cores" -> Runtime.getRuntime.availableProcessors,
|
||||||
|
"version_full" -> getVersionAllFullTagHTML,
|
||||||
|
"coeur_md5" -> h(MornySystem.getJarMD5),
|
||||||
|
"compile_time_utc" -> h(formatDate(MornySystem.CODE_TIMESTAMP, 0)),
|
||||||
|
"compile_time_millis" -> MornySystem.CODE_TIMESTAMP,
|
||||||
|
"running_duration" -> h(formatDuration(System.currentTimeMillis - coeur.coeurStartTimestamp)),
|
||||||
|
"running_duration_ms" -> (System.currentTimeMillis - coeur.coeurStartTimestamp),
|
||||||
|
"startup_time_utc" -> h(formatDate(coeur.coeurStartTimestamp, 0)),
|
||||||
|
"startup_time_millis" -> coeur.coeurStartTimestamp
|
||||||
|
)
|
||||||
).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId)
|
).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId)
|
||||||
.unsafeExecute
|
.unsafeExecute
|
||||||
}
|
}
|
||||||
@ -174,12 +215,18 @@ class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
// if !coeur.trusted.isTrusted(update.message.from.id) then return;
|
// if !coeur.trusted.isTrusted(update.message.from.id) then return;
|
||||||
SendMessage(
|
SendMessage(
|
||||||
update.message.chat.id,
|
update.message.chat.id,
|
||||||
|
VarText(
|
||||||
// language=html
|
// language=html
|
||||||
s"""<b>Coeur Task Scheduler:</b>
|
"""<b>Coeur Task Scheduler:</b>
|
||||||
| - <i>scheduled tasks</i>: <code>${coeur.tasks.amount}</code>
|
| - <i>scheduled tasks</i>: <code>{coeur.tasks.amount}</code>
|
||||||
| - <i>scheduler status</i>: <code>${coeur.tasks.state}</code>
|
| - <i>scheduler status</i>: <code>{coeur.tasks.state}</code>
|
||||||
| - <i>current runner status</i>: <code>${coeur.tasks.runnerState}</code>
|
| - <i>current runner status</i>: <code>{coeur.tasks.runnerState}</code>
|
||||||
|""".stripMargin
|
|""".stripMargin
|
||||||
|
).render(
|
||||||
|
"coeur.tasks.amount" -> coeur.tasks.amount,
|
||||||
|
"coeur.tasks.state" -> coeur.tasks.state,
|
||||||
|
"coeur.tasks.runnerState" -> coeur.tasks.runnerState
|
||||||
|
)
|
||||||
).parseMode(ParseMode.HTML).replyToMessageId(update.message.messageId)
|
).parseMode(ParseMode.HTML).replyToMessageId(update.message.messageId)
|
||||||
.unsafeExecute
|
.unsafeExecute
|
||||||
}
|
}
|
||||||
@ -188,10 +235,14 @@ class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
coeur.externalContext >> { (reporter: MornyReport) =>
|
coeur.externalContext >> { (reporter: MornyReport) =>
|
||||||
SendMessage(
|
SendMessage(
|
||||||
update.message.chat.id,
|
update.message.chat.id,
|
||||||
|
VarText(
|
||||||
// language=html
|
// language=html
|
||||||
s"""<b>Event Statistics :</b>
|
"""<b>Event Statistics :</b>
|
||||||
|in today
|
|in today
|
||||||
|${reporter.EventStatistics.eventStatisticsHTML}""".stripMargin
|
|{event_statistics}""".stripMargin
|
||||||
|
).render(
|
||||||
|
"event_statistics" -> reporter.EventStatistics.eventStatisticsHTML
|
||||||
|
)
|
||||||
).parseMode(ParseMode.HTML).replyToMessageId(update.message.messageId)
|
).parseMode(ParseMode.HTML).replyToMessageId(update.message.messageId)
|
||||||
.unsafeExecute
|
.unsafeExecute
|
||||||
} || {
|
} || {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cc.sukazyo.cono.morny.data
|
package cc.sukazyo.cono.morny.data
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.core.{MornyAbout, MornySystem}
|
import cc.sukazyo.cono.morny.core.{MornyAbout, MornySystem}
|
||||||
|
import cc.sukazyo.cono.morny.util.var_text.VarText
|
||||||
|
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.rmi.UnknownHostException
|
import java.rmi.UnknownHostException
|
||||||
@ -39,9 +40,16 @@ object MornyInformation {
|
|||||||
def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT get
|
def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT get
|
||||||
|
|
||||||
def getMornyAboutLinksHTML: String =
|
def getMornyAboutLinksHTML: String =
|
||||||
s"""<a href='${MornyAbout MORNY_SOURCECODE_LINK}'>source code</a> | <a href='${MornyAbout MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK}'>backup</a>
|
VarText(
|
||||||
|<a href='${MornyAbout MORNY_ISSUE_TRACKER_LINK}'>反馈 / issue tracker</a>
|
// language=html
|
||||||
|<a href='${MornyAbout MORNY_USER_GUIDE_LINK}'>使用说明书 / user guide & docs</a>"""
|
"""<a href='{MORNY_SOURCECODE_LINK}'>source code</a> | <a href='{MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK}'>backup</a>
|
||||||
.stripMargin
|
|<a href='{MORNY_ISSUE_TRACKER_LINK}'>反馈 / issue tracker</a>
|
||||||
|
|<a href='{MORNY_USER_GUIDE_LINK}'>使用说明书 / user guide & docs</a>""".stripMargin
|
||||||
|
).render(
|
||||||
|
"MORNY_SOURCECODE_LINK" -> MornyAbout.MORNY_SOURCECODE_LINK,
|
||||||
|
"MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK" -> MornyAbout.MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK,
|
||||||
|
"MORNY_ISSUE_TRACKER_LINK" -> MornyAbout.MORNY_ISSUE_TRACKER_LINK,
|
||||||
|
"MORNY_USER_GUIDE_LINK" -> MornyAbout.MORNY_USER_GUIDE_LINK
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ object CommonFormat {
|
|||||||
|
|
||||||
/** human readable [[String]] that describes the millis duration.
|
/** human readable [[String]] that describes the millis duration.
|
||||||
*
|
*
|
||||||
* {{{
|
* @example {{{
|
||||||
* scala> formatDuration(10)
|
* scala> formatDuration(10)
|
||||||
* val res0: String = 10ms
|
* val res0: String = 10ms
|
||||||
*
|
*
|
||||||
|
@ -9,7 +9,10 @@ package cc.sukazyo.cono.morny.util
|
|||||||
* for example, byte `0` is binary `0000 0000`, it will be converted to
|
* for example, byte `0` is binary `0000 0000`, it will be converted to
|
||||||
* `"00"`, and the byte `-1` is binary `1111 1111` which corresponding
|
* `"00"`, and the byte `-1` is binary `1111 1111` which corresponding
|
||||||
* `"ff"`.
|
* `"ff"`.
|
||||||
* {{{
|
*
|
||||||
|
* while converting byte array, the order is: the 1st element of the array
|
||||||
|
* will be put most forward, then the following added to the tail of hex string.
|
||||||
|
* @example {{{
|
||||||
* scala> 0.toByte.toHex
|
* scala> 0.toByte.toHex
|
||||||
* val res6: String = 00
|
* val res6: String = 00
|
||||||
*
|
*
|
||||||
@ -18,11 +21,7 @@ package cc.sukazyo.cono.morny.util
|
|||||||
*
|
*
|
||||||
* scala> -1.toByte.toHex
|
* scala> -1.toByte.toHex
|
||||||
* val res7: String = ff
|
* val res7: String = ff
|
||||||
* }}}
|
|
||||||
*
|
*
|
||||||
* while converting byte array, the order is: the 1st element of the array
|
|
||||||
* will be put most forward, then the following added to the tail of hex string.
|
|
||||||
* {{{
|
|
||||||
* scala> Array[Byte](0, 1, 2, 3).toHex
|
* scala> Array[Byte](0, 1, 2, 3).toHex
|
||||||
* val res5: String = 00010203
|
* val res5: String = 00010203
|
||||||
* }}}
|
* }}}
|
||||||
|
@ -23,8 +23,7 @@ object GivenContext {
|
|||||||
|
|
||||||
/** A mutable collection that can store(provide) any typed value and read(use/consume) that value by type.
|
/** A mutable collection that can store(provide) any typed value and read(use/consume) that value by type.
|
||||||
*
|
*
|
||||||
* ## Simple Guide
|
* @example {{{
|
||||||
* {{{
|
|
||||||
* val cxt = GivenContext()
|
* val cxt = GivenContext()
|
||||||
* class BaseClass {}
|
* class BaseClass {}
|
||||||
* class MyImplementation extends BaseClass {}
|
* class MyImplementation extends BaseClass {}
|
||||||
|
@ -2,7 +2,6 @@ package cc.sukazyo.cono.morny.util
|
|||||||
|
|
||||||
object StringEnsure {
|
object StringEnsure {
|
||||||
|
|
||||||
|
|
||||||
extension (str: String) {
|
extension (str: String) {
|
||||||
|
|
||||||
/** Ensure the string have a length not smaller that the given length.
|
/** Ensure the string have a length not smaller that the given length.
|
||||||
@ -36,8 +35,8 @@ object StringEnsure {
|
|||||||
* Notice that this method have un-defined behavior when the length of the String is less than
|
* Notice that this method have un-defined behavior when the length of the String is less than
|
||||||
* the character that will be kept, so change the character length that will be kept in your need.
|
* the character that will be kept, so change the character length that will be kept in your need.
|
||||||
*
|
*
|
||||||
* Examples:
|
*
|
||||||
* {{{
|
* @example {{{
|
||||||
* scala> val someUserToken = "TOKEN_UV:V927c092FV$REFV[p':V<IE#*&@()U8eR)c"
|
* scala> val someUserToken = "TOKEN_UV:V927c092FV$REFV[p':V<IE#*&@()U8eR)c"
|
||||||
* val someUserToken: String = TOKEN_UV:V927c092FV$REFV[p':V<IE#*&@()U8eR)c
|
* val someUserToken: String = TOKEN_UV:V927c092FV$REFV[p':V<IE#*&@()U8eR)c
|
||||||
*
|
*
|
||||||
|
108
src/main/scala/cc/sukazyo/cono/morny/util/UseString.scala
Normal file
108
src/main/scala/cc/sukazyo/cono/morny/util/UseString.scala
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util
|
||||||
|
|
||||||
|
object UseString {
|
||||||
|
|
||||||
|
/** Convert a list of [[String]] to a multiline string.
|
||||||
|
*
|
||||||
|
* Each input string will be a line in the new string, and the the string
|
||||||
|
* that equals to `null` will be ignored.
|
||||||
|
*
|
||||||
|
* @example {{{
|
||||||
|
* scala> println(MString(
|
||||||
|
* "line1", // line 1
|
||||||
|
* "line2", // line 2
|
||||||
|
* "", // line 3
|
||||||
|
* null, // will be ignored
|
||||||
|
* "line4", // line 4
|
||||||
|
* ))
|
||||||
|
* line1
|
||||||
|
* line2
|
||||||
|
*
|
||||||
|
* line4
|
||||||
|
* }}}
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def MString (lines: String*): String =
|
||||||
|
lines.filterNot(_ == null).mkString("\n")
|
||||||
|
|
||||||
|
/** A simple string interpolator implementation that fixed [[scala.collection.immutable.StringOps.stripMargin]]
|
||||||
|
* will remove the interpolated string's `|` when using s"" or f"" at the
|
||||||
|
* same time.
|
||||||
|
*
|
||||||
|
* @see [[m]]
|
||||||
|
*/
|
||||||
|
implicit class MString (private val sc: StringContext) extends AnyVal:
|
||||||
|
/** A simple string interpolator implementation that fixed [[scala.collection.immutable.StringOps.stripMargin]]
|
||||||
|
* will remove the interpolated string's `|` when using s"" or f"" at
|
||||||
|
* the same time.
|
||||||
|
*
|
||||||
|
* It will process stripMargin for each raw texts, then do the s""
|
||||||
|
* interpolation. So, the interpolated string's margin character (`|`)
|
||||||
|
* will be kept.
|
||||||
|
*
|
||||||
|
* This should be useful when inserting a ascii table or ascii art when
|
||||||
|
* using string interpolator.
|
||||||
|
*
|
||||||
|
* @example {{{
|
||||||
|
* scala> val table =
|
||||||
|
* raw""" +--------+
|
||||||
|
* | | head |
|
||||||
|
* | +--------+
|
||||||
|
* | | body |
|
||||||
|
* | | next |
|
||||||
|
* | +--------+
|
||||||
|
* |""".stripMargin
|
||||||
|
*
|
||||||
|
* val table: String = " +--------+
|
||||||
|
* | head |
|
||||||
|
* +--------+
|
||||||
|
* | body |
|
||||||
|
* | next |
|
||||||
|
* +--------+
|
||||||
|
* "
|
||||||
|
*
|
||||||
|
* scala> println(table)
|
||||||
|
* +--------+
|
||||||
|
* | head |
|
||||||
|
* +--------+
|
||||||
|
* | body |
|
||||||
|
* | next |
|
||||||
|
* +--------+
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* scala> println(
|
||||||
|
* s"""Here is a table:
|
||||||
|
* |$table
|
||||||
|
* |""".stripMargin)
|
||||||
|
* Here is a table:
|
||||||
|
* +--------+
|
||||||
|
* head |
|
||||||
|
* +--------+
|
||||||
|
* body |
|
||||||
|
* next |
|
||||||
|
* +--------+
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* scala> println(
|
||||||
|
* m"""Here is a table:
|
||||||
|
* |$table
|
||||||
|
* |""")
|
||||||
|
* Here is a table:
|
||||||
|
* +--------+
|
||||||
|
* | head |
|
||||||
|
* +--------+
|
||||||
|
* | body |
|
||||||
|
* | next |
|
||||||
|
* +--------+
|
||||||
|
* }}}
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def m (args: Any*): String = {
|
||||||
|
StringContext(sc.parts.map(_.stripMargin)*)
|
||||||
|
.s(args*)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,8 @@ package cc.sukazyo.cono.morny.util.dataview
|
|||||||
|
|
||||||
object Table {
|
object Table {
|
||||||
|
|
||||||
def format (table: Seq[Seq[Any]]): String = {
|
def format (title: Seq[Any], data: Seq[Any]*): String = {
|
||||||
|
val table = data.prepended(title)
|
||||||
if (table.isEmpty) ""
|
if (table.isEmpty) ""
|
||||||
else {
|
else {
|
||||||
// Get column widths based on the maximum cell width in each column (+2 for a one character padding on each side)
|
// Get column widths based on the maximum cell width in each column (+2 for a one character padding on each side)
|
||||||
|
@ -38,8 +38,7 @@ trait Task extends Ordered[Task] {
|
|||||||
|
|
||||||
/** Returns this task's object name and the task name.
|
/** Returns this task's object name and the task name.
|
||||||
*
|
*
|
||||||
* for example:
|
* @example {{{
|
||||||
* {{{
|
|
||||||
* scala> val task = new Task {
|
* scala> val task = new Task {
|
||||||
* val name = "example-task"
|
* val name = "example-task"
|
||||||
* val scheduledTimeMillis = 0
|
* val scheduledTimeMillis = 0
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util.var_text
|
||||||
|
|
||||||
|
trait VTNode {
|
||||||
|
|
||||||
|
def render (vars: Map[String, String]): String
|
||||||
|
|
||||||
|
def serialize: String
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util.var_text
|
||||||
|
|
||||||
|
case class VTNodeLiteral (
|
||||||
|
text: String
|
||||||
|
) extends VTNode {
|
||||||
|
|
||||||
|
override def render (vars: Map[String, String]): String =
|
||||||
|
text
|
||||||
|
|
||||||
|
override def toString: String =
|
||||||
|
val prefix = "literal|"
|
||||||
|
val prefix_following = " |"
|
||||||
|
val pt = text.split('\n')
|
||||||
|
(pt.headOption.map(prefix + _).getOrElse("") ::
|
||||||
|
pt.drop(1).map(prefix_following + _).toList)
|
||||||
|
.mkString("\n")
|
||||||
|
|
||||||
|
override def serialize: String =
|
||||||
|
text
|
||||||
|
.replaceAll("/\\{", "//\\{")
|
||||||
|
.replaceAll("\\{", "/\\{")
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util.var_text
|
||||||
|
|
||||||
|
class VTNodeVar (
|
||||||
|
var_id: String
|
||||||
|
) extends VTNode {
|
||||||
|
|
||||||
|
override def render (vars: Map[String, String]): String =
|
||||||
|
vars.getOrElse(var_id, s"$${$var_id}")
|
||||||
|
|
||||||
|
override def toString: String =
|
||||||
|
s"var_def(id={$var_id})"
|
||||||
|
|
||||||
|
override def serialize: String =
|
||||||
|
s"{$var_id}"
|
||||||
|
|
||||||
|
}
|
94
src/main/scala/cc/sukazyo/cono/morny/util/var_text/Var.scala
Normal file
94
src/main/scala/cc/sukazyo/cono/morny/util/var_text/Var.scala
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util.var_text
|
||||||
|
|
||||||
|
import scala.language.implicitConversions
|
||||||
|
|
||||||
|
/** A Var is a key-value pair, where the key is a string, and the value is also a string.
|
||||||
|
*
|
||||||
|
* This class is used to represent a variable in the [[VarText]].
|
||||||
|
*
|
||||||
|
* You can just call the [[Var]] constructor to create a new Var, or use the implicit
|
||||||
|
* conversion to create a var from a tuple of ([[String]], [[String]]), or use the extension
|
||||||
|
* method [[Var.StringAsVarText.asVar]] to convert a [[String]] to a var.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*
|
||||||
|
* @param id The key of the variable, also known as var-id.
|
||||||
|
*
|
||||||
|
* The var-id have some limitation on the characters that can be used in it.
|
||||||
|
* For details, see [[Var.isLegalId]]. An illegal id will cause the constructor
|
||||||
|
* throws [[IllegalArgumentException]].
|
||||||
|
*
|
||||||
|
* @param text The text content of the variable.
|
||||||
|
*/
|
||||||
|
case class Var (
|
||||||
|
id: String,
|
||||||
|
text: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
// todo: id limitation
|
||||||
|
id.foreach { c =>
|
||||||
|
if (!Var.isLegalId(c))
|
||||||
|
throw new IllegalArgumentException(s"Character $c (${c.toInt}) is not allowed in a var id")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a new Var with the same text but different id.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def asId (id: String): Var =
|
||||||
|
Var(id, this.text)
|
||||||
|
|
||||||
|
/** Create a new Var with the same id but different text.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
Var(this.id, text)
|
||||||
|
|
||||||
|
/** Unpack this Var into a ([[String]], [[String]]) tuple.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def unpackKV: (String, String) =
|
||||||
|
(id, text)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Var {
|
||||||
|
|
||||||
|
private val ID_AVAILABLE_SYMBOLS: Set[Char] =
|
||||||
|
"_-.*/\\|:#@%&?;,~"
|
||||||
|
.toCharArray.toSet
|
||||||
|
|
||||||
|
/** Is this character is a legal var-id character.
|
||||||
|
*
|
||||||
|
* In other words, if this character is a letter, a digit, or one of the following
|
||||||
|
* symbols (`_` `-` `.` `*` `/` `\` `|` `:` `#` `@` `%` `&` `?` `;` `,` `~`), this
|
||||||
|
* character is allowed to shows in the [[Var.id]], we said this character is a
|
||||||
|
* legal var-id character.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*
|
||||||
|
* @return `true` if this character is legal, false otherwise.
|
||||||
|
*/
|
||||||
|
def isLegalId (c: Char): Boolean =
|
||||||
|
c.isLetterOrDigit || ID_AVAILABLE_SYMBOLS.contains(c)
|
||||||
|
|
||||||
|
/** Convert a tuple of ([[String]], [[String]]) to a Var.
|
||||||
|
*
|
||||||
|
* The first string of the tuple will be the [[Var.id]], and the second string
|
||||||
|
* will be the [[Var.text]]
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
implicit def StrStrTupleAsVar (tuple: (String, Any)): Var =
|
||||||
|
Var(tuple._1, tuple._2.toString)
|
||||||
|
|
||||||
|
/** @see [[asVar]] */
|
||||||
|
implicit class StringAsVarText (text: String):
|
||||||
|
/** Convert this string text to a [[Var]].
|
||||||
|
* @since 2.0.0
|
||||||
|
* @param id the var-id.
|
||||||
|
* @return a [[Var]] that the [[Var.text text]] is this string, and the [[Var.id id]]
|
||||||
|
* is the given id.
|
||||||
|
*/
|
||||||
|
def asVar (id: String): Var =
|
||||||
|
Var(id, text)
|
||||||
|
|
||||||
|
}
|
151
src/main/scala/cc/sukazyo/cono/morny/util/var_text/VarText.scala
Normal file
151
src/main/scala/cc/sukazyo/cono/morny/util/var_text/VarText.scala
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util.var_text
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.util.var_text.Var.isLegalId
|
||||||
|
|
||||||
|
/** A text/string template that may contains some named replaceable variables. It's concept may
|
||||||
|
* be similar with scala's `StringContext` or `GString` in groovy.
|
||||||
|
*
|
||||||
|
* A [[VarText]] can contains a stream of [[VTNode]]s, each nodes can be a [[VTNodeLiteral]] or
|
||||||
|
* a [[VTNodeVar]].
|
||||||
|
*
|
||||||
|
* This can be rendered to a native [[String]] by calling [[render]] method with a set of [[Var]]
|
||||||
|
* variables. The [[VTNodeVar]] will look for the given [[Var]]s to find if there's a match, and
|
||||||
|
* replace itself with the value of the [[Var]], or output a placeholder if there's no match.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
trait VarText {
|
||||||
|
|
||||||
|
val nodes: List[VTNode]
|
||||||
|
|
||||||
|
/** Render this VarText with the given `(var-key -> value)` map.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def render (vars: Map[String, String]): String =
|
||||||
|
nodes.map(_.render(vars)).mkString
|
||||||
|
|
||||||
|
/** Render this VarText with the given [[Var]]s seq.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def render (vars: Var*): String =
|
||||||
|
render(Map.from(vars.toList.map(_.unpackKV)))
|
||||||
|
|
||||||
|
/** Inspect the nodes of this VarText.
|
||||||
|
*
|
||||||
|
* Each node will be rendered to a line with the node types prefix.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
override def toString: String =
|
||||||
|
nodes.map(_.toString).mkString("\n")
|
||||||
|
|
||||||
|
/** Serialize this VarText to a template string.
|
||||||
|
*
|
||||||
|
* The return template string will be like the original template string that can be parsed
|
||||||
|
* by the [[VarText.apply(String)]] parser.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def serialize: String =
|
||||||
|
nodes.map(_.serialize).mkString
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object VarText {
|
||||||
|
|
||||||
|
def apply (_nodes: VTNode*): VarText = new VarText:
|
||||||
|
override val nodes: List[VTNode] = _nodes.toList
|
||||||
|
|
||||||
|
private val symbol_escape = '/'
|
||||||
|
private val symbol_var_start = '{'
|
||||||
|
private val symbol_var_end = '}'
|
||||||
|
|
||||||
|
/** Parse a serialized VarText template string to a [[VarText]] object.
|
||||||
|
*
|
||||||
|
* In the current standard, the `{<param>}` will be parsed to a [[VTNodeVar]], unless it
|
||||||
|
* is escaped by the escape char `/`; And the escape char can and can only escape [[VTNodeVar]]
|
||||||
|
* starter `{` or escape char `/` itself, any other chars following the escape char will
|
||||||
|
* be treated both escape char itself and the following char as a normal char; And all others
|
||||||
|
* will be parsed to [[VTNodeLiteral]].
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
def apply (template: String): VarText = {
|
||||||
|
|
||||||
|
val _nodes = collection.mutable.ListBuffer[VTNode]()
|
||||||
|
|
||||||
|
def newBuffer = StringBuilder()
|
||||||
|
var buffer: StringBuilder = newBuffer
|
||||||
|
def pushc (c: Char): Unit =
|
||||||
|
buffer += c
|
||||||
|
def buffer2literal(): Unit =
|
||||||
|
_nodes += VTNodeLiteral(buffer.toString)
|
||||||
|
buffer = newBuffer
|
||||||
|
def buffer2var(): Unit =
|
||||||
|
_nodes += VTNodeVar(buffer.toString drop 1)
|
||||||
|
buffer = newBuffer
|
||||||
|
sealed trait State
|
||||||
|
case class in_escape(it: Char) extends State
|
||||||
|
case object literal extends State
|
||||||
|
case object in_var_def extends State
|
||||||
|
var state: State = literal
|
||||||
|
|
||||||
|
template.foreach { i =>
|
||||||
|
|
||||||
|
def push(): Unit =
|
||||||
|
buffer += i
|
||||||
|
|
||||||
|
state match
|
||||||
|
case in_escape(e) =>
|
||||||
|
i match
|
||||||
|
case f if f == symbol_var_start =>
|
||||||
|
state = literal
|
||||||
|
push()
|
||||||
|
case f if f == symbol_escape =>
|
||||||
|
state = literal
|
||||||
|
push()
|
||||||
|
case _ =>
|
||||||
|
state = literal
|
||||||
|
pushc(e)
|
||||||
|
push()
|
||||||
|
case _: in_var_def.type =>
|
||||||
|
i match
|
||||||
|
case f if f == symbol_var_end =>
|
||||||
|
buffer2var()
|
||||||
|
state = literal
|
||||||
|
case _ if isLegalId(i) =>
|
||||||
|
push()
|
||||||
|
case _ =>
|
||||||
|
state = literal
|
||||||
|
push()
|
||||||
|
case _: literal.type =>
|
||||||
|
i match
|
||||||
|
case f if f == symbol_escape =>
|
||||||
|
state = in_escape(i)
|
||||||
|
case f if f == symbol_var_start =>
|
||||||
|
buffer2literal()
|
||||||
|
state = in_var_def
|
||||||
|
push()
|
||||||
|
case _ =>
|
||||||
|
push()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
state match
|
||||||
|
case in_escape(e) =>
|
||||||
|
pushc(e)
|
||||||
|
case _ =>
|
||||||
|
buffer2literal()
|
||||||
|
|
||||||
|
new VarText:
|
||||||
|
override val nodes: List[VTNode] =
|
||||||
|
_nodes.toList
|
||||||
|
.filterNot {
|
||||||
|
case VTNodeLiteral(text) if text.isEmpty =>
|
||||||
|
true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package cc.sukazyo.cono.morny.test.utils.var_text
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.test.MornyTests
|
||||||
|
import cc.sukazyo.cono.morny.util.var_text.{VarText, VTNodeLiteral, VTNodeVar}
|
||||||
|
|
||||||
|
class VarTextTest extends MornyTests {
|
||||||
|
|
||||||
|
"VarText template convertor works." in {
|
||||||
|
VarText("abcdefg {one_var}{following}it /{escaped}it and this is //double-escape-literal, with a /no-need-to-escape then {{non formatted}}xxx {missing_part")
|
||||||
|
.toString
|
||||||
|
.shouldEqual(VarText(
|
||||||
|
VTNodeLiteral("abcdefg "),
|
||||||
|
VTNodeVar("one_var"),
|
||||||
|
VTNodeVar("following"),
|
||||||
|
VTNodeLiteral("it {escaped}it and this is /double-escape-literal, with a /no-need-to-escape then "),
|
||||||
|
VTNodeLiteral("{{non formatted}}xxx "),
|
||||||
|
VTNodeLiteral("{missing_part"),
|
||||||
|
).toString)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user