% KKluaverb.sty
% Copyright (c) 2026 Kosei Kawaguchi
% Released under the MIT License (see LICENSE.md for details)
% -----
% This file is based on 'bxrawstr.lua' by Takayuki YATO (aka. "ZR").
% Copyright (c) 2018 Takayuki YATO
% -----

% Commands for usr: KKv-
% Commands for system: KKlv-

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{KKluaverb}[2026/06/11 v2.2.0]

%%% package
\RequirePackage{luatexbase, luacode}
\RequirePackage{pgfkeys}
\RequirePackage[dvipsnames, svgnames, x11names]{xcolor}
\directlua{require("KKluaverb")}
%%%

%%% kvop
\pgfkeys{
  /kklv/.is family, /kklv/.cd,
  font/.store in  = \kklv@set@font,
  color/.store in = \kklv@set@color,
  enabled/.code = {%
    \directlua{KKLuaVerb.enabled = #1}%
  },
}
\newcommand{\KKvOpChange}[1]{\pgfkeys{/kklv/.cd, #1}}
\KKvOpChange{font=\ttfamily, color=black, enabled=true}
\newcommand{\KKvScanOn}{\KKvOpChange{enabled=true}}
\newcommand{\KKvScanOff}{\KKvOpChange{enabled=false}}
%%%

%%% def delims
% delimiters
\newtoks\kklv@delims
\newcommand{\KKvSetDelims}[2]{\kklv@delims{{#1}{#2}}}
\KKvSetDelims{|}{|}

% starter command
\newcommand{\KKverb}{\relax} 
\newcommand{\KKcodeS}{\relax} 
\newcommand{\KKcodeE}{\relax} 
%%%

%%% linebreak op
  % If style op is 0, the line break appears as nothing.  
  % If style is 1, the line break appears as real linebreak.
  % If style is 2, the line break appears as real linebreak and line-number-index.
\newcount\kklv@linenum@start
\newtoks\kklv@linebreak
\newcommand{\kklv@error@invalidlb}[1]{%
  \PackageError{KKluaverb}{%
    Invalid value '#1' for LineBreak%
  }{%
    LineBreak must be 0 (none), 1 (paragraph), or 2 (with line numbers).%
  }%
}
\pgfkeys{
  /kklvlinenumber/.is family, /kklvlinenumber/.cd,
  font/.store in  = \kklvlinenumber@set@font,
  color/.store in = \kklvlinenumber@set@color,
  size/.store in = \kklvlinenumber@set@size,
  start/.code = {\kklv@linenum@start=#1},
  style/.code = {%
    \ifnum#1<0 \kklv@error@invalidlb{#1}\else
    \ifnum#1>2 \kklv@error@invalidlb{#1}\else
      \kklv@linebreak={#1}%
    \fi\fi
  }
}
\newcommand{\KKvLNChange}[1]{\pgfkeys{/kklvlinenumber/.cd, #1}}
\KKvLNChange{font=\ttfamily, color=black!80, size=\small, start=1, style=0}

\newcommand{\KKlvLineNumber}[1]{{%
  % Upper limit of the line number is 6 digits.
  % This is an internal macro.
  \kklvlinenumber@set@font%
  \color{\kklvlinenumber@set@color}%
  \kklvlinenumber@set@size%
  \llap{%
    \makebox[3em][r]{#1}\phantom{l}%
  }\inhibitglue%
}}
%%%

%%% replacer
\def\kklv@lua@str#1{"\luatexluaescapestring{#1}"}
\newcommand{\KKvSetMap}[2]{%
  \directlua{
    KKLuaVerb.add_replacement(\kklv@lua@str{#1}, \kklv@lua@str{#2})
  }%
}
\newcommand{\KKvSpaceForce}{%
  \directlua{
    KKLuaVerb.add_replacement(" ", string.char(194, 160))
  }%
}

% Escape character for a literal \KKcodeE
% inside the \KKcodeS/E environment.
\newcommand{\KKvSetCodeEscape}[1]{%
  \directlua{
    KKLuaVerb.code_escape_char = \kklv@lua@str{#1}
  }%
}
%%%

%%% color change
\newcommand{\KKvUsePreset}[1]{%
  \directlua{KKLuaVerb.load_preset("#1")}%
}
%%%

%%% main
% When the scanned chunk includes
% a \KKlvStart*<text>\KKlvEnd* part,
% it is transformed as follows:
\long\def\KKlvStart*#1\KKlvEnd*{%
  \ifx\protect\relax%
    \begingroup%
      \kklv@set@font%
      \color{\kklv@set@color}%
      \directlua{
        KKLuaVerb.decode([[#1]])
      }%
    \endgroup%
  \else% 
    % in .toc
    \noexpand\KKlvStart*#1\noexpand\KKlvEnd*%
  \fi%
}

% Run KKLuaVerb.scanner on each line.
\directlua{
  luatexbase.add_to_callback(
    "process_input_buffer",
    KKLuaVerb.scanner_for_verb, 
    "kkluaverb_scanner_for_verb"
  )
}
%%%
\endinput