% file: kskorsym.sty
%
% written by Nova de Hi (2024-2025)
%
%
\ProvidesExplPackage{kskorsymb}
	{2025/06/04}
	{v0.8.7}
	{shorthands for korean punctuations}

\RequirePackage{l3keys2e}
\RequirePackage{etoolbox}

\newif\ifparentypemore\parentypemorefalse
\newif\ifparentypetroublesome\parentypetroublesomefalse

\bool_new:N \opt_wavedashnormal_bool

\keys_define:nn { kskorsym }
{
	localenv	.bool_set:N = \opt_localenv_bool,
	minimal		.bool_set:N = \opt_minimal_bool,
	minimalplus	.bool_set:N = \opt_minimalplus_bool,
	wavedash	.choice:,
		wavedash / 223C	.code:n = { \bool_set_true:N  \opt_wavedashnormal_bool },
		wavedash / 301C	.code:n = { \bool_set_false:N \opt_wavedashnormal_bool },
		wavedash / FF5E	.code:n = { \bool_set_false:N \opt_wavedashnormal_bool },
	parentype	.choice:,
		parentype / normal	.code:n = { \parentypetroublesomefalse \parentypemorefalse },
		parentype / troublesome	.code:n = { \parentypetroublesometrue \parentypemorefalse },
		parentype / moreparen	.code:n = { \parentypetroublesomefalse \parentypemoretrue },
		parentype / moreparens	.code:n = { \parentypetroublesomefalse \parentypemoretrue }
}

\keys_set:nn { kskorsym }
{
	localenv = false,
	minimal  = false,
	minimalplus = false,
	parentype = normal,
	wavedash = 223C
}

\ProcessKeysOptions { kskorsym }

\ifparentypetroublesome
	\bool_set_true:N \opt_minimalplus_bool
\fi
\ifparentypemore
	\bool_set_true:N \opt_minimalplus_bool
\fi

\RequirePackage{iftex}
\RequirePackage{relsize}
\sys_if_engine_pdftex:T {
	\AtEndPreamble{
		\@ifpackageloaded{adjustbox}{}{\RequirePackage{adjustbox}}
	}
}

\ifx\ifXeTeX\ifLuaTeX
	\providecommand*\_UnBatang_font {}
	\providecommand*\_HCRBatang_font {}
\else
\AtEndPreamble{
    \NewDocumentCommand \_UnBatang_font {} {
    	\fontspec{UnBatang.ttf}[BoldFont=UnBatangBold.ttf]
		\cs_if_exist:NT \hangulfontspec {
        	\hangulfontspec{UnBatang.ttf}[BoldFont=UnBatangBold.ttf]
		}
    }
    \NewDocumentCommand \_HCRBatang_font {} {
    	\fontspec{HANBatang-LVT.ttf}[BoldFont=HANBatangB-LVT.ttf]
		\cs_if_exist:NT \hangulfontspec {
	    	\hangulfontspec{HANBatang-LVT.ttf}[BoldFont=HANBatangB-LVT.ttf]
		}
    }
}
\fi


