<?xml version="1.0" encoding="utf-8"?>
<article id="Filters">
  <title>Using Filters<indexterm>
      <primary>filters</primary>

      <seealso>file filters</seealso>

      <seealso>file masks</seealso>

      <seealso>line filters</seealso>

      <seealso>substitution filters</seealso>
    </indexterm></title>

  <para>When you compare files or folders, you can use filters to narrow the
  scope of the comparison. This can be useful when you want to simplify the
  comparison result by eliminating differences that you are not interested in.
  Filters are rules based on regular expressions. WinMerge uses the popular PCRE
  (Perl Compatible Regular Expressions) regular expression engine.<indexterm>
      <primary>regular expressions</primary>

      <secondary>supported engine</secondary>
    </indexterm><indexterm>
      <primary>PCRE regular expression engine</primary>
    </indexterm><indexterm>
      <primary>regexp</primary>

      <see>regular expressions</see>
    </indexterm></para>

  <para>The basic function of filtering is simple: evaluate each item that would
  normally be compared (a folder, file, or line within a file), and if the
  filter expression matches the target item, apply the filter. Depending on the
  type of filter, the item is either included or excluded in the
  comparison.</para>

  <para>There are different WinMerge filters for folder compare and file compare
  operations:</para>

  <variablelist>
    <varlistentry>
      <term>Folder comparison: File masks and file filters<indexterm>
          <primary>comparing folders</primary>

          <secondary>filtering</secondary>
        </indexterm></term>

      <listitem>
        <para>You can specify files to include in a folder comparison by using
        simple file masks, or, for more complex filtering, by applying multiple
        rules specified in a file filter.</para>

        <para>Files and folders that are filtered are hidden in the result by
        default, which is typically what you want. You can click <menuchoice>
            <guimenu>View</guimenu>

            <guimenuitem>Show Skipped Items</guimenuitem>
          </menuchoice> to unhide filtered items, but the Folder Compare window
        shows only minimal information about them. For example, you cannot tell
        whether a skipped file is a text file or binary.</para>

        <para>The display file/folder filter is also available for folder compare
        operations. Unlike file filters, it does not affect the comparison result;
        it only controls which items are visible in the Folder Compare window.
        See <xref linkend="Filters_DisplayFileFolderFilter"/>.</para>
      </listitem>
    </varlistentry>

    <varlistentry>
      <term>File comparisons: Line filters and substitution filters<indexterm>
          <primary>comparing files</primary>

          <secondary>filtering</secondary>
        </indexterm></term>

      <listitem>
        <para>Line filters are applied only to file compare operations. They let
        you ignore single line differences.</para>
        <para>Substitution filters are applied only to file compare operations.
        They replace the strings in the diff block with the specified strings,
        compare them, and ignore the diff block if the replacement results match.
        They are useful for ignoring large numbers of uninteresting changes. 
        </para>
        <para>The display line filter is also applied only to file compare
        operations. Unlike line filters, it does not affect the comparison result;
        it only controls which lines are visible in the File Compare window.
        See <xref linkend="Filters_DisplayLineFilter"/>.</para>
      </listitem>
    </varlistentry>
  </variablelist>

  <section id="Filters_Mask">
    <title>Using file masks<indexterm>
        <primary>file masks</primary>
      </indexterm><indexterm>
        <primary>filters</primary>

        <secondary>file masks</secondary>
      </indexterm><indexterm>
        <primary>filters</primary>

        <secondary>in folder comparisons</secondary>
      </indexterm></title>

    <para>You can use one or more <glossterm>file masks</glossterm> that specify
    file extensions to include in a folder comparison. All other files are
    omitted from your selection.</para>

    <section id="Filters_MaskApply">
      <title>Defining and applying file masks<indexterm>
          <primary>command line</primary>

          <secondary>applying file masks</secondary>
        </indexterm></title>

      <para>Define and apply a file mask at the time you launch your folder
      compare operation:</para>

      <itemizedlist>
        <listitem>
          <para>If you are using the Select Files or Folders dialog, after
          choosing the <guilabel>1st</guilabel> and <guilabel>2nd</guilabel>
          folders, enter one or more file masks in the
          <guilabel>Filter</guilabel> field. The masks are applied when you
          start the folder compare operation.</para>
        </listitem>

        <listitem>
          <para>If you are using the WinMerge command line, use the
          <option>-f</option> flag to specify file masks (see the example in the
          next section).</para>
        </listitem>
      </itemizedlist>
    </section>

    <section id="Filters_MaskSyntax">
      <title>File mask syntax and example<indexterm>
          <primary>rules</primary>

          <secondary>file masks</secondary>
        </indexterm><indexterm>
          <primary>filters</primary>

          <secondary>file masks</secondary>
        </indexterm><indexterm>
          <primary>regular expressions</primary>

          <secondary>in file masks</secondary>
        </indexterm></title>

      <para>You can specify file masks and extended filters using this format:</para>

      <synopsis>
        <replaceable>Filter1 of Group1</replaceable>;<replaceable>Filter2</replaceable> ...|<replaceable>Filter1 of Group2</replaceable>;<replaceable>Filter2</replaceable> ...|...
      </synopsis>

      <itemizedlist>
        <listitem><para>The <filename>|</filename> character separates filter groups and acts as a logical AND.</para></listitem>
        <listitem><para>Filters within the same group are separated by <filename>;</filename> and are interpreted with a logical OR.</para></listitem>
        <listitem><para>A file is included only if it matches at least one filter in each group.</para></listitem>
        <listitem>
          <para>To include a literal <filename>|</filename> (pipe) character in a regular expression that is not enclosed in double quotes (such as in <filename>f:</filename> or <filename>f!:</filename> filters), use <filename>||</filename> instead. </para>
          <para>Example: <userinput>f:(abc||def)\.txt$</userinput></para>
        </listitem>
        <listitem>
          <para>Each filter (e.g., Filter1, Filter2) can be one of the following types:</para>
          <variablelist>
            <varlistentry><term><replaceable>*.ext</replaceable></term><listitem><para>File mask by extension (e.g., *.txt)</para></listitem></varlistentry>
            <varlistentry><term><replaceable>*.</replaceable></term><listitem><para>Files with no extension (e.g., README)</para></listitem></varlistentry>
            <varlistentry><term>!<replaceable>*.ext</replaceable></term><listitem><para>Exclude files matching the extension (Available since 2.16.19)</para></listitem></varlistentry>
            <varlistentry><term><replaceable>folder</replaceable>\</term><listitem><para>Target folders (must end with \) (Available since 2.16.19)</para></listitem></varlistentry>
            <varlistentry><term>!<replaceable>folder</replaceable>\</term><listitem><para>Exclude matching folders (Available since 2.16.19)</para></listitem></varlistentry>
            <varlistentry><term>f: <replaceable>regexp</replaceable></term><listitem><para>Match file names using regular expressions (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>f!: <replaceable>regexp</replaceable></term><listitem><para>Exclude files matching regex (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>d: <replaceable>regexp</replaceable></term><listitem><para>Match folder names using regex (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>d!: <replaceable>regexp</replaceable></term><listitem><para>Exclude folders matching regex (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>fe: <replaceable>expr</replaceable></term><listitem><para>Filter expression for files (e.g. fe:Size &lt; 1KB) (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>fe!: <replaceable>expr</replaceable></term><listitem><para>Filter expression to exclude files (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>de: <replaceable>expr</replaceable></term><listitem><para>Filter expression for folders (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>de!: <replaceable>expr</replaceable></term><listitem><para>Filter expression to exclude folders (Available since 2.16.49)</para></listitem></varlistentry>
            <varlistentry><term>pf: <replaceable>file filter name</replaceable></term><listitem><para>Apply a file filter by name (Available since 2.16.49)</para></listitem></varlistentry>
          </variablelist>
        </listitem>
      </itemizedlist>

      <example>
        <title>File mask</title>

        <para>In this command-line example, the folder compare operation
        includes only files with <filename>xml</filename> or
        <filename>txt</filename> extensions. All other files are omitted:</para>

        <para><userinput>WinMergeU c:\project\docs c:\temp /f
        *.xml;*.txt</userinput></para>
      </example>

      <example>
        <title>Excluding folders (since version 2.16.19)</title>

        <para>In this command-line example, the folder compare operation
        excludes <filename>.git</filename> and
        <filename>.vs</filename> folders:</para>

        <para><userinput>WinMergeU c:\project\docs c:\temp /f
        !.git\;!.vs\</userinput></para>
      </example>

      <example>
        <title>Filter expression (since version 2.16.49)</title>

        <para>In this command-line example, the folder compare operation
        includes only files with <filename>cpp</filename> or <filename>h</filename> extensions and
        a file size less than 1KB:</para>

        <para><userinput>WinMergeU c:\project\docs c:\temp /f
        "*.cpp;*.h|fe:Size &lt; 1KB"</userinput></para>
      </example>
    </section>

    <section id="FilterExpression_Syntax">
      <title>Filter Expression Syntax</title>

      <para>
        WinMerge allows powerful filtering using expressions that operate on file metadata,
        contents, and comparison context. This section describes the supported attributes, operators,
        functions, data types, and evaluation rules.
      </para>

      <section id="FilterExpression_Literals">
        <title>Literals and Types</title>

        <para>Supported literal types include:</para>
        <itemizedlist>
          <listitem><para><emphasis>Boolean</emphasis>: <literal>true</literal>, <literal>false</literal></para></listitem>
          <listitem><para><emphasis>Null</emphasis>: <literal>none</literal> (represents a null or missing value)</para></listitem>
          <listitem><para><emphasis>Integer</emphasis>: 64-bit signed integers (e.g., <literal>1024</literal>, or with units like <literal>100KB</literal>, <literal>7days</literal>)</para></listitem>
          <listitem><para><emphasis>Real (Double)</emphasis>: Floating-point numbers with optional decimal or exponent (e.g., <literal>3.14</literal>, <literal>.5</literal>, <literal>1e6</literal>)</para></listitem>
          <listitem><para><emphasis>String</emphasis>: Enclosed in double quotes (e.g., <literal>"example"</literal>)</para></listitem>
          <listitem><para><emphasis>Date/Time</emphasis>: Prefixed with <literal>d</literal> and enclosed in double quotes (e.g., <literal>d"2026-05-21 07:16:33"</literal>, <literal>d"2026-05-21"</literal>)</para></listitem>
        </itemizedlist>

        <para>
          Internally, values may be of the following types:
          Boolean, Integer, Real, Timestamp, String, File Content, Array, or <literal>none</literal>.
        </para>
      </section>

      <section id="FilterExpression_Directives">
        <title>Directives</title>

        <para>
          Filter expressions support directives that control how the expression is evaluated.
          Directives are specified at the beginning of the expression, prefixed with <literal>@</literal>,
          and separated from the expression by whitespace.
        </para>

        <section id="FilterExpression_CaseSensitivity">
          <title>Case Sensitivity Directives</title>

          <para>
            By default, all string comparison operators (<literal>=</literal>, <literal>!=</literal>,
            <literal>&lt;</literal>, <literal>&lt;=</literal>, <literal>&gt;</literal>, <literal>&gt;=</literal>,
            <literal>contains</literal>, <literal>recontains</literal>, <literal>like</literal>, <literal>matches</literal>)
            are case-insensitive. You can control this behavior using the following directives:
          </para>

          <variablelist>
            <varlistentry>
              <term><literal>@cs</literal>, <literal>@casesensitive</literal></term>
              <listitem>
                <para>
                  Enable case-sensitive comparison. With these directives, <literal>"ABC"</literal> and <literal>"abc"</literal> are considered different.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><literal>@ci</literal>, <literal>@caseinsensitive</literal></term>
              <listitem>
                <para>
                  Enable case-insensitive comparison (default behavior). With these directives, <literal>"ABC"</literal> and <literal>"abc"</literal> are considered identical.
                </para>
              </listitem>
            </varlistentry>
          </variablelist>

          <example>
            <title>Case Sensitivity Examples</title>
            <programlisting>@cs Name = "README.txt"           ## Case-sensitive: matches only "README.txt"
@ci Name = "readme.txt"           ## Case-insensitive: matches "README.txt", "readme.txt", "ReadMe.TXT", etc.
@casesensitive Extension = "TXT"  ## Case-sensitive: matches only files with ".TXT" extension
@caseinsensitive Content contains "error"  ## Case-insensitive: matches "Error", "ERROR", "error", etc.</programlisting>
          </example>
        </section>

        <section id="FilterExpression_Optimize">
          <title>Optimization Directives</title>

          <para>
            By default, filter expressions are optimized to improve performance. You can control this behavior
            using the following directives:
          </para>

          <variablelist>
            <varlistentry>
              <term><literal>@optimize</literal>, <literal>@opt</literal></term>
              <listitem>
                <para>
                  Enable filter expression optimization (default behavior). This may improve performance for complex expressions.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><literal>@nooptimize</literal>, <literal>@noopt</literal></term>
              <listitem>
                <para>
                  Disable filter expression optimization. This is useful for debugging or when optimization causes unexpected results.
                </para>
              </listitem>
            </varlistentry>
          </variablelist>

          <example>
            <title>Optimization Examples</title>
            <programlisting>@optimize Size &gt; 10MB and Extension = "log"     ## Enable optimization (default)
@noopt Name matches "complex[0-9]+pattern"    ## Disable optimization for debugging
@nooptimize Content contains "special-case"   ## Disable optimization</programlisting>
          </example>
        </section>

        <section id="FilterExpression_Name">
          <title>Name Directive</title>

          <para>
            The <literal>@name</literal> directive allows you to assign a descriptive name to a filter expression.
            This name is intended for use in error messages and logs to help identify which filter expression caused an issue.
          </para>

          <variablelist>
            <varlistentry>
              <term><literal>@name="Filter Name"</literal>, <literal>@name=FilterName</literal></term>
              <listitem>
                <para>
                  Assigns a name to the filter expression. If the name contains spaces or special characters,
                  it must be enclosed in double quotes. Names without spaces can be specified without quotes.
                </para>
                <para>
                  The specified name will be used in error messages and diagnostic output to identify the filter.
                  This is particularly useful when working with multiple complex filter expressions.
                </para>
              </listitem>
            </varlistentry>
          </variablelist>

          <example>
            <title>Name Directive Examples</title>
            <programlisting>@name="Large Image Files" Size &gt; 10MB and Extension = "png"
@name=SmallTextFiles Size &lt; 1KB and Extension = "txt"
@name="Modified Today" Date &gt;= today()
@name="Test Filter" @cs Name like "test_*.cpp"</programlisting>
          </example>

          <note>
            <para>
              The <literal>@name</literal> directive can be combined with other directives.
              When multiple directives are used, they should all appear at the beginning of the expression,
              separated by whitespace.
            </para>
          </note>
        </section>
      </section>

      <section id="FilterExpression_Attributes">
        <title>Attributes</title>

        <para>
          Filter expressions support a variety of attributes referring to file metadata and content.
          Attribute names are case-insensitive. You can optionally specify which side of the comparison
          (Left, Right, or Middle) an attribute applies to by using a prefix.
        </para>

        <section>
          <title>Core Attributes</title>
          <variablelist>
            <varlistentry>
              <term><varname>Exists</varname></term>
              <listitem><para>Returns <literal>true</literal> if the file exists, <literal>false</literal> otherwise</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Name</varname></term>
              <listitem><para>File name</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>BaseName</varname></term>
              <listitem><para>Returns the filename without extension. For example, "document.txt" returns "document".</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Extension</varname></term>
              <listitem><para>File extension</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>IsFolder</varname></term>
              <listitem><para>Returns true if the item is a folder/directory, false if it's a file.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Folder</varname></term>
              <listitem><para>Returns the relative path excluding the file name and base folder</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>RelPath</varname></term>
              <listitem><para>Returns the relative path from the comparison root directory, including both folder path and filename. For example, if comparing "C:\Project" and the file is at "C:\Project\src\main.cpp", RelPath returns "src\main.cpp".</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>FullPath</varname></term>
              <listitem><para>Returns the full path of the file</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Size</varname></term>
              <listitem><para>File size</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Date</varname></term>
              <listitem><para>Last modified timestamp</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>DateStr</varname></term>
              <listitem><para>Last modified date string in <literal>yyyy-MM-dd</literal> format</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>CreationTime</varname></term>
              <listitem><para>Creation date timestamp</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Attributes</varname></term>
              <listitem><para>Returns the file attributes as an integer value</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>AttrStr</varname></term>
              <listitem>
                <para>Returns file attribute string. Examples:
                  <literal>"R"</literal> for Read-only,
                  <literal>"H"</literal> for Hidden,
                  <literal>"A"</literal> for Archive,
                  <literal>"S"</literal> for System file.
                </para>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section>
          <title>File-only Attributes</title>
          <para>
            The following attributes are available only for file comparison items.
            When used with folder items, the behavior is undefined.
          </para>

          <variablelist>
            <varlistentry>
              <term><varname>Content</varname></term>
              <listitem><para>Content of the file. Returns a FileContent-type value. Only <literal>contains</literal> and <literal>recontains</literal> can be used with this type.</para></listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section>
          <title>Folder-only Attributes</title>
          <para>
            The following attributes are available only for folder comparison items.
            When used with file items, the behavior is undefined.
          </para>

          <variablelist>
            <varlistentry>
              <term><varname>Files</varname></term>
              <listitem><para>Number of files directly contained in the folder.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>RecursiveFiles</varname></term>
              <listitem><para>Number of files contained in the folder, including all subfolders.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Items</varname></term>
              <listitem><para>Number of items (files and subfolders) directly contained in the folder.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>RecursiveItems</varname></term>
              <listitem><para>Number of items (files and subfolders) contained in the folder, including all subfolders.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>TotalSize</varname></term>
              <listitem><para>Total size of all files directly contained in the folder, in bytes.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>RecursiveTotalSize</varname></term>
              <listitem><para>Total size of all files contained in the folder, including all subfolders, in bytes.</para></listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section>
          <title>Side-Specific Prefixes</title>
          <para>
            Prefixes may be added to specify the comparison side:
          </para>
          <itemizedlist>
            <listitem><para><emphasis>Left</emphasis>: Applies to the file on the left side (e.g., <literal>LeftSize</literal>)</para></listitem>
            <listitem><para><emphasis>Right</emphasis>: Applies to the file on the right side (e.g., <literal>RightDate</literal>)</para></listitem>
            <listitem><para><emphasis>Middle</emphasis>: Applies to the middle file in 3-way comparison (e.g., <literal>MiddleName</literal>)</para></listitem>
          </itemizedlist>

          <para>
            Attributes without a prefix (e.g., <literal>Size</literal>) return an array of values from all available sides (Left, Middle, Right).
          </para>
        </section>

        <section>
          <title>Windows Property Attributes</title>
          <para>
            These attributes provide access to Windows Property System values,
            such as metadata defined by the Windows Property System schema
            (e.g., <literal>System.Title</literal>,
            <literal>System.FileOwner</literal>, <literal>System.Image.HorizontalResolution</literal>).
          </para>

          <variablelist>
            <varlistentry>
              <term><varname>Prop</varname></term>
              <listitem>
                <para>
                  Returns an array of property values (Left, Middle, Right) for the specified canonical property name.
                  Example: <literal>prop("System.Title")</literal>
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>LeftProp</varname></term>
              <listitem>
                <para>
                  Property value of the left-side file. Example: <literal>leftprop("System.FileOwner")</literal>
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>MiddleProp</varname></term>
              <listitem>
                <para>Property value of the middle file (in 3-way comparison).</para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>RightProp</varname></term>
              <listitem>
                <para>Property value of the right-side file.</para>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section>
          <title>Display Filters Only Attributes</title>
          <para>
            The following attributes are designed for use in <emphasis role="bold">Display filters only</emphasis> 
            (specified via <guilabel>e:</guilabel>, <guilabel>e!:</guilabel>, <guilabel>fe:</guilabel>, 
            <guilabel>fe!:</guilabel>, <guilabel>de:</guilabel>, or <guilabel>de!:</guilabel> prefixes in the Filter field).
            They should not be used in file filter (<filename>.flt</filename>) include/exclude rules,
            as they require the comparison to be completed first and may lead to unexpected behavior.
          </para>

          <variablelist>
            <varlistentry>
              <term><varname>Identical</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the comparison result indicates the items are identical, <literal>false</literal> otherwise.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>Identical</literal> to show only identical files.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>Different</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the comparison result indicates the items are different, <literal>false</literal> otherwise.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>Different</literal> to show only different files.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>Skipped</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the comparison was skipped due to an error or filter rule, <literal>false</literal> otherwise.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>Skipped</literal> to show only skipped items.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>Binary</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the file is detected as binary, <literal>false</literal> if it's text, or <literal>none</literal> if the file doesn't exist.
                  This attribute supports side-specific prefixes (e.g., <literal>LeftBinary</literal>, <literal>RightBinary</literal>).
                  Example: <literal>allof(Binary)</literal> to show files that are binary on all sides.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>DifferentLeftMiddle</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the left and middle files are different in a 3-way comparison, <literal>false</literal> otherwise.
                  Returns <literal>none</literal> in 2-way comparisons.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>DifferentLeftMiddle and not DifferentMiddleRight</literal> to find files where only left differs from middle.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>DifferentMiddleRight</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the middle and right files are different in a 3-way comparison, <literal>false</literal> otherwise.
                  Returns <literal>none</literal> in 2-way comparisons.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>DifferentMiddleRight</literal> to show files where middle and right differ.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>DifferentLeftRight</varname></term>
              <listitem>
                <para>
                  In 3-way comparisons, returns <literal>true</literal> if the left and right files are different, <literal>false</literal> otherwise.
                  In 2-way comparisons, returns <literal>true</literal> if both files exist and are different.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>DifferentLeftRight</literal> to show files where left and right differ.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>Differences</varname></term>
              <listitem>
                <para>
                  Returns the number of text differences in the file comparison.
                  This attribute is only meaningful for text files that have been compared.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>Differences &gt; 0</literal> to show files with differences, 
                  or <literal>Differences &gt; 10</literal> to show files with more than 10 differences.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>IgnoredDiffs</varname></term>
              <listitem>
                <para>
                  Returns the number of ignored differences in the file comparison (differences filtered by line filters or whitespace settings).
                  This attribute is only meaningful for text files that have been compared.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>IgnoredDiffs &gt; 0</literal> to show files with ignored differences,
                  or <literal>Differences = 0 and IgnoredDiffs &gt; 0</literal> to show files that are identical except for ignored differences.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>Unpacker</varname></term>
              <listitem>
                <para>
                  Returns the name of the unpacker plugin used for the file comparison, or an empty string if no unpacker was used.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>Unpacker = "CompareMSExcelFiles"</literal> to show files compared using the Excel unpacker,
                  or <literal>Unpacker != ""</literal> to show all files where an unpacker was used.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>Prediffer</varname></term>
              <listitem>
                <para>
                  Returns the name of the prediffer plugin used for the file comparison, or an empty string if no prediffer was used.
                  This is a global attribute (does not support side-specific prefixes).
                  Example: <literal>Prediffer = "IgnoreColumns"</literal> to show files compared using the IgnoreColumns prediffer,
                  or <literal>Prediffer != ""</literal> to show all files where a prediffer was used.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>EOL</varname></term>
              <listitem>
                <para>Returns the end-of-line (EOL) style as an integer value. For files, returns the predominant EOL style; for lines, returns the EOL style of that specific line.</para>
                <para>Values: 0 = None, 1 = LF (Unix), 2 = CR (Mac), 3 = CRLF (Windows), 4 = Mixed (multiple EOL styles in file)</para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>EOLStr</varname></term>
              <listitem>
                <para>Returns the end-of-line (EOL) style as a string. For files, returns the predominant EOL style; for lines, returns the EOL style of that specific line.</para>
                <para>Values: "None", "LF", "CR", "CRLF", "Mixed"</para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><varname>Codepage</varname></term>
              <listitem>
                <para>
                  Returns the file's codepage (character encoding) as an integer value.
                  This attribute supports side-specific prefixes (e.g., <literal>LeftCodepage</literal>, <literal>RightCodepage</literal>).
                  Example: <literal>Codepage = 65001</literal> to show UTF-8 files,
                  or <literal>allof(Codepage = 65001)</literal> to show files that are UTF-8 on all sides.
                </para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><varname>HasBOM</varname></term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if the file has a Byte Order Mark (BOM), <literal>false</literal> otherwise.
                  This attribute supports side-specific prefixes (e.g., <literal>LeftHasBOM</literal>, <literal>RightHasBOM</literal>).
                  Example: <literal>HasBOM</literal> to show files with BOM,
                  or <literal>not HasBOM</literal> to show files without BOM.
                </para>
              </listitem>
            </varlistentry>

          </variablelist>
        </section>

        <section id="FilterExpression_ArrayEvaluation">
          <title>Array Evaluation</title>

          <para>
            Attributes without a side prefix (e.g., <literal>Size</literal>) return an array of values from all available sides
            (Left, Middle, Right). When applying an operator to such arrays, behavior differs depending on whether the comparison is
            with a scalar or another array.
          </para>

          <section id="FilterExpression_ArrayVsScalar">
            <title>Array vs Scalar</title>
            <para>
              When comparing an array to a scalar, the operation is applied to each array element individually.
              This results in a boolean array. If any element in this boolean array is <literal>true</literal>,
              the overall expression evaluates to <literal>true</literal>. Otherwise, it evaluates to <literal>false</literal>.
            </para>
            <example>
              <title>Example</title>
              <programlisting>[3, 5, 8] &gt; 6 -> [false, false, true] -> true</programlisting>
            </example>
          </section>

          <section id="FilterExpression_ArrayVsArray">
            <title>Array vs Array</title>
            <para>
              When comparing two arrays, the behavior depends on the operator:
            </para>
            <itemizedlist>
              <listitem>
                <para>
                  For <literal>=</literal> and <literal>!=</literal>:
                  The arrays must have the same length.
                  The result is a single boolean value, not an array.
                  <literal>=</literal> returns <literal>true</literal> only if all elements are equal.
                  <literal>!=</literal> returns <literal>true</literal> if any element differs.
                </para>
              </listitem>
              <listitem>
                <para>
                  For all other operators (e.g., <literal>&gt;</literal>, <literal>&lt;</literal>):
                  the operation is applied element-wise, producing a boolean array.
                  The final result of the expression is <literal>true</literal> if any element in the boolean array is <literal>true</literal>,
                  and <literal>false</literal> if all elements are <literal>false</literal>.
                </para>
              </listitem>
            </itemizedlist>

            <example>
              <title>Examples</title>
              <programlisting>[2, 4] = [2, 4] -> true</programlisting>
              <programlisting>[2, 4] != [2, 5] -> true (because 4 != 5)</programlisting>
              <programlisting>[3, 5, 8] &gt; [6, 4, 2]
 -> [false, true, true]
 -> true (because at least one comparison is true)
              </programlisting>
            </example>
          </section>

          <section id="FilterExpression_ArraySummary">
            <title>Summary</title>
            <itemizedlist>
              <listitem>
                <para>
                  Array vs scalar comparisons produce a boolean array.
                  The overall expression result is <literal>true</literal> if at least one element is <literal>true</literal>.
                </para>
              </listitem>
              <listitem>
                <para>
                  Array vs array with <literal>=</literal> or <literal>!=</literal> returns a single boolean value.
                </para>
              </listitem>
              <listitem>
                <para>
                  Array vs array with other operators produces a boolean array.
                  The final result is <literal>true</literal> if any element is <literal>true</literal>.
                </para>
              </listitem>
            </itemizedlist>
          </section>
        </section>
      </section>

      <section id="FilterExpression_Operators">
        <title>Operators</title>

        <para>
          By default, all string comparison operators (such as <literal>=</literal>, <literal>!=</literal>, 
          <literal>&lt;</literal>, <literal>&lt;=</literal>, <literal>&gt;</literal>, <literal>&gt;=</literal>,
          <literal>like</literal>, <literal>matches</literal>, <literal>contains</literal>, and <literal>recontains</literal>) 
          are case-insensitive. You can control this behavior using directives (see <xref linkend="FilterExpression_CaseSensitivity" />).
        </para>

        <variablelist>
          <varlistentry>
            <term><literal>&lt;</literal>, <literal>&lt;=</literal>, <literal>&gt;</literal>, <literal>&gt;=</literal></term>
            <listitem><para>Numeric, timestamp, or string comparison</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>=</literal></term>
            <listitem><para>Equality comparison</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>!=</literal></term>
            <listitem><para>Inequality comparison</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>+</literal>, <literal>-</literal>, <literal>*</literal>, <literal>/</literal>, <literal>%</literal></term>
            <listitem>
              <para>
                Arithmetic operators. <literal>+</literal> and <literal>-</literal> perform addition and subtraction. <literal>*</literal> and <literal>/</literal> perform multiplication and division. <literal>%</literal> is the modulo operator (remainder).
              </para>
            </listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>and</literal>, <literal>or</literal>, <literal>not</literal></term>
            <listitem><para>Logical operators</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>like</literal></term>
            <listitem>
              <para>Wildcard string match</para>
              <para>You can also use <literal>not like</literal> to perform the inverse match.</para>
            </listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>matches</literal></term>
            <listitem>
              <para>Matches regular expressions</para>
              <para>You can also use <literal>not matches</literal> to perform the inverse match.</para>
            </listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>contains</literal></term>
            <listitem>
              <para>Checks if a string contains a substring</para>
              <para>You can also use <literal>not contains</literal> to check for absence of the substring.</para>
            </listitem>
          </varlistentry>
          <varlistentry>
            <term><literal>recontains</literal></term>
            <listitem>
              <para>Checks if any substring matches a regular expression</para>
              <para>You can also use <literal>not recontains</literal> to ensure no match exists.</para>
            </listitem>
          </varlistentry>
        </variablelist>
      </section>

      <section id="FilterExpression_Functions">
        <title>Functions</title>

        <para>
          Filter expressions support various functions for manipulating and analyzing data.
          Functions are organized by category for easier reference.
        </para>

        <section id="FilterExpression_StringFunctions">
          <title>String Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>strlen</function>(<replaceable>source</replaceable>)</term>
              <listitem><para>Returns the length of the string as an <literal>Integer</literal>. If <replaceable>source</replaceable> is a string array, the result is an integer array. Example: <literal>strlen(Name)</literal></para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>strCount</function>(<replaceable>str</replaceable>, <replaceable>substr</replaceable>)</term>
              <listitem>
                <para>
                  Counts how many times the substring <replaceable>substr</replaceable> appears in <replaceable>str</replaceable>.
                  The search is case-insensitive by default (respects <literal>@cs</literal>/<literal>@ci</literal> directives).
                  If <replaceable>str</replaceable> is an array, the result is an integer array with counts for each element.
                  Overlapping matches are counted separately (e.g., <literal>strCount("aaaa", "aa")</literal> returns 2).
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>strCount("hello hello world", "hello")</literal> returns 2</para></listitem>
                  <listitem><para><literal>strCount("Test TEST test", "test")</literal> returns 3 (case-insensitive)</para></listitem>
                  <listitem><para><literal>@cs strCount("Test TEST test", "test")</literal> returns 1 (case-sensitive)</para></listitem>
                  <listitem><para><literal>le:strCount(Line, "ERROR") > 2</literal> shows lines containing "ERROR" more than twice</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>regexCount</function>(<replaceable>str</replaceable>, <replaceable>pattern</replaceable>)</term>
              <listitem>
                <para>
                  Counts how many times the regular expression <replaceable>pattern</replaceable> matches in <replaceable>str</replaceable>.
                  The search is case-insensitive by default (respects <literal>@cs</literal>/<literal>@ci</literal> directives).
                  If <replaceable>str</replaceable> is an array, the result is an integer array with counts for each element.
                  Zero-length matches are handled gracefully to avoid infinite loops.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>regexCount("test123abc456", "\d+")</literal> returns 2</para></listitem>
                  <listitem><para><literal>regexCount("AAA BBB CCC", "[A-Z]+")</literal> returns 3</para></listitem>
                  <listitem><para><literal>@cs regexCount("Test TEST", "TEST")</literal> returns 1</para></listitem>
                  <listitem><para><literal>le:regexCount(Line, "\b(error|warning)\b") > 0</literal> shows lines with error or warning keywords</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>strFind</function>(<replaceable>str</replaceable>, <replaceable>substr</replaceable>[, <replaceable>occurrence</replaceable>])</term>
              <listitem>
                <para>
                  Finds the position (0-based) of the Nth occurrence of substring <replaceable>substr</replaceable> in <replaceable>str</replaceable>.
                  The optional <replaceable>occurrence</replaceable> parameter specifies which occurrence to find (0-based, default is 0 for the first occurrence).
                  The search is case-insensitive by default (respects <literal>@cs</literal>/<literal>@ci</literal> directives).
                  Returns <literal>none</literal> if the substring is not found or if the occurrence index is out of range.
                  If <replaceable>str</replaceable> is an array, the result is an array of positions (or none values).
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>strFind("hello world", "o")</literal> returns 4 (first 'o')</para></listitem>
                  <listitem><para><literal>strFind("hello world", "o", 1)</literal> returns 7 (second 'o')</para></listitem>
                  <listitem><para><literal>@cs strFind("Test TEST test", "test")</literal> returns 10 (case-sensitive)</para></listitem>
                  <listitem><para><literal>strFind(array("abc", "def"), "b")</literal> returns <literal>array(1, none)</literal></para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>regexFind</function>(<replaceable>str</replaceable>, <replaceable>pattern</replaceable>[, <replaceable>group</replaceable>[, <replaceable>occurrence</replaceable>]])</term>
              <listitem>
                <para>
                  Finds the position (0-based) of the Nth occurrence of a regular expression match in <replaceable>str</replaceable>.
                  The optional <replaceable>group</replaceable> parameter specifies which capture group to locate (0-based, default is 0 for the entire match).
                  The optional <replaceable>occurrence</replaceable> parameter specifies which occurrence of the pattern to find (0-based, default is 0 for the first occurrence).
                  The search is case-insensitive by default (respects <literal>@cs</literal>/<literal>@ci</literal> directives).
                  Returns <literal>none</literal> if the pattern doesn't match, the group index is out of range, or the occurrence index is out of range.
                  If <replaceable>str</replaceable> is an array, the result is an array of positions (or none values).
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>regexFind("test123abc456", "\d+")</literal> returns 4 (position of "123")</para></listitem>
                  <listitem><para><literal>regexFind("test123abc456", "\d+", 0, 1)</literal> returns 10 (position of "456", second match)</para></listitem>
                  <listitem><para><literal>regexFind("abc-def-ghi", "([a-z]+)-([a-z]+)", 1)</literal> returns 0 (position of first capture group "abc")</para></listitem>
                  <listitem><para><literal>regexFind("v1.0 and v2.5", "v(\d+)\.(\d+)", 1, 1)</literal> returns 10 (major version "2" in second occurrence)</para></listitem>
                  <listitem><para><literal>regexFind(array("test123", "abc"), "\d+")</literal> returns <literal>array(4, none)</literal></para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>substr</function>(<replaceable>source</replaceable>, <replaceable>start</replaceable>, <replaceable>count</replaceable>)</term>
              <listitem><para>Returns a specific range of text from the <emphasis>string or string array</emphasis> as a <literal>String</literal>. If <replaceable>source</replaceable> is a string array, the result is a string array. Example: <literal>substr(Name, 0, 3)</literal></para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>replace</function>(str, from, to)</term>
              <listitem>
                <para>
                  Replaces all occurrences of the string <replaceable>from</replaceable> with <replaceable>to</replaceable>.
                  If <replaceable>str</replaceable> is an array, the result is an array of strings with replacements applied.
                  Example: <literal>replace(name, ".bak", ".txt")</literal>
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>regexReplace</function>(str, pattern, replacement)</term>
              <listitem>
                <para>
                  Replaces all matches of the regular expression pattern with the replacement string.
                  Supports backreferences ($1, $2, etc.) in the replacement string.
                  If <replaceable>str</replaceable> is an array, the result is an array of strings with replacements applied.
                  Example: <literal>regexReplace(name, "^(\w+)_(\w+)$", "$2_$1")</literal> swaps words separated by underscore.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>replaceWithList</function>(str, filepath)</term>
              <listitem>
                <para>
                  Replaces multiple strings in <replaceable>str</replaceable> using replacement rules loaded from a tab-separated file.
                  The file format is one replacement rule per line: <literal>search_string&lt;TAB&gt;replacement_string</literal>.
                  Lines starting with <literal>#</literal> are treated as comments and ignored.
                  Empty lines are also ignored.
                  If <replaceable>str</replaceable> is an array, the result is an array of strings with replacements applied.
                </para>
                <para>File format example:</para>
                <screen># Comment line
apple	orange
cat	dog
old	new</screen>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>replaceWithList(Name, "C:\Filters\replacements.txt")</literal> - applies replacements from file to file name</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>regexReplaceWithList</function>(str, filepath)</term>
              <listitem>
                <para>
                  Replaces strings in <replaceable>str</replaceable> using regular expression patterns loaded from a tab-separated file.
                  The file format is one pattern per line: <literal>regex_pattern&lt;TAB&gt;replacement_string</literal>.
                  The replacement string can include backreferences ($1, $2, etc.) to captured groups.
                  Lines starting with <literal>#</literal> are treated as comments and ignored.
                  Empty lines are also ignored.
                  If <replaceable>str</replaceable> is an array, the result is an array of strings with replacements applied.
                </para>
                <para>File format example:</para>
                <screen># Comment line
\d+	NUMBER
(\d{4})-(\d{2})-(\d{2})	$1_$2_$3</screen>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>regexReplaceWithList(Name, "C:\Filters\regex_replacements.txt")</literal> - applies regex replacements to file name</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>regexExtract</function>(<replaceable>str</replaceable>, <replaceable>pattern</replaceable>[, <replaceable>group</replaceable>[, <replaceable>offset</replaceable>]])</term>
              <listitem>
                <para>
                  Captures text matching a regular expression pattern from the string.
                  The optional <replaceable>group</replaceable> parameter specifies which capture group to extract (0-based).
                  Group 0 (default) returns the entire match; groups 1, 2, etc. return the corresponding capture groups defined by parentheses in the pattern.
                  The optional <replaceable>offset</replaceable> parameter specifies which occurrence of the pattern to capture (0-based).
                  Offset 0 (default) returns the first match; offset 1 returns the second match, etc.
                  This is useful for capturing the Nth occurrence in a line, such as the second number in a string.
                  Returns <literal>none</literal> if the pattern doesn't match, the group index is out of range, or the offset exceeds the number of matches.
                  If <replaceable>str</replaceable> is an array, the result is an array with captures for each element.
                  The search is case-insensitive by default (respects <literal>@cs</literal>/<literal>@ci</literal> directives).
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>regexExtract("abc123", "[a-z]+\d+")</literal> returns <literal>"abc123"</literal> (entire match)</para></listitem>
                  <listitem><para><literal>regexExtract("abc123", "([a-z]+)(\d+)", 1)</literal> returns <literal>"abc"</literal> (first capture group)</para></listitem>
                  <listitem><para><literal>regexExtract("abc123", "([a-z]+)(\d+)", 2)</literal> returns <literal>"123"</literal> (second capture group)</para></listitem>
                  <listitem><para><literal>regexExtract("2025-05-16", "(\d{4})-(\d{2})-(\d{2})", 1)</literal> returns <literal>"2025"</literal></para></listitem>
                  <listitem><para><literal>regexExtract("user@example.com", "([^@]+)@([^@]+)", 1)</literal> returns <literal>"user"</literal></para></listitem>
                  <listitem><para><literal>regexExtract("user@example.com", "([^@]+)@([^@]+)", 2)</literal> returns <literal>"example.com"</literal></para></listitem>
                  <listitem><para><literal>regexExtract("value 123 and value 456", "(\d+)", 0, 0)</literal> returns <literal>"123"</literal> (first number)</para></listitem>
                  <listitem><para><literal>regexExtract("value 123 and value 456", "(\d+)", 0, 1)</literal> returns <literal>"456"</literal> (second number)</para></listitem>
                  <listitem><para><literal>regexExtract("v1.0.0 and v2.0.0", "v(\d+)\.(\d+)\.(\d+)", 1, 1)</literal> returns <literal>"2"</literal> (major version of second occurrence)</para></listitem>
                  <listitem><para><literal>regexExtract("test", "\d+")</literal> returns <literal>none</literal> (no match)</para></listitem>
                  <listitem><para><literal>regexExtract("abc", "([a-z])", 5)</literal> returns <literal>none</literal> (group out of range)</para></listitem>
                  <listitem><para><literal>regexExtract(array("abc123", "def456"), "([a-z]+)(\d+)", 1)</literal> returns <literal>array("abc", "def")</literal></para></listitem>
                  <listitem><para><literal>@cs regexExtract("ABC123", "([a-z]+)", 1)</literal> returns <literal>none</literal> (case-sensitive, no match)</para></listitem>
                  <listitem><para><literal>le:regexExtract(Line, "error:\s+(\w+)", 1)</literal> extracts error type from log lines</para></listitem>
                  <listitem><para><literal>fe:regexExtract(Name, "v(\d+)\.(\d+)\.(\d+)", 1) = "2"</literal> filters files with major version 2</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>normalizeUnicode</function>(str[, form])</term>
              <listitem>
                <para>
                  Normalizes Unicode string. The optional form parameter specifies the normalization form:
                  "NFC" or "C" (default), "NFD" or "D", "NFKC" or "KC", "NFKD" or "KD".
                  Can also use numeric forms: 1=NFC, 2=NFD, 5=NFKC, 6=NFKD.
                  If <replaceable>str</replaceable> is an array, the result is an array of normalized strings.
                  Example: <literal>normalizeUnicode(name, "NFC")</literal>
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toLower</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts all characters in the string to lowercase.
                  If <replaceable>str</replaceable> is an array, the result is an array of lowercase strings.
                  Example: <literal>toLower("Hello World")</literal> returns <literal>"hello world"</literal>
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toUpper</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts all characters in the string to uppercase.
                  If <replaceable>str</replaceable> is an array, the result is an array of uppercase strings.
                  Example: <literal>toUpper("Hello World")</literal> returns <literal>"HELLO WORLD"</literal>
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toHalfWidth</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts full-width characters to half-width characters.
                  Primarily used for converting full-width alphanumeric and katakana characters to half-width.
                  If <replaceable>str</replaceable> is an array, the result is an array of converted strings.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toFullWidth</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts half-width characters to full-width characters.
                  Primarily used for converting half-width alphanumeric and katakana characters to full-width.
                  If <replaceable>str</replaceable> is an array, the result is an array of converted strings.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toKatakana</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts hiragana characters to katakana.
                  Non-hiragana characters remain unchanged.
                  If <replaceable>str</replaceable> is an array, the result is an array of converted strings.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toHiragana</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts katakana characters to hiragana.
                  Non-katakana characters remain unchanged.
                  If <replaceable>str</replaceable> is an array, the result is an array of converted strings.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toSimplifiedChinese</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts traditional Chinese characters to simplified Chinese characters.
                  Characters that don't have a simplified form remain unchanged.
                  If <replaceable>str</replaceable> is an array, the result is an array of converted strings.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>toTraditionalChinese</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Converts simplified Chinese characters to traditional Chinese characters.
                  Characters that don't have a traditional form remain unchanged.
                  If <replaceable>str</replaceable> is an array, the result is an array of converted strings.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>trim</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Removes leading and trailing whitespace characters (space, tab, newline, carriage return) from the string.
                  If <replaceable>str</replaceable> is an array, the result is an array of trimmed strings.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>trim("  hello  ")</literal> returns <literal>"hello"</literal></para></listitem>
                  <listitem><para><literal>trim(array("  test  ", "  data  "))</literal> returns <literal>array("test", "data")</literal></para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>trimLeft</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Removes leading whitespace characters (space, tab, newline, carriage return) from the beginning of the string.
                  Trailing whitespace is preserved.
                  If <replaceable>str</replaceable> is an array, the result is an array of left-trimmed strings.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>trimLeft("  hello  ")</literal> returns <literal>"hello  "</literal></para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <function>trimRight</function>(<replaceable>str</replaceable>)
              </term>
              <listitem>
                <para>
                  Removes trailing whitespace characters (space, tab, newline, carriage return) from the end of the string.
                  Leading whitespace is preserved.
                  If <replaceable>str</replaceable> is an array, the result is an array of right-trimmed strings.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>trimRight("  hello  ")</literal> returns <literal>"  hello"</literal></para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_FileContentFunctions">
          <title>File Content Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>lineCount</function>(<replaceable>content</replaceable>)</term>
              <listitem><para>Returns the number of lines in the file content or file content array as an <literal>Integer</literal>. If <replaceable>content</replaceable> is an array, the result is an integer array. Example: <literal>lineCount(Content)</literal></para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>sublines</function>(<replaceable>content</replaceable>, <replaceable>start</replaceable>, <replaceable>count</replaceable>)</term>
              <listitem>
                <para>
                  Extracts the specified number of lines starting from the given line index in the file content or file content array, and returns them as a single concatenated string.
                  If <replaceable>content</replaceable> is an array, the result is an array of strings.
                </para>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_TypeConversionFunctions">
          <title>Type Conversion Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>toNumber</function>(<replaceable>str</replaceable>),
              <function>toInt</function>(<replaceable>str</replaceable>),
              <function>toDouble</function>(<replaceable>str</replaceable>)</term>
              <listitem><para>Convert a string to a number. <function>toNumber</function>
              returns an integer or floating-point number depending on the input format;
              <function>toInt</function> returns only integers;
              <function>toDouble</function> returns only floating-point numbers.
              Commas in the input are ignored. Returns <literal>none</literal>on parse failure.
              Example: <literal>le:toInt(Column("Count")) &gt; 100</literal>
              </para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>toDateTime</function>(<replaceable>str</replaceable>)</term>
              <listitem>
                <para>
                  Converts a string to a timestamp value. Supports multiple date/time formats.
                  Returns <literal>none</literal>if the string cannot be parsed.
                  Example: <literal>toDateTime("2025-01-15") &gt; today()</literal>
                </para>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_DateTimeFunctions">
          <title>Date/Time Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>now</function>()</term>
              <listitem><para>Returns the current date and time as a <literal>Timestamp</literal> value.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>today</function>()</term>
              <listitem><para>Returns today's date as a <literal>Timestamp</literal> value representing <literal>00:00:00.000</literal> at the start of the day.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>startOfWeek</function>(<replaceable>timestamp</replaceable>)</term>
              <listitem><para>Returns the first day of the week, which is always Sunday regardless of locale.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>startOfMonth</function>(<replaceable>timestamp</replaceable>)</term>
              <listitem><para>Returns the first day of the month.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>startOfYear</function>(<replaceable>timestamp</replaceable>)</term>
              <listitem><para>Returns the first day of the year.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>toDateStr</function>(<replaceable>timestamp</replaceable>)</term>
              <listitem><para>Converts the given timestamp to a date string in <literal>yyyy-MM-dd</literal> format. If <replaceable>timestamp</replaceable> is a timestamp array, the result is a string array.</para></listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_MathFunctions">
          <title>Math and Comparison Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>abs</function>(<replaceable>value</replaceable>)</term>
              <listitem><para>Returns the absolute value of the <emphasis>integer or integer array</emphasis>. If <replaceable>value</replaceable> is an integer array, the result is an integer array.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>isWithin</function>(<replaceable>value</replaceable>, <replaceable>min</replaceable>, <replaceable>max</replaceable>)</term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if <replaceable>value</replaceable> is within the range <literal>[min, max]</literal> (inclusive on both ends).
                  Supports integers, floating-point numbers, timestamps, and strings (case-insensitive comparison).
                  If <replaceable>value</replaceable> is an array, the result is a boolean array with each element checked individually.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>isWithin(5, 1, 10)</literal> returns <literal>true</literal></para></listitem>
                  <listitem><para><literal>isWithin(Size, 1KB, 10MB)</literal> checks if any file size is between 1KB and 10MB</para></listitem>
                  <listitem><para><literal>isWithin(Date, today() - 7days, today())</literal> checks if file was modified within the last week</para></listitem>
                  <listitem><para><literal>allof(isWithin(Size, 1KB, 10MB))</literal> checks if all file sizes are between 1KB and 10MB</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>inRange</function>(<replaceable>value</replaceable>, <replaceable>min</replaceable>, <replaceable>max</replaceable>)</term>
              <listitem>
                <para>
                  Returns <literal>true</literal> if <replaceable>value</replaceable> is within the range <literal>[min, max)</literal> (inclusive on the lower bound, exclusive on the upper bound).
                  Supports integers, floating-point numbers, timestamps, and strings (case-insensitive comparison).
                  If <replaceable>value</replaceable> is an array, the result is a boolean array with each element checked individually.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>inRange(5, 1, 10)</literal> returns <literal>true</literal></para></listitem>
                  <listitem><para><literal>inRange(10, 1, 10)</literal> returns <literal>false</literal></para></listitem>
                  <listitem><para><literal>inRange(Size, 0, 1MB)</literal> checks if any file size is less than 1MB</para></listitem>
                  <listitem><para><literal>anyof(inRange(Date, startOfMonth(today()), today()))</literal> checks if any file was modified this month (excluding today)</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_ArrayFunctions">
          <title>Array Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>array</function>(<replaceable>value1</replaceable>, <replaceable>value2</replaceable>, ...)</term>
              <listitem><para>Creates an array from the given values. Example: <literal>array(1, 2, 3)</literal></para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>at</function>(<replaceable>array</replaceable>, <replaceable>index</replaceable>)</term>
              <listitem><para>Returns the element at the specified index (0-based). Negative indices count from the end. Example: <literal>at(array(1, 2, 3), -1)</literal> returns 3</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>anyof</function>(<replaceable>booleans</replaceable>)</term>
              <listitem><para>Returns <literal>true</literal> if any element in the <emphasis>boolean array</emphasis> satisfies the condition.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>allof</function>(<replaceable>booleans</replaceable>)</term>
              <listitem><para>Returns <literal>true</literal> if all elements in the <emphasis>boolean array</emphasis> satisfy the condition.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>allequal</function>(<replaceable>array</replaceable>)</term>
              <listitem><para>Returns <literal>true</literal> if all values in the array are equal.</para></listitem>
            </varlistentry>
            <varlistentry>
              <term><function>len</function>(<replaceable>value</replaceable>)</term>
              <listitem>
                <para>Returns the length of the value as an <literal>Integer</literal>.</para>
                <para>Behavior:</para>
                <itemizedlist>
                  <listitem><para><emphasis>Array</emphasis>: Returns the number of elements in the array</para></listitem>
                  <listitem><para><emphasis>String</emphasis>: Returns the UTF-8 character count</para></listitem>
                  <listitem><para><emphasis>None (monostate)</emphasis>: Returns 0</para></listitem>
                  <listitem><para><emphasis>Other scalar values</emphasis> (Integer, Real, Boolean, Timestamp, etc.): Returns 1</para></listitem>
                </itemizedlist>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>len(array(1, 2, 3))</literal> - returns 3</para></listitem>
                  <listitem><para><literal>len("hello")</literal> - returns 5</para></listitem>
                  <listitem><para><literal>len(123)</literal> - returns 1</para></listitem>
                  <listitem><para><literal>len(Size)</literal> - returns the number of sides (2 or 3) in a folder comparison</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_ConditionalFunctions">
          <title>Conditional Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>if</function>(<replaceable>condition</replaceable>, <replaceable>trueValue</replaceable>, <replaceable>falseValue</replaceable>)</term>
              <listitem>
                <para>
                  Returns <replaceable>trueValue</replaceable> if <replaceable>condition</replaceable> evaluates to true, otherwise returns <replaceable>falseValue</replaceable>.
                  This function performs short-circuit evaluation (it only evaluates the branch that will be returned).
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>if(Size > 1MB, "large", "small")</literal> - returns "large" or "small" based on file size</para></listitem>
                  <listitem><para><literal>if(Extension = "txt", "text file", "other file")</literal> - classifies files by extension</para></listitem>
                  <listitem><para><literal>if(Exists, Size, 0)</literal> - returns file size or 0 if file doesn't exist</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>ifEach</function>(<replaceable>conditionArray</replaceable>, <replaceable>trueValue</replaceable>, <replaceable>falseValue</replaceable>)</term>
              <listitem>
                <para>
                  Element-wise conditional selection. For each element in <replaceable>conditionArray</replaceable>,
                  returns the corresponding element from <replaceable>trueValue</replaceable> if the condition is true,
                  otherwise returns the corresponding element from <replaceable>falseValue</replaceable>.
                  If <replaceable>trueValue</replaceable> or <replaceable>falseValue</replaceable> is a scalar, 
                  it is broadcast to all elements.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>ifEach(Size &gt; 1MB, "large", "small")</literal> - returns array of "large"/"small" labels for each file</para></listitem>
                  <listitem><para><literal>ifEach(array(true, false, true), array("a", "b", "c"), array("x", "y", "z"))</literal> - returns <literal>array("a", "y", "c")</literal></para></listitem>
                  <listitem><para><literal>anyof(ifEach(Size &gt; 100KB, Size &lt; 10MB, false))</literal> - checks if any file is between 100KB and 10MB</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>choose</function>(<replaceable>index</replaceable>, <replaceable>value0</replaceable>, <replaceable>value1</replaceable>, ...)</term>
              <listitem>
                <para>
                  Selects a value from the arguments based on <replaceable>index</replaceable>.
                  If <replaceable>index</replaceable> is 0, returns <replaceable>value0</replaceable>; if 1, returns <replaceable>value1</replaceable>, etc.
                  Negative indices are clamped to 0. Indices beyond the last value return the last value.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>choose(0, "first", "second", "third")</literal> - returns "first"</para></listitem>
                  <listitem><para><literal>choose(DiffCode % 3, "equal", "different", "unique")</literal> - maps diff codes to labels</para></listitem>
                  <listitem><para><literal>choose(5, "a", "b", "c")</literal> - returns "c" (out of bounds, returns last value)</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term><function>chooseEach</function>(<replaceable>indexArray</replaceable>, <replaceable>value0</replaceable>, <replaceable>value1</replaceable>, ...)</term>
              <listitem>
                <para>
                  Element-wise value selection. For each index in <replaceable>indexArray</replaceable>,
                  selects the corresponding value from the remaining arguments.
                  If <replaceable>indexArray</replaceable> is a scalar, behaves like <literal>choose</literal>.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>chooseEach(array(0, 1, 2), "a", "b", "c")</literal> - returns <literal>array("a", "b", "c")</literal></para></listitem>
                  <listitem><para><literal>chooseEach(array(0, 0, 1), "x", "y")</literal> - returns <literal>array("x", "x", "y")</literal></para></listitem>
                  <listitem><para><literal>chooseEach(array(2, 0, 1), "first", "second", "third")</literal> - returns <literal>array("third", "first", "second")</literal></para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_LogicalFunctions">
          <title>Element-wise Logical Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>andEach</function>(<replaceable>value1</replaceable>, <replaceable>value2</replaceable>), <function>orEach</function>(<replaceable>value1</replaceable>, <replaceable>value2</replaceable>), <function>notEach</function>(<replaceable>value</replaceable>)</term>
              <listitem>
                <para>
                  Element-wise logical operations. These functions operate on booleans, boolean arrays, or a combination of both:
                </para>
                <itemizedlist>
                  <listitem><para><literal>andEach</literal> - Logical AND operation</para></listitem>
                  <listitem><para><literal>orEach</literal> - Logical OR operation</para></listitem>
                  <listitem><para><literal>notEach</literal> - Logical NOT operation (single argument)</para></listitem>
                </itemizedlist>
                <para>
                  When arguments are scalars, returns a scalar boolean result.
                  When one argument is an array and the other is a scalar, the scalar is broadcast to all elements.
                  When both arguments are arrays, performs element-wise operation.
                </para>
                <para>Examples:</para>
                <itemizedlist>
                  <listitem><para><literal>andEach(Size &gt; 1KB, Size &lt; 1MB)</literal> - files between 1KB and 1MB</para></listitem>
                  <listitem><para><literal>orEach(Extension = "txt", Extension = "log")</literal> - txt or log files</para></listitem>
                  <listitem><para><literal>notEach(Exists)</literal> - files that don't exist</para></listitem>
                  <listitem><para><literal>allof(andEach(Exists, Size &gt; 0))</literal> - all files exist with non-zero size</para></listitem>
                  <listitem><para><literal>anyof(notEach(Size &gt; 1MB))</literal> - any file 1MB or smaller</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>

        <section id="FilterExpression_DiagnosticFunctions">
          <title>Diagnostic and Logging Functions</title>
          <variablelist>
            <varlistentry>
              <term><function>logError</function>(<replaceable>value1</replaceable>, <replaceable>value2</replaceable>, ...), <function>logWarn</function>(<replaceable>value1</replaceable>, <replaceable>value2</replaceable>, ...), <function>logInfo</function>(<replaceable>value1</replaceable>, <replaceable>value2</replaceable>, ...)</term>
              <listitem>
                <para>
                  Outputs the concatenated string representation of all arguments to the log (at error, warning, or information level respectively), 
                  separated by spaces, and returns the last argument value.
                  These functions are useful for debugging filter expressions.
                </para>
                <para>Examples (using return value):</para>
                <itemizedlist>
                  <listitem><para><literal>logInfo("File size:", Size) > 1MB</literal> - logs the file size(s) and checks if greater than 1MB</para></listitem>
                  <listitem><para><literal>logWarn("Processing:", Name) like "*.tmp"</literal> - logs the file name(s) and checks if it's a temporary file</para></listitem>
                  <listitem><para><literal>Size > 1KB and logInfo("Large file:", Name) contains "test"</literal> - logs only when size condition is true, then checks name</para></listitem>
                </itemizedlist>
              </listitem>
            </varlistentry>
          </variablelist>
        </section>
      </section>

      <section id="FilterExpression_Units">
        <title>Units</title>
        <para>File sizes support these suffixes:</para>
        <simplelist type="inline">
          <member>KB</member>
          <member>MB</member>
          <member>GB</member>
          <member>TB</member>
        </simplelist>
        <para>Time durations support these suffixes:</para>
        <simplelist type="inline">
          <member>weeks</member><member>week</member><member>w</member>
          <member>days</member><member>day</member><member>d</member>
          <member>hours</member><member>hour</member><member>hr</member><member>h</member>
          <member>minutes</member><member>minute</member><member>min</member><member>m</member>
          <member>seconds</member><member>second</member><member>sec</member><member>s</member>
          <member>milliseconds</member><member>millisecond</member><member>msec</member><member>ms</member>
        </simplelist>
      </section>

      <section id="FilterExpression_Examples">
        <title>Examples</title>
        <itemizedlist>
          <listitem><para><literal>Size &lt; 10KB</literal> - Any side's size is less than 10KB</para></listitem>
          <listitem><para><literal>LeftSize &gt;= 10MB</literal> - Left side file is at least 10MB</para></listitem>
          <listitem><para><literal>allof(Size &lt; 1MB)</literal> - All sides are under 1MB</para></listitem>
          <listitem><para><literal>abs(LeftSize - RightSize) &lt; 1KB</literal> - Size difference is small</para></listitem>
          <listitem><para><literal>DateStr = "2025-07-20"</literal> - File was last modified on that date</para></listitem>
          <listitem><para><literal>Date &gt;= today()</literal> - Modified today or later</para></listitem>
          <listitem><para><literal>Date &gt; d"2026-05-21 07:16:33"</literal> - Modified after a specific date and time</para></listitem>
          <listitem><para><literal>isWithin(Date, d"2026-01-01", d"2026-12-31 23:59:59")</literal> - Modified during the year 2026</para></listitem>
          <listitem><para><literal>isWithin(Date, today() - 7days, today())</literal> - File modified within the last week</para></listitem>
          <listitem><para><literal>inRange(Size, 1KB, 10MB)</literal> - File size is between 1KB (inclusive) and 10MB (exclusive)</para></listitem>
          <listitem><para><literal>allof(isWithin(Size, 100KB, 1MB))</literal> - All file sizes are between 100KB and 1MB</para></listitem>
          <listitem><para><literal>AttrStr contains "R"</literal> - File is read-only</para></listitem>
          <listitem><para><literal>Name matches "file[0-9]\.txt"</literal> - Regex on filename</para></listitem>
          <listitem><para><literal>Content contains "Test"</literal> - File content includes keyword</para></listitem>
          <listitem><para><literal>sublines(Content, 0, 1) contains "XML"</literal> - First line contains "XML"</para></listitem>
          <listitem><para><literal>strCount(Content, "TODO") &gt; 5</literal> - File contains more than 5 TODO comments</para></listitem>
          <listitem><para><literal>regexCount(Content, "\bFIXME\b") &gt; 0</literal> - File contains at least one FIXME marker</para></listitem>
          <listitem><para><literal>strFind(Name, "_test") != none</literal> - Files containing "_test" in their name</para></listitem>
          <listitem><para><literal>strFind(Name, ".", 1) &gt; 0</literal> - Files with multiple dots in their name (second dot exists)</para></listitem>
          <listitem><para><literal>regexFind(Name, "\d{4}") &lt; 5</literal> - Files where a 4-digit number appears within the first 5 characters</para></listitem>
          <listitem><para><literal>regexExtract(Name, "v(\d+)\.(\d+)\.(\d+)", 1) = "2"</literal> - Files with major version 2 (e.g., "v2.16.48")</para></listitem>
          <listitem><para><literal>regexExtract(Name, "([^_]+)_([^_]+)\.txt", 2) like "test*"</literal> - Files where second part of name starts with "test"</para></listitem>
          <listitem><para><literal>le:regexExtract(Line, "(\d+)", 0, 1)</literal> - Extracts the second number in each line (offset=1)</para></listitem>
          <listitem><para><literal>(Extension = "log" and Size > 10MB) or (Date &lt; today() - 7days)</literal> - Large log files or files older than a week</para></listitem>
          <listitem><para><literal>AttrStr not contains "H" and Name like "*.tmp"</literal> - Non-hidden temporary files</para></listitem>
          <listitem><para><literal>isWithin(Extension, "a", "m") and inRange(Size, 0, 1MB)</literal> - Files with extensions from 'a' to 'm' and size less than 1MB</para></listitem>
          <listitem><para><literal>toLower(Name) = "readme.txt"</literal> - Case-insensitive filename matching</para></listitem>
          <listitem><para><literal>toHalfWidth(Name) like "*.txt"</literal> - Match after converting full-width to half-width</para></listitem>
          <listitem><para><literal>trim(Name) = "readme.txt"</literal> - Match filename after removing leading/trailing whitespace</para></listitem>
          <listitem><para><literal>trimLeft(Column("Value")) = "123"</literal> - Match column value after removing leading whitespace (table mode)</para></listitem>
          <listitem><para><literal>trimRight(Line) contains "end"</literal> - Check if line (without trailing whitespace) contains "end"</para></listitem>
          <listitem><para><literal>EOL = 3</literal> - Files with CRLF (Windows) line endings</para></listitem>
          <listitem><para><literal>EOLStr = "LF"</literal> - Files with LF (Unix) line endings</para></listitem>
          <listitem><para><literal>allof(EOL = 1)</literal> - Checks whether all compared files use LF line endings</para></listitem>
          <listitem><para><literal>leftprop("System.Title") != none</literal> - Left file has a title property set</para></listitem>
          <listitem><para><literal>prop("System.Author") = none</literal> - No author property is set on any side</para></listitem>
          <listitem><para><literal>if(LeftExists, LeftSize, 0) == 0</literal> - Checks whether the left file is missing or empty</para></listitem>
          <listitem><para><literal>Different</literal> - Show only files/folders that are different (Display filter only)</para></listitem>
          <listitem><para><literal>Identical</literal> - Show only files/folders that are identical (Display filter only)</para></listitem>
          <listitem><para><literal>allof(Binary)</literal> - Show only files that are binary on all sides (Display filter only)</para></listitem>
          <listitem><para><literal>DifferentLeftMiddle and not DifferentMiddleRight</literal> - In 3-way comparison, show files where only left-middle pair differs (Display filter only)</para></listitem>
        </itemizedlist>
      </section>
    </section>
  </section>

  <section id="Filters_FileFilter">
    <title>Using file filters<indexterm>
        <primary>filters</primary>

        <secondary>file filters</secondary>
      </indexterm><indexterm>
        <primary>filters</primary>

        <secondary>in folder comparisons</secondary>
      </indexterm></title>

    <para><glossterm>File filters</glossterm> are text files with an extension
    of <filename>flt</filename>. They enable you to apply multiple filtering
    rules to a folder comparison. Unlike file masks, file filters can either
    include or exclude matches.</para>

    <para><indexterm>
        <primary>file filters</primary>

        <secondary>template</secondary>
      </indexterm>WinMerge installs a number of predefined file filters. If
    these file filters do not provide the filtering you need, you can create
    your own. To make that task easier, WinMerge also provides a template file
    named <filename>FileFilter.tmpl</filename>. This section describes how to
    apply file filters to comparisons, and documents the file filter syntax.
    <xref linkend="Filters_dlg" /> describes how to add, edit, and manage
    filters.</para>

    <section id="Filters_FileFilterLoc">
      <title>File filter locations<indexterm>
          <primary>Filters folders</primary>

          <secondary>locations</secondary>
        </indexterm><indexterm>
          <primary>file filters</primary>

          <secondary>locations</secondary>
        </indexterm></title>

      <para>WinMerge automatically detects file filters in these
      locations:</para>

      <variablelist>
        <varlistentry>
          <term>Filters subfolder in the WinMerge installation folder</term>

          <listitem>
            <para>This is where the predefined file filters are installed. For
            example, <filename>C:\Program Files\WinMerge\Filters</filename>. You
            can create or copy filter files in this location to make them
            available to all users on your system.</para>

            <para>Before creating a new file filter, see if the predefined ones
            already contain what you need. If not, you might find useful rule
            examples in the existing files.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>Default private filter folder</term>

          <listitem>
            <para>The location of this folder is defined in the System page of
            WinMerge options. By default, it is specified as a subfolder in your
            user profile folder (for example, <filename>Documents</filename> in
            Windows 10). Filters that are created or copied here are normally
            visible only to you. If you create new file filters, you can copy
            them here to keep them private.</para>
          </listitem>
        </varlistentry>
      </variablelist>

      <para>Before you can apply file filters that exist in any other folder,
      you must first install them.</para>
    </section>

    <section id="Filters_FileFilterApply">
      <title>Applying file filters<indexterm>
          <primary>file filters</primary>

          <secondary>applying</secondary>
        </indexterm></title>

      <para>You can apply a file filter using any of these methods:</para>

      <itemizedlist>
        <listitem>
          <para>When you launch a folder compare from the Select Files or
          Folders dialog:</para>

          <orderedlist>
            <listitem>
              <para>After choosing the <guilabel>1st</guilabel> and
              <guilabel>2nd</guilabel> folders, click
              <guibutton>Select</guibutton> next to the
              <guilabel>Filter</guilabel> field.</para>
            </listitem>

            <listitem>
              <para>In the Filters dialog, use the File Filters tab to choose a
              file filter and load it in the <guilabel>Filter</guilabel>
              field.</para>

              <note>
                <para>If a file filter is currently enabled, the selected file
                filter is already loaded in the <guilabel>Filter</guilabel>
                field.</para>
              </note>
              <para></para>
            </listitem>

            <listitem>
              <para>Proceed with the compare operation. The file in the
              <guilabel>Filter</guilabel> field is applied when you start the
              operation.</para>
            </listitem>
          </orderedlist>
        </listitem>

        <listitem>
          <para>To change file filtering after you have already launched a
          folder compare operation (for example, applying a different filter or
          disabling filtering):</para>

          <orderedlist>
            <listitem>
              <para>Click <menuchoice>
                  <guimenu>Tools</guimenu>

                  <guimenuitem>Filters</guimenuitem>
                </menuchoice>.</para>
            </listitem>

            <listitem>
              <para>In the Filters dialog, configure your new file filter
              setting, and click <guibutton>OK</guibutton>.</para>
            </listitem>

            <listitem>
              <para>The new filtering is not automatically applied when you
              close the Filters dialog: press <keycap>F5</keycap> to see the new
              results in the Folder Compare window.</para>
            </listitem>
          </orderedlist>
        </listitem>

        <listitem>
          <para><indexterm>
              <primary>command line</primary>

              <secondary>applying file filters</secondary>
            </indexterm>When you launch a folder compare from the WinMerge
          command line, use the <option>-f</option> flag to specify a file
          filter.</para>
        </listitem>
      </itemizedlist>
    </section>

    <section id="Filters_FileFilterSyntax">
      <title>File filter syntax<indexterm>
          <primary>rules</primary>

          <secondary>file filter</secondary>
        </indexterm><indexterm>
          <primary>file filters</primary>

          <secondary>syntax</secondary>
        </indexterm></title>

      <para>This section describes the syntax of WinMerge file filters and
      provides guidelines for writing them.</para>

      <para>The comment delimiter is <code>##</code>. After a comment delimiter,
      all characters in a line are ignored. WinMerge ignores most whitespace
      characters in rules. However, a comment must always be preceded by one or
      more whitespace (space or tab) characters. To use <code>##</code> as
      characters in a rule, omit the whitespace prefix.</para>

      <para>The first two required lines of a file filter are:</para>

      <variablelist>
        <varlistentry>
          <term>name</term>

          <listitem>
            <para>The filter name that is listed in the Files dialog</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>def</term>

          <listitem>
            <para>The type of filtering to be applied. Specify one of these
            values:</para>

            <variablelist>
              <varlistentry>
                <term>include</term>

                <listitem>
                  <para>Includes everything except items matching the specified
                  rule.</para>
                </listitem>
              </varlistentry>

              <varlistentry>
                <term>exclude</term>

                <listitem>
                  <para>Excludes everything except items matching the specified
                  rule.</para>

                  <para>When you choose the exclude method, you must also add a
                  <guilabel>d</guilabel> (directory) rule that specifies the
                  subfolders. It's usually a good idea to specify all
                  subfolders, like this:</para>

                  <screen>d: \\*$ ## Subfolders</screen>
                </listitem>
              </varlistentry>
            </variablelist>

            <tip>
              <para>Don't confuse these terms. Remember, in file filters, an
              <guilabel>include</guilabel> rule does not specify what to
              include, it specifies what <emphasis>not</emphasis> to include.
              Similarly, <guilabel>exclude</guilabel> does not specify what to
              exclude, it specifies what not to exclude.</para>
            </tip>
          </listitem>
        </varlistentry>
      </variablelist>

      <para>Next, your file should contain one or more filter rules. You can add
      as many rules as you like. There must be one rule per line, and each rule
      must be entirely on one line (no line breaks are allowed in a rule).
      A rule begins with a type designator, followed by either a regular
      expression or a filter expression.  The supported type designators are:
      </para>

      <variablelist>
        <varlistentry><term>f: <replaceable>regexp</replaceable></term><listitem><para>Match file names using regular expressions</para></listitem></varlistentry>
        <varlistentry><term>f!: <replaceable>regexp</replaceable></term><listitem><para>Exclude files matching regex (Available since 2.16.19)</para></listitem></varlistentry>
        <varlistentry><term>d: <replaceable>regexp</replaceable></term><listitem><para>Match folder names using regex</para></listitem></varlistentry>
        <varlistentry><term>d!: <replaceable>regexp</replaceable></term><listitem><para>Exclude folders matching regex (Available since 2.16.19)</para></listitem></varlistentry>
        <varlistentry><term>fe: <replaceable>expr</replaceable></term><listitem><para>Filter expression for files (e.g. fe:Size &lt; 1KB) (Available since 2.16.49)</para></listitem></varlistentry>
        <varlistentry><term>fe!: <replaceable>expr</replaceable></term><listitem><para>Filter expression to exclude files (Available since 2.16.49)</para></listitem></varlistentry>
        <varlistentry><term>de: <replaceable>expr</replaceable></term><listitem><para>Filter expression for folders (Available since 2.16.49)</para></listitem></varlistentry>
        <varlistentry><term>de!: <replaceable>expr</replaceable></term><listitem><para>Filter expression to exclude folders (Available since 2.16.49)</para></listitem></varlistentry>
        <varlistentry><term>e: <replaceable>expr</replaceable></term><listitem><para>Filter expression applied to both files and folders (e.g. e:Name like "Common*.*") (Available since 2.16.56)</para></listitem></varlistentry>
        <varlistentry><term>e!: <replaceable>expr</replaceable></term><listitem><para>Filter expression to exclude both files and folders (Available since 2.16.56)</para></listitem></varlistentry>
      </variablelist>

      <para>Among the many regexp special characters, the following are
      particularly important in file filter rules:<indexterm>
          <primary>regular expressions</primary>

          <secondary>special characters in filters</secondary>
        </indexterm><indexterm>
          <primary>regular expressions</primary>

          <secondary>in file filters</secondary>
        </indexterm></para>

      <variablelist>
        <varlistentry>
          <term>^ (beginning of line)</term>

          <listitem>
            <para>Frequently required for rules to work correctly.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>$ (end of line)</term>

          <listitem>
            <para>Frequently required for rules to work correctly. For
            example:</para>

            <screen>\.c$ ## matches only file names with the extension, <filename>c</filename>.
\.c  ## matches any extension beginning with <filename>c</filename>, like <filename>cpp</filename> and <filename>com</filename>.</screen>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>\ (escape)</term>

          <listitem>
            <para>Forces special characters to match normal characters. For
            example, to match a folder name, precede the folder backslash
            delimiter with a backslash (<code>\\</code>). To match the dot in a
            file name, specify a backslash followed by a dot
            (<code>\.</code>).</para>
          </listitem>
        </varlistentry>
      </variablelist>

      <para>No special characters or wildcards are used to match file names. To
      match all filenames of a certain type, simply omit the filename.</para>

      <para>Rules are case-insensitive. For example, <code>f: \.bat$</code>
      matches <filename>winmerge.bat</filename> and
      <filename>compare.BAT</filename>.</para>

      <example>
        <title>File filter rule examples</title>

        <para>Some simple file filter rules:</para>

        <screen>f: \.cpp$ ## Match <filename>*.cpp</filename> files
f: \.h$ ## Match <filename>*.h</filename> files
f: ^My ## Match <filename>My*.*</filename> files
f: Dlg\. ## Match <filename>*Dlg.*</filename> files
d: \\test$ ## Match <filename>test</filename> folders
d: ^\\Build$ ## Match <filename>Build</filename> folders
d: Temp$ ## Match <filename>*Temp</filename> folders (for example, <filename>FirstTemp</filename>)
d: Src ## Match <filename>*Src*</filename> folders</screen>

        <para>Some rules with more complex regular expressions:</para>

        <screen format="linespecific">f: ^\.#.*$ ## <filename>.#filename.version</filename> files
f: Dlg\.c(pp)?$ ## <filename>*Dlg.c</filename> and <filename>*Dlg.cpp</filename> files
f: ^I.*\.h$ ## <filename>I*.h</filename> files
f: Srv[1-9]\.def$ ## <filename>*Srv1.def</filename> to <filename>*Srv9.def</filename> files
f: ^[h,k,m] ## <filename>h*.*</filename>, <filename>k*.*</filename>, and <filename>m*.*</filename> files</screen>
      </example>
    </section>
  </section>

  <section id="Filters_LineFilter">
    <title>Using line filters<indexterm>
        <primary>filters</primary>

        <secondary>line</secondary>
      </indexterm><indexterm>
        <primary>filters</primary>

        <secondary>in file comparisons</secondary>
      </indexterm></title>

    <para>In a file comparison, you can use line filters to ignore single lines.
    For example, you might use line filters to ignore comments or certain type
    of generated code, like version control system timestamps. Each line filter
    is a rule, and you can apply any number of line filters to a file
    comparison.</para>

    <para>To learn how to add, edit, and manage filters, see <xref
    linkend="Filters_dlg" />.</para>

    <section id="Filters_LineFilterApply">
      <title>Applying line filters</title>

      <para>You can apply line filters using any of these methods:</para>

      <itemizedlist>
        <listitem>
          <para>When you launch a file compare from the Select Files or Folders
          dialog</para>

          <orderedlist>
            <listitem>
              <para>After choosing the <guilabel>1st</guilabel> and
              <guilabel>2nd</guilabel> files, click
              <guibutton>Select</guibutton> next to the
              <guilabel>Filter</guilabel> field.</para>
            </listitem>

            <listitem>
              <para>In the Filters dialog, use the Line Filters tab to enable the
              line filters you want to use (if any), or to see what line filters
              are currently enabled.</para>

              <note>
                <para>The <guilabel>Filter</guilabel> field does not indicate
                what line filters are enabled.</para>
              </note>
              <para></para>
            </listitem>

            <listitem>
              <para>Proceed with the file compare operation. The enabled line
              filters are applied when you start the operation.</para>
            </listitem>
          </orderedlist>
        </listitem>

        <listitem>
          <para>After you have already launched a file compare operation (for
          example, to apply different filters or disabling filtering)</para>

          <orderedlist>
            <listitem>
              <para>Click <menuchoice>
                  <guimenu>Tools</guimenu>

                  <guimenuitem>Filters</guimenuitem>
                </menuchoice>.</para>
            </listitem>

            <listitem>
              <para>Open the File Filters tab.</para>
            </listitem>

            <listitem>
              <para>Check the individual line filters you want to apply, and
              uncheck filters that you don't want to apply.</para>

              <para>You can also add, edit, and remove filters from the list by
              using the <guibutton>New</guibutton>, <guibutton>Edit</guibutton>,
              and <guibutton>Remove</guibutton> buttons.</para>
            </listitem>

            <listitem>
              <para>To turn on line filtering, check the <guilabel>Enable Line
              Filters</guilabel>. To turn line filtering off, uncheck the
              option.</para>
            </listitem>

            <listitem>
              <para>Click <guibutton>OK</guibutton> to dismiss the File Filters
              dialog.</para>
            </listitem>

            <listitem>
              <para>Click <keycap>F5</keycap> to apply your changes and refresh
              the File Compare window.</para>
            </listitem>
          </orderedlist>
        </listitem>
      </itemizedlist>
    </section>

    <section id="Filters_LineFilterSyntax">
      <title>Line filter syntax<indexterm>
          <primary>rules</primary>

          <secondary>line filter</secondary>
        </indexterm><indexterm>
          <primary>filters</primary>

          <secondary>line</secondary>
        </indexterm><indexterm>
          <primary>regular expressions</primary>

          <secondary>in line filters</secondary>
        </indexterm></title>

      <para>A line filter is a rule that is evaluated against each single-line
      difference in your compared files, if line filter rules are enabled. When
      a rule matches a single-line difference, the difference is ignored.</para>

      <para>Ignored differences are marked in the File Compare window with the
      <guilabel>Ignored Difference</guilabel> color (as defined in the Colors
      page of WinMerge Options). This enables you to distinguish ignored
      differences from other types. However, you cannot select or merge ignored
      difference.</para>

      <para>Line filter matching can be described in terms of two ideas:</para>

      <itemizedlist>
        <listitem>
          <para>When a rule matches any part of the line, the entire difference
          is ignored. Therefore, you cannot filter just part of a line. For
          example, suppose two files have the following single-line
          difference:</para>

          <formalpara>
            <title>File1:</title>

            <para><screen># Jean Sibelius</screen></para>
          </formalpara>

          <formalpara>
            <title>File2:</title>

            <para><screen># Janne Sibelius</screen></para>
          </formalpara>

          <para>With no filtering, the line is detected as a difference. But if
          we apply a line filter rule with the expression, <code>^#</code>, the
          lines are reported as identical, because the expression specifies only
          the first character, which matches in both files.</para>
        </listitem>

        <listitem>
          <para>A rule is applied to a multi-line difference only if all the
          lines match. For example, consider this two-line difference:</para>

          <formalpara>
            <title>File1:</title>

            <para><screen># Jean Sibelius
# Pekka Himanen</screen></para>
          </formalpara>

          <formalpara>
            <title>File2:</title>

            <para><screen># Janne Sibelius
Pekka Himanen</screen></para>
          </formalpara>

          <para>The same <code>^#</code> rule matches the first line, but not
          the second line. Therefore, the difference is not ignored.</para>
        </listitem>
      </itemizedlist>

      <tip>
        <para>It's usually good practice to use the beginning of line (
        <code>^</code> ) and end of line ( <code>$</code> ) markers to
        control your patterns precisely, because the rule is applied if any part
        of a line matches the expression.</para>
      </tip>

      <example>
        <title>Sample line filters</title>

        <screen format="linespecific">^MYTAG$</screen>

        <para>Filters lines that exactly match <literal>MYTAG</literal></para>

        <screen format="linespecific">^::</screen>

        <para>Filters lines beginning with <literal>::</literal></para>

        <screen format="linespecific">^/\*.*\*/$</screen>

        <para>Filters lines beginning with
        <literal><constant>/*</constant></literal> and ending with
        <literal>*/</literal></para>

        <screen format="linespecific">^[1-5]00</screen>

        <para>Filters lines beginning with numbers 100, 200, 300, 400, and
        500</para>
      </example>

      <example>
        <title>Line filter rule matching CVS Id lines</title>

        <para>CVS Id lines look like this:</para>

        <screen>// $Id: Filters.xml 7591 2013-01-20 15:47:42Z christianlist $</screen>

        <para>... and can be filtered with this rule:</para>

        <screen>^// \WId: .*\$</screen>
      </example>

      <example>
        <title>Filter line number comments in po files</title>

        <para>po line number comments look like this:</para>

        <screen>#: src/filename.c:766</screen>

        <para>... and can be filtered with this rule:</para>

        <screen>^#</screen>
      </example>
    </section>
  </section>

  <section id="Filters_DisplayLineFilter">
    <title>Using the display line filter<indexterm>
        <primary>display line filter</primary>
      </indexterm></title>

    <para>The display line filter controls which lines are visible in the
    File Compare window. Lines that do not match the filter are hidden, but
    the comparison result itself is not affected.</para>

    <section id="Filters_DisplayLineFilterApply">
      <title>Opening the display filter bar</title>

      <para>Use any of the following methods to open the display filter
      bar:</para>

      <itemizedlist>
        <listitem>
          <para>Click <menuchoice>
              <guimenu>View</guimenu>
              <guimenuitem>Display Filter Bar</guimenuitem>
            </menuchoice>, or press
            <keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap>
            <keycap>L</keycap></keycombo>.</para>
        </listitem>
        <listitem>
          <para>Right-click selected text in the File Compare window and
          choose <menuchoice>
              <guimenu>Add to Filters</guimenu>
              <guimenuitem>Add to Display Filters</guimenuitem>
            </menuchoice>. WinMerge automatically builds a
            <literal>Line contains "..."</literal> expression from the
            selected text and opens the filter bar.</para>
        </listitem>
      </itemizedlist>

      <para>To remove the filter, clear the input field and press
      <keycap>Enter</keycap>. To hide the filter bar while keeping the filter 
      active, click the close button.</para>
    </section>

    <section id="Filters_DisplayLineFilterInput">
      <title>Entering a filter</title>

      <para>The display filter bar accepts input in two forms, determined
      by whether the input starts with the <literal>le:</literal>
      prefix:</para>

      <variablelist>
        <varlistentry>
          <term>Plain string (no prefix)</term>
          <listitem>
            <para>Input without the <literal>le:</literal> prefix is treated
            as a literal string. WinMerge shows only lines that contain that
            string. Internally, the input is equivalent to
            <literal>le:Line contains "<replaceable>input</replaceable>"</literal>.</para>
            <para>Example: entering <userinput>TODO</userinput> shows all
            lines that contain the text <literal>TODO</literal>.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><literal>le:</literal> prefix (filter expression)</term>
          <listitem>
            <para>If the input starts with <literal>le:</literal>, the
            remainder is interpreted as a filter expression. The full
            expression syntax described in
            <xref linkend="Filters_DisplayLineFilter_Syntax"/> is
            available.</para>
            <para>Example: <userinput>le:Different and Line contains "ERROR"</userinput></para>

            <important>
              <para>The <literal>le:</literal> prefix must appear at the
              very beginning of the input. If it appears anywhere else, the
              entire input is treated as a plain string.</para>
              <para>For example, <userinput>Hello or le:Line contains "Hello"</userinput>
              does <emphasis>not</emphasis> contain a filter expression.
              The whole input is treated as a literal string search for
              the text <literal>Hello or le:Line contains "Hello"</literal>.</para>
            </important>
          </listitem>
        </varlistentry>
      </variablelist>
    </section>

    <section id="Filters_DisplayLineFilter_Syntax">
      <title>Filter expression syntax</title>

      <para>Display line filter expressions use the same engine as folder
      compare filter expressions (see <xref linkend="FilterExpression_Syntax"/>),
      with the following additional attributes and functions that operate
      on individual lines.</para>

      <section id="Filters_DisplayLineFilter_Attrs">
        <title>Line attributes</title>

        <para>Attributes marked as supporting side-specific prefixes accept
        <literal>Left</literal>, <literal>Middle</literal>, and
        <literal>Right</literal> prefixes (e.g.,
        <literal>LeftLine</literal>, <literal>RightLineLength</literal>).
        Attributes without a prefix evaluate across all panes.</para>

        <variablelist>
          <varlistentry>
            <term><varname>Line</varname></term>
            <listitem><para>Text content of the current line.
            Supports side-specific prefixes.
            Example: <literal>Line contains "TODO"</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>LineLength</varname></term>
            <listitem><para>Length of the current line in characters.
            Supports side-specific prefixes.
            Example: <literal>LineLength &gt; 120</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>LineNumber</varname></term>
            <listitem><para>Real line number in the file (1-based),
            not counting ghost lines.
            Supports side-specific prefixes.
            Example: <literal>LineNumber &lt;= 50</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>ViewLineNumber</varname></term>
            <listitem><para>Display line number including ghost lines
            (1-based). Global attribute (no side prefix).
            Example: <literal>ViewLineNumber &lt;= 100</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Different</varname></term>
            <listitem><para>True if the line is part of a difference block.
            Global attribute.
            Example: <literal>Different</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Identical</varname></term>
            <listitem><para>True if the line is identical across all panes.
            Global attribute.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Trivial</varname></term>
            <listitem><para>True if the line differs only in whitespace or
            other ignored content. Global attribute.
            Example: <literal>Different or Trivial</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Exists</varname></term>
            <listitem><para>True if the line exists in the pane (not a ghost
            line). Supports side-specific prefixes.
            Example: <literal>LeftExists and not RightExists</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Missing</varname></term>
            <listitem><para>True if the line is a ghost line in the pane.
            The opposite of <varname>Exists</varname>.
            Supports side-specific prefixes.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Moved</varname></term>
            <listitem><para>True if the line is detected as a moved line.
            Supports side-specific prefixes.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Bookmarked</varname></term>
            <listitem><para>True if the line has a bookmark.
            Supports side-specific prefixes.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>DifferentLeftMiddle</varname>,
            <varname>DifferentMiddleRight</varname>,
            <varname>DifferentLeftRight</varname></term>
            <listitem><para>True if the indicated pair of panes differs on
            this line. 3-way comparisons only (except
            <varname>DifferentLeftRight</varname> which also works in 2-way).
            Global attributes.
            Example: <literal>DifferentLeftMiddle and not DifferentMiddleRight</literal>
            </para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>EOL</varname></term>
            <listitem><para>End-of-line style for the current line as an integer value.
            Supports side-specific prefixes.
            Values: 0 = None, 1 = LF, 2 = CR, 3 = CRLF
            Example: <literal>le:EOL = 3</literal> shows only lines with CRLF endings</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>EOLStr</varname></term>
            <listitem><para>End-of-line style for the current line as a string.
            Supports side-specific prefixes.
            Values: "None", "LF", "CR", "CRLF"
            Example: <literal>le:EOLStr = "LF"</literal> shows only lines with LF endings</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><varname>Column</varname>, <varname>ColumnCount</varname>
            (table mode only)</term>
            <listitem><para>Cell content and column count in CSV/table mode.
            Support side-specific prefixes.
            Example: <literal>Column("Status") = "FAIL"</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>LineAt</function>(<replaceable>lineNumber</replaceable>),
            <function>LineOffsetAt</function>(<replaceable>offset</replaceable>)</term>
            <listitem><para>Text of the line at an absolute line number or
            at a relative offset from the current line.
            Supports side-specific prefix functions.
            Example: <literal>le:Different and RightLineOffsetAt(-1) matches "^//"</literal>
            </para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>Column</function>(<replaceable>indexOrName</replaceable>),
            <function>ColumnAt</function>(<replaceable>line</replaceable>, <replaceable>indexOrName</replaceable>),
            <function>ColumnOffsetAt</function>(<replaceable>offset</replaceable>, <replaceable>indexOrName</replaceable>)
            (table mode only)</term>
            <listitem><para>Cell content by index or name, at the current,
            absolute, or relative line.
            Example: <literal>le:RightColumn("Category") != ColumnOffsetAt(-1, "Category")</literal>
            </para></listitem>
          </varlistentry>
        </variablelist>
      </section>

      <section id="Filters_DisplayLineFilter_Funcs">
        <title>Line functions</title>

        <para>
          Display line filter expressions can also use functions described in
          <xref linkend="FilterExpression_Functions"/>.
        </para>

        <variablelist>
          <varlistentry>
            <term><function>matchContext</function>(<replaceable>expr</replaceable>,
            <replaceable>linesBefore</replaceable>,
            <replaceable>linesAfter</replaceable>)</term>
            <listitem><para>True if the current line is within
            <replaceable>linesBefore</replaceable> lines before or
            <replaceable>linesAfter</replaceable> lines after any line
            matching <replaceable>expr</replaceable>.
            Example: <literal>le:matchContext(Different, 3, 3)</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchNumber</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>1-based index of the current line within all
            matching lines. Returns <literal>none</literal>if the line does not match.
            Example: <literal>le:matchNumber(Different) = 1</literal>
            shows only the first line that matches (the first difference line).</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchCount</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>Total number of lines matching
            <replaceable>expr</replaceable> across the whole file.
            Example: <literal>le:matchNumber(Different) = matchCount(Different)</literal>
            shows only the last line that matches (the last difference line).</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchBlockNumber</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>Returns the 1-based block number of the matching block
            containing the current line. Returns <literal>none</literal> if the current
            line is not in any matching block.
            Example: <literal>le:matchBlockNumber(Different) = 1</literal>
            shows only lines in the first difference block.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchBlockOffset</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>Returns the 1-based offset of the current line within
            the matching block. Returns <literal>none</literal> if the current
            line is not in any matching block.
            Example: <literal>le:matchBlockOffset(Different) = 1</literal>
            shows only the first line of each difference block.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchBlockSize</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>Returns the size (number of lines) of the matching block
            containing the current line. Returns <literal>none</literal> if the current
            line is not in any matching block.
            Example: <literal>le:matchBlockSize(Different) &gt; 5</literal>
            shows only lines in difference blocks larger than 5 lines.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchBlockCount</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>Total number of matching blocks in the file.
            Example: <literal>le:matchBlockNumber(Different) = matchBlockCount(Different)</literal>
            shows only lines in the last difference block.</para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchDistance</function>(<replaceable>expr</replaceable>),
            <function>matchDistanceBefore</function>(<replaceable>expr</replaceable>),
            <function>matchDistanceAfter</function>(<replaceable>expr</replaceable>)</term>
            <listitem><para>Distance in lines to the nearest matching range
            (both directions, before only, or after only).
            Example: <literal>le:matchDistance(Different) &lt;= 5</literal></para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>matchInside</function>(<replaceable>beginExpr</replaceable>,
            <replaceable>endExpr</replaceable>)</term>
            <listitem><para>True if the current line falls between a line
            matching <replaceable>beginExpr</replaceable> and the next line
            matching <replaceable>endExpr</replaceable> (inclusive).
            Example: <literal>le:matchInside(Line matches "^#ifdef", Line matches "^#endif")</literal>
            </para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>average</function>(<replaceable>expr</replaceable>),
            <function>average</function>(<replaceable>expr</replaceable>, <replaceable>condition</replaceable>)</term>
            <listitem><para>Calculates the average (arithmetic mean) of numeric values
            produced by evaluating <replaceable>expr</replaceable> for all lines in the file.
            If <replaceable>condition</replaceable> is provided, only lines where
            <replaceable>condition</replaceable> evaluates to true are included in the calculation.
            Non-numeric results are ignored. Returns <literal>none</literal>if no numeric values are found.
            Example: <literal>le:toInt(Column("Price")) &gt; average(toInt(Column("Price")))</literal>
            shows rows where the price exceeds the average price.
            Example with condition: <literal>le:average(toInt(Column("Score")), Column("Status") = "PASS")</literal>
            calculates the average score for rows with status "PASS".
            </para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>maximum</function>(<replaceable>expr</replaceable>),
            <function>maximum</function>(<replaceable>expr</replaceable>, <replaceable>condition</replaceable>)</term>
            <listitem><para>Returns the maximum value among all results produced by evaluating
            <replaceable>expr</replaceable> for all lines in the file.
            If <replaceable>condition</replaceable> is provided, only lines where
            <replaceable>condition</replaceable> evaluates to true are considered.
            Works with numeric values, strings (alphabetical comparison), and timestamps.
            Returns <literal>none</literal>if no values are found.
            Example: <literal>le:toInt(Column("Quantity")) = maximum(toInt(Column("Quantity")))</literal>
            shows rows with the highest quantity.
            </para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>minimum</function>(<replaceable>expr</replaceable>),
            <function>minimum</function>(<replaceable>expr</replaceable>, <replaceable>condition</replaceable>)</term>
            <listitem><para>Returns the minimum value among all results produced by evaluating
            <replaceable>expr</replaceable> for all lines in the file.
            If <replaceable>condition</replaceable> is provided, only lines where
            <replaceable>condition</replaceable> evaluates to true are considered.
            Works with numeric values, strings (alphabetical comparison), and timestamps.
            Returns <literal>none</literal>if no values are found.
            Example: <literal>le:Column("Status") = minimum(Column("Status"))</literal>
            shows rows with the alphabetically first status value.
            </para></listitem>
          </varlistentry>
          <varlistentry>
            <term><function>sum</function>(<replaceable>expr</replaceable>),
            <function>sum</function>(<replaceable>expr</replaceable>, <replaceable>condition</replaceable>)</term>
            <listitem><para>Calculates the sum of all numeric values produced by evaluating
            <replaceable>expr</replaceable> for all lines in the file.
            If <replaceable>condition</replaceable> is provided, only lines where
            <replaceable>condition</replaceable> evaluates to true are included in the calculation.
            Non-numeric results are ignored. Returns <literal>none</literal>if no numeric values are found.
            Example: <literal>le:toInt(Column("Quantity")) / sum(toInt(Column("Quantity"))) * 100</literal>
            calculates each row's percentage of the total quantity.
            Example with condition: <literal>le:sum(toInt(Column("Sales")), Column("Region") = "East")</literal>
            calculates total sales for the "East" region.
            </para></listitem>
          </varlistentry>
        </variablelist>
      </section>

      <section id="Filters_DisplayLineFilter_Examples">
        <title>Examples</title>

        <informaltable>
          <tgroup cols="2">
            <thead>
              <row>
                <entry>Input</entry>
                <entry>Effect</entry>
              </row>
            </thead>
            <tbody>
              <row>
                <entry><userinput>TODO</userinput></entry>
                <entry>Shows lines containing the text "TODO" (plain string)</entry>
              </row>
              <row>
                <entry><userinput>le:Different</userinput></entry>
                <entry>Shows only lines in difference blocks</entry>
              </row>
              <row>
                <entry><userinput>le:Different or Trivial</userinput></entry>
                <entry>Shows all differences, including ignored differences</entry>
              </row>
              <row>
                <entry><userinput>le:matchContext(Different, 3, 3)</userinput></entry>
                <entry>Shows difference blocks with 3 lines of context on each side</entry>
              </row>
              <row>
                <entry><userinput>le:matchNumber(Different) = 1</userinput></entry>
                <entry>Shows only the first difference line</entry>
              </row>
              <row>
                <entry><userinput>le:matchBlockNumber(Different) &lt;= 3</userinput></entry>
                <entry>Shows only lines in the first 3 difference blocks</entry>
              </row>
              <row>
                <entry><userinput>le:matchBlockOffset(Different) = 1</userinput></entry>
                <entry>Shows only the first line of each difference block</entry>
              </row>
              <row>
                <entry><userinput>le:matchBlockSize(Different) &gt; 10</userinput></entry>
                <entry>Shows only lines in difference blocks larger than 10 lines</entry>
              </row>
              <row>
                <entry><userinput>le:Different and Line contains "ERROR"</userinput></entry>
                <entry>Shows lines that are both different and contain "ERROR"</entry>
              </row>
              <row>
                <entry><userinput>le:strFind(Line, "TODO") &lt; 10</userinput></entry>
                <entry>Shows lines where "TODO" appears within the first 10 characters</entry>
              </row>
              <row>
                <entry><userinput>le:regexFind(Line, "\d{4}") != none</userinput></entry>
                <entry>Shows lines containing a 4-digit number</entry>
              </row>
              <row>
                <entry><userinput>le:matchContext(Bookmarked, 2, 2)</userinput></entry>
                <entry>Shows bookmarked lines with 2 lines of context</entry>
              </row>
              <row>
                <entry><userinput>le:LineNumber &lt;= 50</userinput></entry>
                <entry>Shows only the first 50 lines</entry>
              </row>
              <row>
                <entry><userinput>le:EOL = 3</userinput></entry>
                <entry>Shows only lines with CRLF (Windows) line endings</entry>
              </row>
              <row>
                <entry><userinput>le:EOLStr = "LF"</userinput></entry>
                <entry>Shows only lines with LF (Unix) line endings</entry>
              </row>
              <row>
                <entry><userinput>le:allof(EOL = 1)</userinput></entry>
                <entry>Shows lines where all panes use LF line endings</entry>
              </row>
              <row>
                <entry><userinput>le:toInt(Column("Count")) &gt; 100</userinput></entry>
                <entry>Shows rows where the "Count" column value exceeds 100 (table mode)</entry>
              </row>
            </tbody>
          </tgroup>
        </informaltable>
      </section>
    </section>
  </section>

  <section id="Filters_DisplayFileFolderFilter">
    <title>Using the display file/folder filter<indexterm>
        <primary>display file/folder filter</primary>
      </indexterm></title>

    <para>The display file/folder filter in the Folder Compare window works the same way as
    the display line filter in the File Compare window, but operates on files and folders
    instead of lines. It controls which items are visible without affecting the comparison result.</para>

    <para>To open the display filter bar, click <menuchoice>
        <guimenu>View</guimenu>
        <guimenuitem>Display Filter Bar</guimenuitem>
      </menuchoice>, or press
      <keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap>
      <keycap>L</keycap></keycombo>.</para>

    <para>The filter bar accepts the same syntax as the <guilabel>Filter</guilabel> field
    in the Select Files or Folders dialog. See <xref linkend="Filters_MaskSyntax"/> and
    <xref linkend="FilterExpression_Syntax"/> for details.</para>

    <para>To remove the filter, clear the input field and press
    <keycap>Enter</keycap>. To hide the filter bar while keeping the filter 
    active, click the close button.</para>

    <para>Examples:</para>
    <itemizedlist>
      <listitem><para><userinput>*.cpp;*.h</userinput> - shows C++ source and header files</para></listitem>
      <listitem><para><userinput>!.git\;!.vs\</userinput> - excludes .git and .vs folders</para></listitem>
      <listitem><para><userinput>fe:Different</userinput> - shows only different files</para></listitem>
      <listitem><para><userinput>de:Items &gt; 10</userinput> - shows folders with more than 10 items</para></listitem>
      <listitem><para><userinput>e:Date &gt; today() - 7days</userinput> - shows items modified within the last week</para></listitem>
    </itemizedlist>
  </section>

  <section id="Filters_SubstitutionFilter">
    <title>Using substitution filters<indexterm>
        <primary>filters</primary>

        <secondary>substitution</secondary>
      </indexterm><indexterm>
        <primary>filters</primary>

        <secondary>in file comparisons</secondary>
      </indexterm></title>

    <para>TBD</para>
  </section>

  <section id="Filters_dlg">
    <title>Using the Filters dialog<indexterm>
        <primary>Filters dialog</primary>
      </indexterm><indexterm>
        <primary>filters</primary>

        <secondary>managing and enabling</secondary>
      </indexterm></title>

    <para>This section describes the Filters dialog, which provides functions to
    create and manage file filters and line filters.</para>

    <para>To open the Filters dialog, use either of these methods:</para>

    <itemizedlist>
      <listitem>
        <para>In the Select Files or Folders dialog, click
        <guibutton>Select</guibutton> to the right of the
        <guilabel>Filter</guilabel> field. You use this method when you want to
        apply a file filter to a folder compare operation.</para>
      </listitem>

      <listitem>
        <para>Click <menuchoice>
            <guimenu>Tools</guimenu>

            <guimenuitem>Filters</guimenuitem>
          </menuchoice>. This method can be used at any time except when the
        Select Files or Folders dialog is open.</para>
      </listitem>
    </itemizedlist>

    <para>The Filters dialog has a tab for each type of WinMerge filter:</para>

    <variablelist>
      <varlistentry>
        <term>File Filters</term>

        <listitem>
          <para>Choose this tab to work with file filters for folder compare
          operations.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Line Filters</term>

        <listitem>
          <para>Choose this tab to work with line filters for file compare
          operations.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Substitution Filters</term>

        <listitem>
          <para>Choose this tab to work with substitution filters for file compare
          operations.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Display Line Filter</term>

        <listitem>
          <para>The display line filter is not configured through this dialog.
          Open it via <menuchoice><guimenu>View</guimenu>
          <guimenuitem>Display Filter Bar</guimenuitem></menuchoice>.
          See <xref linkend="Filters_DisplayLineFilter"/>.</para>
        </listitem>
      </varlistentry>
    </variablelist>

    <section id="Filters_FileFiltersTab">
      <title>Using the File Filters tab<indexterm>
          <primary>file filters</primary>

          <secondary>enabling</secondary>
        </indexterm></title>

      <para>The main part of this tab is a list of file filters that are
      available for folder compare operations. The list includes shared,
      private, and installed file filters that WinMerge knows about, as
      described in <xref linkend="Filters_FileFilterLoc" />.</para>

      <section id="Filters_FileFilterEnabling">
        <title>Enabling and disabling file filters</title>

        <para>You must enable a file filter to make it available in a folder
        comparison operation, or to disable a current filter to stop it from
        being used:</para>

        <orderedlist>
          <listitem>
            <para>Open the Filters dialog, if it is not already open.</para>
          </listitem>

          <listitem>
            <para>Select a file filter or
            <guimenuitem>&lt;None&gt;</guimenuitem> from the list.</para>
          </listitem>

          <listitem>
            <para>Click <guibutton>OK</guibutton> to dismiss the Filters
            dialog.</para>
          </listitem>
        </orderedlist>

        <para>There are several ways to apply file filters after enabling them.
        For details, see <xref linkend="Filters_FileFilterApply" />.</para>
      </section>

      <section id="Filters_FileFilterCfg">
        <title>Configuring file filters</title>

        <para>Use these buttons to manage your <guilabel>File Filters</guilabel>
        list and create new file filters:</para>

        <variablelist>
          <varlistentry>
            <term>Test</term>

            <listitem>
              <para>Select a file filter in the list and click
              <guibutton>Test</guibutton> to quickly see how the filter works.
              See <xref linkend="Filters_TestingDlg" /> for details.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Install</term>

            <listitem>
              <para>Enables you to locate a file filter and adds it to the
              Filters list. File filters that are not in either the shared or
              default private folder are not detected unless you install
              them.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>New</term>

            <listitem>
              <para>Creates a new copy of a file template in either the shared
              or private filter folders, and opens it in your default editor.
              Edit the template and add your rules, as described in <xref
              linkend="Filters_CreatingFile" />.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Edit</term>

            <listitem>
              <para>Select a file filter in the list and click
              <guibutton>Edit</guibutton> to open the file in your default
              editor.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Delete</term>

            <listitem>
              <para>Select a file filter in the list and click
              <guibutton>Delete</guibutton> to delete the file and remove it
              from the list. Yes, the file is really deleted!</para>
            </listitem>
          </varlistentry>
        </variablelist>

        <para>Your changes are saved when you click <guibutton>OK</guibutton> to
        dismiss the Filters dialog. Line filters are stored in the Windows
        registry.</para>
      </section>

      <section id="Filters_CreatingFile">
        <title>Creating a file filter</title>

        <para>If the file filters that are installed with WinMerge do not
        provide the filtering you need, you can create your own:</para>

        <orderedlist>
          <listitem>
            <para>Click <menuchoice>
                <guimenu>Tools</guimenu>

                <guimenuitem>Filters</guimenuitem>
              </menuchoice>. Or, from the Select Files or Folders dialog, click
            <guibutton>Select</guibutton> to the right of the
            <guilabel>Filter</guilabel> field.</para>
          </listitem>

          <listitem id="Filters_New_step">
            <para>In the Filters dialog File Filters tab, click
            <guibutton>New</guibutton>.</para>
          </listitem>

          <listitem>
            <para>In the Shared or Private Filter dialog, choose
            <guilabel>Shared Filter</guilabel> or <guilabel>Private
            Filter</guilabel> (see <xref linkend="Filters_FileFilterLoc" /> for
            their uses) and click <keycap>OK</keycap>.</para>

            <para>The Select Filename for New Filter dialog opens in the shared
            or private files folder on your system (if the private folder does
            not exist, WinMerge creates it).</para>
          </listitem>

          <listitem>
            <para>In the Select Filename for New Filter dialog, enter a new file
            name and click <guibutton>Save</guibutton>.</para>

            <note>
              <para>Don't choose an existing file name: to edit an existing
              file, go back to Step <xref linkend="Filters_New_step" /> and
              click Edit instead of New.</para>
            </note>

            <para>WinMerge initializes the new file with the contents of the
            <filename>FileFilter.tmpl</filename> template, and opens it in your
            default text editor.</para>
          </listitem>

          <listitem>
            <para>Follow the template instructions to edit the template,
            updating the placeholder name and description and adding filter
            rules as described in <xref linkend="Filters_FileFilterSyntax" />.
            Save the file in your text editor.</para>

            <tip>
              <para>If you want to quickly test a rule that you are defining,
              try clicking Test in the Filters dialog. See <xref
              linkend="Filters_TestingDlg" /> for details.</para>
            </tip>
            <para></para>
          </listitem>

          <listitem>
            <para>If you created your file filter in one of the standard
            <filename>Filters</filename> folders, and the Filters dialog does
            not list your new file filter, try clicking
            <guibutton>OK</guibutton> to close it, then click <menuchoice>
                <guimenu>Tools</guimenu>

                <guimenuitem>Filters</guimenuitem>
              </menuchoice> again to reopen it. The
            <guilabel>File Filters</guilabel> list should now include the new
            file filter.</para>

            <para>If you saved the file in an alternate location on your file
            system), WinMerge cannot detect it unless you install it. To make a
            file filter detectable anywhere on your system:</para>

            <orderedlist numeration="loweralpha">
              <listitem>
                <para>Click <guibutton>Install</guibutton> in the Filters
                dialog.</para>
              </listitem>

              <listitem>
                <para>In the Locate Filter File to Install dialog, navigate to
                the <filename>flt</filename> file on your system, and click
                <guibutton>Open</guibutton>. The File Filters list should now
                include the installed file filter.</para>
              </listitem>
            </orderedlist>
          </listitem>
        </orderedlist>
      </section>

      <section id="Filters_TestingDlg">
        <title>Testing file filter rules<indexterm>
            <primary>file filters</primary>

            <secondary>testing</secondary>
          </indexterm><indexterm>
            <primary>testing file filters</primary>
          </indexterm></title>

        <para>Use the Test Filter dialog to quickly test a file filter against
        sample data, to help you develop new rules or to understand how existing
        rules work. It can be easier than running a full compare
        operation.</para>

        <para>Starting from the Filters dialog:</para>

        <orderedlist>
          <listitem>
            <para>In the File Filters tab, choose the file filter you want to
            test.</para>
          </listitem>

          <listitem>
            <para>If you want to see the rules you will be testing, click
            <guibutton>Edit</guibutton> now to open the file so that you can
            view it during the next steps.</para>
          </listitem>

          <listitem>
            <para>Click <guibutton>Test</guibutton>.</para>
          </listitem>

          <listitem>
            <para>In the Test Filter dialog, choose the type of rule to
            test:</para>

            <itemizedlist>
              <listitem>
                <para>To test an <guilabel>f:</guilabel> file rule in your file
                filter, uncheck the <guilabel>Folder Name</guilabel>
                option.</para>
              </listitem>

              <listitem>
                <para>To test a <guilabel>d:</guilabel> folder rule, check the
                <guilabel>Folder Name</guilabel> option.</para>
              </listitem>
            </itemizedlist>
          </listitem>

          <listitem>
            <para>Enter the text to test.</para>

            <para>The text should be appropriate for the type of rule you are
            testing. For example, if you have checked the <guilabel>Folder
            Name</guilabel> option, you probably want to enter a folder name,
            such as \temp.</para>

            <para>The <guilabel>Result</guilabel> box displays your entry,
            followed by its status: either
            <computeroutput>passed</computeroutput> or
            <computeroutput>failed</computeroutput>.</para>
          </listitem>
        </orderedlist>
      </section>
    </section>

    <section id="Filters_LineFiltersTab">
      <title>Using the Line Filters tab<indexterm>
          <primary>line filters</primary>

          <secondary>enabling</secondary>
        </indexterm></title>

      <para>Use this tab to configure and enable line filters for file compare
      operations. The tab features a list of rules. Each rule contains a single
      regular expression. You can apply any combination of rules from the list
      to a file comparison.</para>

      <section id="Filters_LineFilterCfg">
        <title>Configuring line filters</title>

        <para>Below the <guilabel>Regular Expressions</guilabel> list is an edit
        box and buttons that you can use to maintain the list at any time by
        adding, editing, and removing rules.</para>

        <para>To add a new rule:</para>

        <orderedlist>
          <listitem>
            <para>Click <guibutton>New</guibutton>. Your edit cursor is
            automatically enabled in the edit box.</para>
          </listitem>

          <listitem>
            <para>Enter an expression in the edit box below the
            <guilabel>Regular Expressions</guilabel> list.</para>
          </listitem>

          <listitem>
            <para>Click <guibutton>Save</guibutton> to load the expression in a
            new line in the list.</para>
          </listitem>
        </orderedlist>

        <para>To edit an existing rule:</para>

        <orderedlist>
          <listitem>
            <para>Select the line and click <guibutton>Edit</guibutton>.</para>
          </listitem>

          <listitem>
            <para>Edit the expression in the edit box.</para>
          </listitem>

          <listitem>
            <para>Click <guibutton>Save</guibutton><guibutton> </guibutton>when
            you're done.</para>
          </listitem>
        </orderedlist>

        <para>To delete an existing rule, select (check) the rule and click
        <guibutton>Remove</guibutton>.</para>
      </section>

      <section id="Filters_LineFilterEnabling">
        <title>Enabling and disabling line filters<indexterm>
            <primary>line filters</primary>

            <secondary>list of available</secondary>
          </indexterm></title>

        <orderedlist>
          <listitem>
            <para>In the <guilabel>Regular Expressions</guilabel> list, check
            just the filters that you want to apply, and uncheck any filters you
            do not want to apply.</para>
          </listitem>

          <listitem>
            <para>Check or uncheck the <guilabel>Enable Line Filters</guilabel>
            option. If you turn filtering on, all the rules that are currently
            checked in the <guilabel>Regular Expression</guilabel> list are
            used. If filtering is off, no rules are used even if they are
            checked.</para>
          </listitem>

          <listitem>
            <para>Click <guibutton>OK</guibutton> to dismiss the Filters dialog
            and save your settings.</para>
          </listitem>
        </orderedlist>

        <para>There are several ways to apply file filters after enabling them.
        For details, see <xref linkend="Filters_LineFilterApply" />.</para>
      </section>
    </section>

    <section id="Filters_SubstitutionFiltersTab">
      <title>Using the Substitution Filters tab<indexterm>
          <primary>substitution filters</primary>

          <secondary>enabling</secondary>
        </indexterm></title>

        <para>TBD</para>

      <section id="Filters_SubstitutionFilterCfg">
        <title>Configuring substitution filters</title>

        <para>TBD</para>

      </section>

      <section id="Filters_SubstitutionFilterEnabling">
        <title>Enabling and disabling substitution filters<indexterm>
            <primary>substitution filters</primary>

            <secondary>list of available</secondary>
          </indexterm></title>

        <para>TBD</para>
      </section>
    </section>
  </section>

  <section id="AboutFilters_regexp">
    <title>Getting help with regular expressions<indexterm>
        <primary>regular expressions</primary>

        <secondary>getting help</secondary>
      </indexterm></title>

    <para>Regular expressions can be very complex. Fortunately, most file
    filters in WinMerge involve simple extension expressions, as shown in the
    examples in this topic. The filter files installed with WinMerge include
    many other useful examples.</para>

    <para>Finally, there are lots of resources on the Web for help with regexps,
    including these sites:</para>

    <variablelist>
      <varlistentry>
        <term>Good site devoted to regexps:</term>

        <listitem>
          <simpara><ulink
          url="https://www.regular-expressions.info/">https://www.regular-expressions.info/</ulink></simpara>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Tutorial:</term>

        <listitem>
          <simpara><ulink
          url="http://www.zvon.org/comp/r/tut-Regexp.html">http://www.zvon.org/comp/r/tut-Regexp.html</ulink></simpara>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>PDF quick reference:</term>

        <listitem>
          <simpara><ulink
          url="https://github.com/GordonMcKinney/gist-assets/raw/master/regex.pdf">
          https://github.com/GordonMcKinney/gist-assets/raw/master/regex.pdf</ulink></simpara>
        </listitem>
      </varlistentry>
    </variablelist>
  </section>
</article>
