/******************************************************************************/
/*                                                                            */
/* Highlighter.Drivers.cls - Rexx highlighter driver system                   */
/* ========================================================                   */
/*                                                                            */
/* This program is part of the Rexx Parser package                            */
/* [See https://rexx.epbcn.com/rexx.parser/]                                  */
/*                                                                            */
/* Copyright (c) 2024-2025 Josep Maria Blasco <josep.maria.blasco@epbcn.com>  */
/*                                                                            */
/* License: Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0)  */
/*                                                                            */
/* Version history:                                                           */
/*                                                                            */
/* Date     Version Details                                                   */
/* -------- ------- --------------------------------------------------------- */
/* 20241231    0.1e First version                                             */
/* 20250222    0.2  Add drive to path for requires                            */
/*                                                                            */
/******************************************************************************/

-- We call all the drivers (the .cls files) in our own directory,
-- unless ourselves.

If .environment~Highlighter.Driver == .Nil Then Do
   .environment~Highlighter.Driver =  .Highlighter.Driver
  package    = .context~package
  local      =  package~local
  mypath     =  FileSpec( "Drive", package~name )FileSpec( "Path", package~name )
  myName     =  FileSpec( "Name", package~name )
  drivers    = .File~new(mypath)~list
  Do driver Over drivers
    If driver == myName Then Iterate    -- Don't call ourselves
    If driver~endsWith(".cls") Then     -- Call every driver in turn
      Call (mypath||driver)
  End
End

/******************************************************************************/
/* Base class, should be subclassed by actual drivers                         */
/******************************************************************************/

::Class Highlighter.Driver Public Abstract

-- These two methods are driver-specific, and should be implemented
-- by all subclasses.

::Method Prolog    Abstract
::Method Epilog    Abstract

-- Emit a simple newline by default

::Method startLine
  Use Strict Arg lineNo
  self~say("")

-- Store options. and output

::Method Init
  Expose Options. output

  Use Strict Arg Options., output

  source = Options.!Source

  -- If we are going to print line numbers, we need to compute
  -- the width of the line number area. We use a minimum of
  -- two columns, even in the case that a single digit is enough.
  -- If the user has specified the "numberWidth" option, we use that
  -- value, unless it's incapable to accomodate our numbers.
  -- Otherwise, we use the width of the maximum line number, plus one.

  If options.numberLines Then Do
    nWidth = Max( Length(options.startFrom + source~items - 1), 2) + 1
    If options.numberWidth > nWidth Then nWidth = options.numberWidth
    Options.!numberWidth = nWidth       -- Store in options.
  End

-- Conceptually, this is CHAROUT , Arg(1)

::Method Emit
  Expose output
  output[ output~last ] ||= Arg(1)      -- Collate Arg(1) to the current line

-- Conceptually, this is SAY Arg(1)

::Method Say
  Expose output
  self~emit( Arg(1) )
  output~append("")                     -- Start a new, empty line

-- Used by the terminal and LaTeX highlighter.
-- The HTML Highlighter uses inline <style>s.

::Method tags2highlight
  Expose Options.

  Use Strict Arg tags, extra

  Tag2Attr.  = Options.!Tag2Attr

  attrs      = ""
  color      = ""
  background = ""

  Do tag Over tags~makeArray(" ")
    Parse Value Tag2Attr.tag With attr fg"/"bg
    attrs ||= attr
    If fg \== "" Then color      = fg
    If bg \== "" Then background = bg
  End

  If extra \== "" Then Do
    Parse Value extra With attr fg"/"bg
    attrs ||= attr
    If fg \== "" Then color      = fg
    If bg \== "" Then background = bg
  End

  If background = "" Then Do
    Parse Value Tag2Attr.["rexx"] With "/"background
  End

  bold      = .False
  italic    = .False
  underline = .False

  Do attr Over attrs~makeArray("")
    Select Case attr
      When "B" Then bold      = .True
      When "b" Then bold      = .False
      When "I" Then italic    = .True
      When "i" Then italic    = .False
      When "U" Then underline = .True
      When "u" Then underline = .False
      Otherwise Nop
    End
  End

  Return bold italic underline color"/"background