Filesystem Path Display in LaTeX – How to Display Part of the Path

currfilefilesystem-access

I use the currfile package to help keep track of the source of my latex files. I use Linux, and the full path of the file looks like this:

/home/username/(various directories)/project-one/proposal/FIRST.tex

If I use

\usepackage[abs]{currfile}
\currfilename

then it displays the full path. If I use

\usepackage{currfile}

then I only see FIRST.tex.

Question: Is there a way to display

project-one/proposal/FIRST.tex

(it does not matter if there is a backslash in front of the path).

In case this matters, I use TeXlive in Linux.

Best Answer

In the following code, once \defineKnownPrefixes has been called:

  • \currFileAbsPathWithoutPrefix expands in one step to the desired thing (string'ified path with one instance of the prefix removed if possible, if it is among those specified with \defineKnownPrefixes);

  • \stripPrefixFrom{⟨balanced text⟩} recursively expands to same thing, but using ⟨balanced text⟩ as input instead of the “contents” of \currfileabspath.

\stripPrefixFrom is restricted-expandable: it can be used inside \edef, \xdef, \write, \typeout, \message, etc.

\defineKnownPrefixes assigns the list of prefixes \l_uflow_prefixes_seq and the resulting \currFileAbsPathWithoutPrefix locally (in other words, it respects TeX's grouping rules).

As reminded below, the \currFileAbsPathWithoutPrefix setting requires the document to be compiled with the -recorder option of the TeX engine (see the documentation of currfile).

\documentclass{article}
% For correct typesetting of chars like _ in category code 12, either
% uncomment this or use an Unicode engine (e.g., LuaTeX or XeTeX):
% \usepackage[T1]{fontenc}
\usepackage{xparse} % only useful if your LaTeX is older than 2020-10-01
\usepackage[abspath]{currfile} % use the correct option name

\ExplSyntaxOn
\seq_new:N \l_uflow_prefixes_seq

\NewDocumentCommand \defineKnownPrefixes { m }
  {
    \seq_set_from_clist:Nn \l_uflow_prefixes_seq {#1}
    \tl_set:Nx \currFileAbsPathWithoutPrefix
      { \uflow_strip_prefix_from:V \currfileabspath } % correct macro name
  }

\prg_generate_conditional_variant:Nnn \str_if_eq:nn { f } { TF }

\prg_new_conditional:Npnn \uflow_str_starts_with:nn #1#2 { T }
  {
    \str_if_eq:fnTF { \str_range:nnn {#1} { 1 } { \str_count:n {#2} } } {#2}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new:Npn \__uflow_check_for_one_prefix:nn #1#2
  {
    \uflow_str_starts_with:nnT {#1} {#2}
      {
        \seq_map_break:n
          {
            \str_range:nnn {#1} { 1 + \str_count:n {#2} } { -1 }
            \use_none:nn
          }
      }
  }

\cs_new:Npn \uflow_strip_prefix_from:n #1
  {
    \seq_map_tokens:Nn \l_uflow_prefixes_seq
      { \__uflow_check_for_one_prefix:nn {#1} }
    % If none of the registered prefixes matches, leave a string'ified version
    % of #1 in the input stream (string'ified for consistency with the other
    % case, when one of the prefixes matches).
    \tl_to_str:n {#1}
  }

\cs_generate_variant:Nn \uflow_strip_prefix_from:n { V }
\cs_new_eq:NN \stripPrefixFrom \uflow_strip_prefix_from:n
\ExplSyntaxOff

\begin{document}

\defineKnownPrefixes{/foo/, /bar/baz/, /quux, {/one/with, a comma/}, /tmp/}

\noindent
\stripPrefixFrom{/foo/bar/baz/quux}\\
\stripPrefixFrom{/bar/baz/quux/mmmmh}\\
\stripPrefixFrom{/quux/z/oo/t}\\
\stripPrefixFrom{/one/with, a comma/blah/bleh}\\
\stripPrefixFrom{no match/bar/baz/quux}

\medskip\noindent
% This requires the .fls file, and therefore a compilation with the
% '-recorder' option.
\currfileabspath\\
\currFileAbsPathWithoutPrefix

\end{document}

enter image description here