%%% \symbolU
\NewDocumentCommand \symbolU { m }
{
	\int_set:Nn \l_tmpa_int { \int_from_hex:n { #1 } }
	\exp_args:Nf \symbol { \int_use:N \l_tmpa_int }
}

%%% starts package codes
\let\ORG_RQRQ"

\prop_new:N \g_UserSymb_prop 
\bool_new:N \korsym_parenstatus_bool
\bool_new:N \korsym_largequotestatus_bool
\bool_new:N \korsym_smallquotestatus_bool

\bool_if:NTF \opt_minimal_bool
{
    \prop_const_from_keyval:Nn \g_KorSymb_prop
    {
    	.	=  ·, 
	}
}
{
	\bool_if:NTF \opt_minimalplus_bool
	{
	    \prop_const_from_keyval:Nn \g_KorSymb_prop
	    {
	    	.	=  ·, 
	    	\~	= {\_UnBatang_font ∼},
	    	-	= {\_HCRBatang_font …},
	    	:	= ：,
	    	'	= \mysmallQuoteSymbol,
	    	"	= \myQuoteSymbol,
			\' 	= \mysmallQuoteSymbolDeep,
			\"	= \myQuoteSymbolDeep,
			/	= \myExtraParenMark,
		}
	}
	{
	    \prop_const_from_keyval:Nn \g_KorSymb_prop
	    {
	    	.	=  ·, 
	    	\.	=  。,
	    	\,	=  、,
	    	<	=  〈,
	    	>	=  〉,
	    	(	=  《,
	    	)	=  》,
	    	[	=  「,
	    	]	=  」,
	    	\{	=  『,
	    	\}	=  』,
	%%%    	-	= \myEllipsisSymbol,
			- 	= {\_HCRBatang_font …},
	    	:	= ：,
	    	'	= \mysmallQuoteSymbol,
	    	"	= \myQuoteSymbol,
			\' 	= \mysmallQuoteSymbolDeep,
			\"	= \myQuoteSymbolDeep,
	    	/	= \myExtraParenMark,
	    }
	}
}

\bool_if:NTF \opt_wavedashnormal_bool
{
	\prop_gput_from_keyval:Nn \g_KorSymb_prop
	{
	    	\~	= {\_UnBatang_font ∼},   %% 223C
	}
}
{
	\prop_gput_from_keyval:Nn \g_KorSymb_prop
	{
	    	\~  = 〜,  %% 301C
	}

}

\char_set_catcode_active:N \"

\bool_if:NF \opt_localenv_bool
{
	\AtBeginDocument {
		\catcode`\"=\active
	}
}

%%% \protected? 
\def"{
	\mode_if_math:F
	{
    	\peek_catcode:NTF \c_space_token
    	{ \texorpdfstring { \ORG_RQRQ } {} }
    	{ \__shorthand_kor_punctuations }
	}
}

\NewDocumentCommand \__shorthand_kor_punctuations { m }
{
	\group_begin:

	\prop_if_in:NnTF \g_KorSymb_prop { #1 }
	{
		\prop_get:NnN \g_KorSymb_prop { #1 } \l_tmpa_tl
		\tl_use:N \l_tmpa_tl
	}
	{
		\prop_if_in:NnTF \g_UserSymb_prop { #1 }
		{
			\prop_get:NnN \g_UserSymb_prop { #1 } \l_tmpa_tl 
			\tl_use:N \l_tmpa_tl
		}
		{
			\texorpdfstring { \ORG_RQRQ #1 } { #1 }
		}
	}
	
	\group_end:
}

\NewDocumentCommand \makerqother  {} { \catcode`\"=12 }
\NewDocumentCommand \makerqactive {} { \catcode`\"=\active }
%%% alias for backward compatibility
\let\escaperqcat\makerqother
\let\restorerqcat\makerqactive
%%% [localenv]
\let\startkorsymbols\makerqactive

%\NewDocumentCommand \myEllipsisSymbol {}
%{
%	\__ellipsis_double_dash:nn
%}
%
%\cs_new:Npn \__ellipsis_double_dash:nn #1 #2
%{
%	#1 {\_HCRBatang_font …}
%	\str_if_eq:nnTF { #2 } { - }
%	{
%		\nobreak {\_HCRBatang_font …}
%	}
%	{
%		\relax #2
%	}
%}

\NewDocumentCommand \addUserSymbol { m }
{
	\prop_gput_from_keyval:Nn \g_UserSymb_prop { #1 }
}

\int_new:N \l_tmpz_tl

\NewDocumentCommand \addUserUnicodeSymbol { m }
{
	\clist_set:Nn \l_tmpa_clist { #1 }
	\clist_map_inline:Nn \l_tmpa_clist 
	{
    	\_korsymb_split_byequal:w ##1 \q_stop
    	\int_set:Nn \l_tmpa_int { \exp_args:No \int_from_hex:n { \l_tmpb_tl } }
    	\tl_set:Nx \l_tmpz_tl { \l_tmpa_tl = \symbol{ \int_use:N \l_tmpa_int } }
    	\exp_args:NNx \prop_gput_from_keyval:Nn \g_UserSymb_prop { \l_tmpz_tl }
	}
}

\cs_set:Npn \_korsymb_split_byequal:w #1 = #2 \q_stop
{
	\tl_set:Nn \l_tmpa_tl { #1 }
	\tl_set:Nn \l_tmpb_tl { #2 }
}

\NewDocumentCommand \addDefaultSymbol { m }
{
	\prop_gput_from_keyval:Nn \g_KorSymb_prop { #1 }
}


\NewDocumentCommand \clearUserSymbol {}
{
	\prop_gclear:N \g_UserSymb_prop
}

\bool_if:nT
{
	( ! \opt_minimal_bool ) && ( ! \opt_minimalplus_bool )
}
{ 
	\addUserSymbol{
			*	=  ※,
			{=}	=  ☞,
			?	=  ◎,
			X	= {\_UnBatang_font ×},
	}
}

\NewDocumentCommand \removeDefaultSymbol { m }   %% not indended to use practically
{
	\clist_set:Nn \l_tmpa_clist { #1 }
	\clist_map_inline:Nn \l_tmpa_clist
	{
		\prop_gremove:Nn \g_KorSymb_prop { ##1 }
	}
}

\NewDocumentCommand \removeUserSymbol { m }
{
	\clist_set:Nn \l_tmpa_clist { #1 }
	\clist_map_inline:Nn \l_tmpa_clist
	{
		\prop_gremove:Nn \g_UserSymb_prop { ##1 }
	}
}


%%%% 0.6
\NewDocumentCommand \myQuoteSymbol {}
{
	\bool_if:NTF \korsym_largequotestatus_bool
	{
		”
		\bool_gset_false:N \korsym_largequotestatus_bool
	}
	{
		“
		\bool_gset_true:N \korsym_largequotestatus_bool
	}
}

\NewDocumentCommand \myQuoteSymbolDeep {}
{
	\bool_if:NTF \l_tmpa_bool
	{
		”
		\bool_gset_false:N \l_tmpa_bool
	}
	{
		“
		\bool_gset_true:N \l_tmpa_bool
	}
}

\NewDocumentCommand \mysmallQuoteSymbol {}
{
	\bool_if:NTF \korsym_smallquotestatus_bool
	{
		’\hskip\korsym_aftersmallquote_skip\relax
		\bool_gset_false:N \korsym_smallquotestatus_bool
	}
	{
		\hskip\korsym_beforesmallquote_skip\relax ‘
		\bool_gset_true:N \korsym_smallquotestatus_bool
	}
}

\NewDocumentCommand \mysmallQuoteSymbolDeep {}
{
	\bool_if:NTF \l_tmpb_bool
	{
		’\hskip\korsym_aftersmallquote_skip\relax
		\bool_gset_false:N \l_tmpb_bool
	}
	{
		\hskip\korsym_beforesmallquote_skip\relax ‘
		\bool_gset_true:N \l_tmpb_bool
	}
}

\skip_new:N \korsym_aftersmallquote_skip
\skip_new:N \korsym_beforesmallquote_skip

\NewDocumentCommand \hskipaftersmallquote { m }
{
	\skip_set:Nn \korsym_aftersmallquote_skip { #1 }
}

\NewDocumentCommand \hskipbeforesmallquote { m }
{
	\skip_set:Nn \korsym_beforesmallquote_skip { #1 }
}


\NewDocumentCommand \defineextraparenmark { m }
{
	\tl_set:Nn \l_tmpa_tl { #1 }
	\tl_gset:Nx \extraParenMarkOpen { \tl_item:Nn \l_tmpa_tl { 1 } }
	\tl_gset:Nx \extraParenMarkClose { \tl_item:Nn \l_tmpa_tl { 2 } }
}

\defineextraparenmark{{〔}{〕}}

\NewDocumentCommand \myExtraParenMark {}
{
	\bool_if:NTF \korsym_parenstatus_bool
	{
		\extraParenMarkClose
		\bool_gset_false:N \korsym_parenstatus_bool
	}
	{
		\extraParenMarkOpen
		\bool_gset_true:N \korsym_parenstatus_bool
	}	
}

%%% verbatim
\patchcmd\@verbatim{\dospecials}{\dospecials\catcode`\"=12}{}{}
\patchcmd\verb{\dospecials}{\dospecials\catcode`\"=12}{}{}
%\AddToHook{env/verbatim/begin}{\catcode`\"=12}

\AtEndPreamble{
	\@ifpackageloaded{hyperref}{}{
		\providecommand*\texorpdfstring[2]{#1}
	}
}

%%%% \XBrule is a provided command by oblivoir, and the
%%%% \expldash uses it. We redefine it here.
%%%% --- drop 2025/04/04
%\ifx\XBrule\undefined\else
%\renewcommand*\XBrule{
%	\sbox\togetheightoffont{!}
%	\setlength\htoffnt{\ht\togetheightoffont}
%	\raise.43\htoffnt\hbox{\rule{1.25em}{.04em}}
%}
%\fi

%%% kssuperscript and ksparensmall

\dim_new:N \hnglscriptraisedim
\dim_set:Nn \hnglscriptraisedim {.367em}
\def\hnglscriptfontsize{.62}
\def\hnglsmallerfactor{0.833}

\NewDocumentCommand \respect_my_superscript { r<> }
{
	\tl_gset:Nn \g_tmpa_tl {#1}
	
	\sys_if_engine_pdftex:TF
	{
		\print_hnglsuperscript_result_pdftex:N \g_tmpa_tl
	}
	{
		\print_hnglsuperscript_result:N \g_tmpa_tl
	}
}

\NewDocumentCommand \kssuperscript { m }
{
	\tl_gset:Nn \g_tmpa_tl {#1}
	\sys_if_engine_pdftex:TF
	{
		\print_hnglsuperscript_result_bare_pdftex:N \g_tmpa_tl
	}
	{
		\print_hnglsuperscript_result_bare:N \g_tmpa_tl
	}
}

\NewDocumentCommand \respect_my_smaller { r() }
{
	\tl_gset:Nn \g_tmpa_tl { #1 }
	\print_hnglsmaller_result:N \g_tmpa_tl
}

\tl_new:N \g_ksparensmallparenopen_tl
\tl_new:N \g_ksparensmallparenclose_tl

\cs_new:Npn \_resolve_parensmall_paren:w #1 #2 \q_stop:
{
	\tl_set:Nn \g_ksparensmallparenopen_tl { #1 }
	\tl_set:Nn \g_ksparensmallparenclose_tl { #2 }
}

\NewDocumentCommand \ksparensmall { O{{（}{）}} m }
{
	\let\@@@smallparenopen\g_ksparensmallparenopen_tl
	\let\@@@smallparenclose\g_ksparensmallparenclose_tl
	\_resolve_parensmall_paren:w #1 \q_stop:
	\tl_gset:Nn \g_tmpa_tl { #2 }
	\print_hnglsmaller_result_bare:N \g_tmpa_tl
	\let\g_ksparensmallparenopen_tl\@@@smallparenopen
	\let\g_ksparensmallparenclose_tl\@@@smallparenclose
}

\NewDocumentCommand \defineparensmallparen { m }
{
	\_resolve_parensmall_paren:w #1 \q_stop:
}

%%% default
\defineparensmallparen{{（}{）}}

\cs_new:Npn \print_hnglsuperscript_result:N #1
{
	\regex_replace_all:nnN { \c{group_begin:} } {} #1
	\regex_replace_all:nnN { \c{group_end:} } {} #1
%	\exp_args:Nno \regex_match:nnTF { [가-힣一-鿿豈-龜ぁ-ー] } { #1 } {
	\relax \hnglsuperscript { #1 } \endgroup
%	} { \relax \exp_args:Nx \textsuperscript { #1 } \endgroup }
}

\cs_new:Npn \print_hnglsuperscript_result_bare:N #1
{
	\regex_replace_all:nnN { \c{group_begin:} } {} #1
	\regex_replace_all:nnN { \c{group_end:} } {} #1
%	\exp_args:Nno \regex_match:nnTF { [가-힣一-鿿豈-龜ぁ-ー] } { #1 } {
	\relax \hnglsuperscript { #1 } 
%	} { \relax \exp_args:Nx \textsuperscript { #1 } \endgroup }
}

\cs_new:Npn \print_hnglsuperscript_result_pdftex:N #1
{
	\regex_replace_all:nnN { \c{group_begin:} } {} #1
	\regex_replace_all:nnN { \c{group_end:} } {} #1
	\relax \pdftex_hnglsuperscript { #1 } \endgroup
}

\cs_new:Npn \print_hnglsuperscript_result_bare_pdftex:N #1
{
	\regex_replace_all:nnN { \c{group_begin:} } {} #1
	\regex_replace_all:nnN { \c{group_end:} } {} #1
%	\exp_args:Nno \regex_match:nnTF { [가-힣一-鿿豈-龜ぁ-ー] } { #1 } {
	\relax \pdftex_hnglsuperscript { #1 } 
%	} { \relax \exp_args:Nx \textsuperscript { #1 } \endgroup }
}

\NewDocumentCommand \pdftex_hnglsuperscript { +m }
{
	\begingroup
	\regex_split:nnN { \s } { #1 } \l_tmpa_seq
	\seq_map_indexed_inline:Nn \l_tmpa_seq
	{
		\tl_set:Nn \l_tmpa_tl { ##2 }
%		\regex_match:nVTF { [가-힣] } \l_tmpa_tl
%		{
%			\tl_map_function:NN \__eachhangulprint__:n
%		}
%		{
			\adjustbox{raise=\hnglscriptraisedim}{\relscale{\hnglscriptfontsize}{\l_tmpa_tl}}
%		}
		\int_compare:nF { ##1 == \seq_count:N \l_tmpa_seq }
		{
			\relscale{\hnglscriptfontsize}{\space}
		}
	}
	\endgroup
}


\NewDocumentCommand \hnglsuperscript { m }
{
	\group_begin:
	\sys_if_engine_xetex:TF
	{
		\@ifpackageloaded{xetexko}{
        	\hangulmarks
        	\addhanjafontfeature{CharRaise=.9\hnglscriptraisedim,Scale=\hnglscriptfontsize}
        	\addhangulfontfeature{CharRaise=\hnglscriptraisedim,Scale=\hnglscriptfontsize}
		}{}
	}
	{
		\sys_if_engine_luatex:T
		{
			\@ifpackageloaded{luatexko}{
            	\addfontfeatures{CharRaise=\dim_use:N \hnglscriptraisedim,Scale=\hnglscriptfontsize,CompressPunctuations}
            	\addhangulfontfeatures{CharRaise=\dim_use:N \hnglscriptraisedim,Scale=\hnglscriptfontsize,CompressPunctuations}
            	\addhanjafontfeatures{CharRaise=\dim_use:N \hnglscriptraisedim,Scale=\hnglscriptfontsize,CompressPunctuations}
				\hangulpunctuations=0
			}{}
		}
	}		
	#1
	\group_end:
	\sys_if_engine_luatex:T { \@ifpackageloaded{luatexko}{ \hangulpunctuations=1 }{} }
}

\cs_new:Npn \print_hnglsmaller_result:N #1
{
	\regex_replace_all:nnN { \c{group_begin:} } {} #1
	\regex_replace_all:nnN { \c{group_end:} } {} #1
%	\exp_args:No \tl_to_str:n { #1 }
	\relax \relscale{\hnglsmallerfactor} \g_ksparensmallparenopen_tl #1 \g_ksparensmallparenclose_tl \endgroup \relax
}

\cs_new:Npn \print_hnglsmaller_result_bare:N #1
{
	\regex_replace_all:nnN { \c{group_begin:} } {} #1
	\regex_replace_all:nnN { \c{group_end:} } {} #1
%	\exp_args:No \tl_to_str:n { #1 }
	{ \relscale{\hnglsmallerfactor} \g_ksparensmallparenopen_tl #1 \g_ksparensmallparenclose_tl }
}

\NewDocumentCommand \respect_my_dotemph { +r!! }
{
	\tl_set:Nn \l_tmpa_tl { #1 }
	\regex_replace_all:nnN { \c{group_begin:} } {} \l_tmpa_tl
	\regex_replace_all:nnN { \c{group_end:} } {} \l_tmpa_tl
%	\exp_args:No \tl_to_str:n { #1 }
	\relax \my_dotemph: {\my_em_cmd: \l_tmpa_tl} \endgroup \relax
}

\NewDocumentCommand \respectdotemph { m }
{
	\relax \my_dotemph: {\my_em_cmd: #1 }
}

\keys_define:nn { dotemphmod }
{
	dot	.tl_set:N = \dotemphmod_dot_tl,
	em	.tl_set:N = \dotemphmod_em_tl,
}

\keys_set:nn { dotemphmod }
{
	dot = \dotemph,
	em  = \em
}

\cs_new:Nn \_activate_dotemphmod:
{
	\exp_last_unbraced:NNo \cs_set_eq:NN \my_dotemph: \dotemphmod_dot_tl
	\exp_last_unbraced:NNo \cs_set_eq:NN \my_em_cmd: \dotemphmod_em_tl	
}

%%% initialization
\_activate_dotemphmod:

\NewDocumentCommand \ksdotemphmod { m }
{
	\keys_set:nn { dotemphmod } { #1 }
	\_activate_dotemphmod:
}

%%% parentypes 
%%% parentype = troublesome or moreparen

\ifx\ifparentypetroublesome\ifparentypemore\else  

\addUserSymbol{<=\respect_my_superscript<,(=\respect_my_smaller(,!=\respect_my_dotemph!}
\fi

%%% parentype = troublesome : start
\ifparentypetroublesome

\prop_set_from_keyval:Nn \g_KorDOUBLESymb_prop
{
    	<	=  〈,
    	>	=  〉,
    	(	=  《,
    	)	=  》,
    	[	=  「,
    	]	=  」,
    	\{	=  『,
    	\}	=  』,
}

\cs_new:Npn \__shorthand_DOUBLE_kor_punctuations:nn #1 #2
{
	#1 \scan_stop:
	
	\group_begin:

	\prop_if_in:NnTF \g_KorDOUBLESymb_prop { #2 }
	{
		\prop_get:NnN \g_KorDOUBLESymb_prop { #2 } \l_tmpa_tl
		\tl_use:N \l_tmpa_tl
	}
	{
		#2
	}
	
	\group_end:
}

\addUserSymbol{*=\__shorthand_DOUBLE_kor_punctuations:nn}

\fi

%%% parentype = troublesome : end

%%% parentype = moreparens : start 

\ifparentypemore

\NewDocumentCommand \kskorShorthandBNM { +r[] }
{
	『#1』
}

\NewDocumentCommand \kskorShorthandSNM { +r[] }
{
	「#1」
}

\NewDocumentCommand \kskorShorthandCNM { +r[] }
{
	〈#1〉
}

\NewDocumentCommand \kskorShorthandCCNM { +r[] }
{
	《#1》
}

\NewDocumentCommand \kskorShorthandsogwalho { +r[] }
{
	（#1）
}

\NewDocumentCommand \kskorShorthandjunggwalho { +r[] }
{
	｛#1｝
}

\NewDocumentCommand \kskorShorthanddaegwalho { +r[] }
{
	［#1］
}

\NewDocumentCommand \kskorShorthandgakgwalho { +r[] }
{
	〔#1〕
}

\NewDocumentCommand \kskorShorthandkkeundaegwalho { +r[] }
{
	【#1】
}

\NewDocumentCommand \kskorShorthandkkeunttaompyo { +r[] }
{
	“#1”
}

\NewDocumentCommand \kskorShorthandjageunttaompyo { +r[] }
{
	‘#1’
}

\def \defaultKSParenName {SNM}

\cs_new:Npn \__shorthand_bnms_kor_punctuations:nn #1 #2
{
	#1 \scan_stop:
	
	\group_begin:
	
	\str_case:nnTF { #2 }
	{
%		{ n } { \kskorShorthandSNM }
%		{ N } { \kskorShorthandBNM }
%		{ c } { \kskorShorthandCNM }
%		{ C } { \kskorShorthandCCNM }
		{ ' } { \kskorShorthandSNM }
		{ " } { \kskorShorthandBNM }
		{ ; } { \kskorShorthandCNM }
		{ : } { \kskorShorthandCCNM }
		{ 0 } { \kskorShorthandsogwalho }
		{ 1 } { \kskorShorthandjunggwalho }
		{ 2 } { \kskorShorthanddaegwalho }
		{ 3 } { \kskorShorthandgakgwalho }
		{ 4 } { \kskorShorthandkkeundaegwalho }
		{ q } { \kskorShorthandjageunttaompyo }
		{ Q } { \kskorShorthandkkeunttaompyo }
	}
	{
		[ 
	}
	{
		\use:c { kskorShorthand \defaultKSParenName } [ #2
	}
	
	\group_end:
}

\addUserSymbol{[=\__shorthand_bnms_kor_punctuations:nn}

\fi
%%% parentype: moreparens --- end.

\endinput
