%luacensor.sty \def\luacensorversionnumber{1.0.0} \ProvidesPackage{luacensor} [2022/02/18 \luacensorversionnumber\ Redact sensitive information using Lua] % !TeX program = lualatex % !TeX encoding = utf8 % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Elijah Z Granet %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % DEPENDENCIES %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{luacode} \RequirePackage{environ}% http://ctan.org/pkg/environ \RequirePackage{verbatim} % ^ for the censoring \RequirePackage{accsupp} %^for accessibility \RequirePackage{fontspec} %^for black lines %in theory, you could do %a lighter version of this %package with just asterisks %or `[TEXT-REDACTED]' %And perhaps that's better for %the environment with printing %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % FONTS %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % redacted is prettier and free to download %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % Strongly recommended %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \IfFontExistsTF{Redacted}{% \newfontface\cnsrfnt[%%%%%% %the scale is arbitrary, but kind of works Scale=1.1, %%the below declarations are to prevent warnings about shapes not being available ItalicFont=Redacted,% BoldItalicFont=Redacted,% BoldFont=Redacted,% SmallCapsFont=Redacted]{Redacted} \newcommand{\onething}{\cnsrfnt\ • } \newcommand{\twothings}{\cnsrfnt\ • • } \newcommand{\donothing}{} %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %The little spaces let justification happen %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % x chosen as an arbitrary average width %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% }{ %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % This option works perfectly %fine, it's just less pretty %%but a good fallback because % Source Sans is in TeX dists by default %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \newfontface\cnsrfnt[Scale=1.01,%To allow for separate use of source sans in text WordSpace=0,%To make it all one black line %the below declarations are to prevent warnings about shapes not being available ItalicFont={Source Sans Pro Black},BoldItalicFont={Source Sans Pro Black},BoldFont={Source Sans Pro Black},SmallCapsFont={Source Sans Pro Black}]{Source Sans Pro Black} %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % Bit of unicode magic below to make the black line effect %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand{\onething}{\cnsrfnt ▬ } \newcommand{\twothings}{\cnsrfnt ▬ ▬ } \newcommand{\donothing}{} } %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % A neat fallback for disappearing things… %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % FULL CREDIT % and FULSOME THANKS % TO TEX.SE USER % Werner for the code below %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \makeatletter \newcommand{\voidenvironment}[1]{% \expandafter\providecommand\csname env@#1@save@env\endcsname{}% \expandafter\providecommand\csname env@#1@process\endcsname{}% \@ifundefined{#1}{}{\RenewEnviron{#1}{}}% } \makeatother \newcommand{\hddn}[1]{% \ifcnsr{}\else% #1\fi} \newenvironment*{hidden}{\begin{@empty} }{\end{@empty}} \voidenvironment{hidden} %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % the CENSOR COMMAND %%%%%%%%%%%%%%%%%%%%%%%%%%% \newif\ifcnsr\cnsrfalse \newcommand{\cnsr}[1]{% \ifcnsr{% \voidenvironment{equation*} \voidenvironment{equation} \voidenvironment{table} \voidenvironment{table*} \voidenvironment{tabular} \voidenvironment{tabular*} \voidenvironment{} %%%%%%%%%%%%%%%%%%%%%%%%%%% % I don't know how many % people use TEX native accent commands % in LuaTEX given that using Unicode is more %people's style. But just in case, because these can lead to stray accent marks floating above censored letters. %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \renewcommand{\`}[1]{} \renewcommand{\'}[1]{} \renewcommand{\^}[1]{} \renewcommand{\"}[1]{} \renewcommand{\H}[1]{} \renewcommand{\~}[1]{} \renewcommand{\c}[1]{} \renewcommand{\k}[1]{} \renewcommand{\l}[1]{} \renewcommand{\=}[1]{} \renewcommand{\b}[1]{} \renewcommand{\.}[1]{} \renewcommand{\d}[1]{} \renewcommand{\r}[1]{} \renewcommand{\u}[1]{} \renewcommand{\v}[1]{} \renewcommand{\t}[1]{} \renewcommand{\o}[1]{} \renewcommand{\i}[1]{} %%%%%%%%%%%%%%%%%%%%%%%%%%% %TEX primitives can break the %code because they don't have the good manners %to put their arguments in brackets %No offence, of course, to the %honoured Prof Knuth, who had %magnificent genius reasons %for coding things that way %it's just that i'm an idiot %and therefore need things simple %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \renewcommand{\hskip}[1]{} \renewcommand{\vskip}[1]{} \renewcommand{\raise}[1]{} \renewcommand{\lower}[1]{} \renewcommand{\kern}[1]{} % here we have the accsupp magic % this operates by replacing the 'x's % or unicode black squares as the case % may be with an alt text % this serves a dual purpose of both making %pdftotext not break with huge strings of meaningless characters %but more importantly % it means screen readers don't subject %. their users to the meaningless reading out of unicode black squares 50 times in a row! %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \BeginAccSupp{method=plain,ActualText={TEXT REDACTED}}% \rndstring{#1} \EndAccSupp{}% } \else% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % if the conditional is off % the command does absolutely nothing %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% #1% \fi} %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % The LUA MAGIC PART %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{luacode} --fulsome thanks to TeX.SE users Henri Menke and David Carlisle, without whom none of this would be possible local function rndstring() local toks = token.scan_toks(s) local on = true for n, t in ipairs(toks) do if t.csname == "begin" or t.csname == "end" then on = false -- The below is necessary as TeX primitives can break the code otherwise because they do not use brackets end if not(on) and t.cmdname == "right_brace" then on = true -- This prevents needless errors about gibberish up commands end if on and t.csname == "&" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "%" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "$" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "#" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "_" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "{" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "}" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "~" then local letter = token.create'donothing' toks[n] = letter elseif on and t.csname == "^" then local letter = token.create'donothing' toks[n] = letter elseif on and t.cmdname == "letter" then -- The below is the randomness part of this, which I admit is fairly arbitrary, but will more often artificially shorten strings than lengthen them, as testing found if lengthening was too frequent, it led to really unsightly long strings. local f = math.random (1,20) if f == 1 then local letter = token.create'donothing' toks[n] = letter elseif f == 2 then local letter = token.create'donothing' toks[n] = letter elseif f == 3 then local letter = token.create'donothing' toks[n] = letter elseif f == 4 then local letter = token.create'twothings' toks[n] = letter elseif f == 5 then local letter = token.create'donothing' toks[n] = letter else local letter = token.create'onething' toks[n] = letter end elseif on and t.cmdname == "spacer" then local f = math.random (1,20) if f == 2 then local letter = token.create'donothing' toks[n] = letter elseif f == 3 then local letter = token.create'donothing' toks[n] = letter elseif f == 4 then local letter = token.create'donothing' toks[n] = letter elseif f == 5 then local letter = token.create'twothings' toks[n] = letter elseif f == 6 then local letter = token.create'donothing' toks[n] = letter elseif f == 7 then local letter = token.create'donothing' toks[n] = letter else local letter = token.create'onething' toks[n] = letter end elseif on and t.cmdname == "other_char" then local f = math.random (1,20) if f == 2 then local letter = token.create'donothing' toks[n] = letter elseif f == 3 then local letter = token.create'donothing' toks[n] = letter elseif f == 4 then local letter = token.create'donothing' toks[n] = letter elseif f == 5 then local letter = token.create'twothings' toks[n] = letter elseif f == 6 then local letter = token.create'donothing' toks[n] = letter elseif f == 7 then local letter = token.create'donothing' toks[n] = letter else local letter = token.create'onething' toks[n] = letter end end end --Drop the token in and move on token.put_next(toks) end local lft = lua.get_functions_table() --make a global command lft[#lft + 1] = rndstring token.set_lua("rndstring", #lft, "global") \end{luacode}