{Resaltador de sintaxis sencillo usado para el terminal.
 Se basa en el ejemplo de resaltador con plegado publicado en "La Biblia del SynEdit"

                                     Por Tito Hinostroza 27/06/2014
}
unit uResaltTerm;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, Graphics, LCLProc, SynEditHighlighter,
  SynEditHighlighterFoldBase;
type
  {Clase para la creación de un resaltador}
  TRangeState = (rsUnknown, rsComment);
  //ID para categorizar a los tokens
  TtkTokenKind = (tkIndentif,
                  tkComment,
                  tkKey,    //Palabra clave
                  tkError,  //Palabra ERROR.
                  tkWarning,  //Palabra WARNING.
                  tkNull,
                  tkSpace,
                  tkString,
                  tkPrompt,
                  tkUnknown,
                  tkDirect  //Listado de directorio
                  );

  TProcTableProc = procedure of object; //Tipo procedimiento para procesar el
                                        //token por el carácter inicial.
  { TResaltTerm }
  TResaltTerm = class(TSynCustomFoldHighlighter)
  protected
    posIni, posFin: Integer;
    fStringLen: Integer;  //Tamaño del token actual
    fToIdent: PChar;      //Puntero a identificcdor
    linAct   : PChar;
    fProcTable: array[#0..#255] of TProcTableProc; //tabla de procedimientos
    fTokenID : TtkTokenKind;  //Id del token actual
    fRange: TRangeState;
    //define las categorías de los "tokens"
    fAtriIdentif : TSynHighlighterAttributes;
    fAtriComent  : TSynHighlighterAttributes;
    fAtriClave   : TSynHighlighterAttributes;
    fAtriEspac   : TSynHighlighterAttributes;
    fAtriCadena  : TSynHighlighterAttributes;
    fAtriPrompt  : TSynHighlighterAttributes;
    fAtriDirect  : TSynHighlighterAttributes;
    fAtriError   : TSynHighlighterAttributes;
    fAtriWarning : TSynHighlighterAttributes;
  public
    //detecPrompt : boolean;    //Activa la detección del prompt
    //prIni, prFin: string;     //Cadena inicial, y final del prompt { TODO : En teoría no deberían ser necesarias estas variables  }
    curSesObj   : Tobject;    {Referencia a la sesión. Se requiere la sesión, porque cada sesión
                              mantiene su propia configuración de prompt. Se define como
                              TObject para no crear referencias circulares entre las unidades. }
    procedure SetLine(const NewValue: String; LineNumber: Integer); override;
    procedure Next; override;
    function  GetEol: Boolean; override;
    procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
              override;
    function  GetTokenAttribute: TSynHighlighterAttributes; override;
    function GetToken: String; override;
    function GetTokenPos: Integer; override;
    function GetTokenKind: integer; override;
    constructor Create(AOwner: TComponent); override;
    function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes; override;
  private
    posTok     : integer;       //para identificar el ordinal del token en una línea
    procedure CommentProc;
    procedure CreaTablaDeMetodos;
    function KeyComp(const aKey: String): Boolean;
    procedure ProcComent;
    procedure ProcIdent;
    procedure ProcNull;
    procedure ProcSpace;
    procedure ProcString;
    procedure ProcUnknown;

    //Funciones de procesamiento de identificadores
    procedure ProcA;
    procedure ProcB;
    procedure ProcC;
    procedure ProcD;
    procedure ProcE;
    procedure ProcF;
    procedure ProcG;
    procedure ProcH;
    procedure ProcI;
    procedure ProcK;
    procedure ProcJ;
    procedure ProcL;
    procedure ProcM;
    procedure ProcP;
    procedure ProcR;
    procedure ProcS;
    procedure ProcT;
    procedure ProcU;
    procedure ProcV;
    procedure ProcW;
    procedure ProcZ;
  public
    function GetRange: Pointer; override;
    procedure SetRange(Value: Pointer); override;
    procedure ResetRange; override;
  end;


implementation
uses FrameTabSession; //para la detección de prompt
var
  Identifiers: array[#0..#255] of ByteBool;
  curSes: TfraTabSession;

procedure CreaTablaIdentif;
var  i, j: Char;
begin
  for i := #0 to #255 do
  begin
    Case i of
      '_', '0'..'9', 'a'..'z', 'A'..'Z': Identifiers[i] := True;
    else Identifiers[i] := False;
    end;
    j := UpCase(i);
  end;
end;
constructor TResaltTerm.Create(AOwner: TComponent);
//Constructor de la clase. Aquí se deben crear los atributos a usar.
begin
  inherited Create(AOwner);
  //atributo de identificadores
  fAtriIdentif  := TSynHighlighterAttributes.Create('Identif');
  fAtriIdentif.Foreground := clWhite;    //color de letra
  AddAttribute(fAtriIdentif);
  //Atributo de comentarios
  fAtriComent  := TSynHighlighterAttributes.Create('Comment');
//  fAtriComent.Style := [fsItalic];     //en cursiva
  fAtriComent.Foreground := clLtGray;    //color de letra gris
  AddAttribute(fAtriComent);
  //atribuuto de palabras claves
  fAtriClave   := TSynHighlighterAttributes.Create('Key');
  fAtriClave.Style := [fsBold];       //en negrita
  fAtriClave.Foreground:=TColor($40D040);;     //color de letra verde
  AddAttribute(fAtriClave);
  //Atributo de espacios. Sin atributos
  fAtriEspac   := TSynHighlighterAttributes.Create('space');
  AddAttribute(fAtriEspac);
  //Atributo de cadenas
  fAtriCadena  := TSynHighlighterAttributes.Create('String');
  fAtriCadena.Foreground :=  TColor($FFFF00);   //color de letra celeste
  AddAttribute(fAtriCadena);
  //Atributo de prompt
  fAtriPrompt  := TSynHighlighterAttributes.Create('Prompt');
  fAtriPrompt.Foreground := clWhite;   //color de letra
  fAtriPrompt.Background:= clGreen;
  AddAttribute(fAtriPrompt);
  //Atributo de directorio
  fAtriDirect  := TSynHighlighterAttributes.Create('Direct');
  fAtriDirect.Foreground := clYellow;   //color de letra
  AddAttribute(fAtriDirect);

  //Atributo de error
  fAtriError  := TSynHighlighterAttributes.Create('Error');
  fAtriError.Foreground := clRed;   //color de letra
  AddAttribute(fAtriError);

  //Atributo de Advertencia
  fAtriWarning  := TSynHighlighterAttributes.Create('Warning');
  fAtriWarning.Foreground := clYellow;   //color de letra
  AddAttribute(fAtriWarning);

  CreaTablaDeMetodos;  //Construye tabla de métodos
end;
procedure TResaltTerm.CreaTablaDeMetodos;
var
  I: Char;
begin
  for I := #0 to #255 do
    case I of
      '#'    : fProcTable[I] := @ProcComent;
      '"'    : fProcTable[I] := @ProcString;
      'a': fProcTable[I] := @ProcA;
      'b': fProcTable[I] := @ProcB;
      'c': fProcTable[I] := @ProcC;
      'd': fProcTable[I] := @ProcD;
      'e','E': fProcTable[I] := @ProcE;
      'f': fProcTable[I] := @ProcF;
      'g': fProcTable[I] := @ProcG;
      'h': fProcTable[I] := @ProcH;
      'i': fProcTable[I] := @ProcI;
      'j': fProcTable[I] := @ProcJ;
      'k': fProcTable[I] := @ProcK;
      'l': fProcTable[I] := @ProcL;
      'm': fProcTable[I] := @ProcM;
      'n': fProcTable[I] := @ProcIdent;
      'o': fProcTable[I] := @ProcIdent;
      'p': fProcTable[I] := @ProcP;
      'q': fProcTable[I] := @ProcIdent;
      'r': fProcTable[I] := @ProcR;
      's': fProcTable[I] := @ProcS;
      't': fProcTable[I] := @ProcT;
      'u': fProcTable[I] := @ProcU;
      'v': fProcTable[I] := @ProcV;
      'w','W': fProcTable[I] := @ProcW;
      'x': fProcTable[I] := @ProcIdent;
      'y': fProcTable[I] := @ProcIdent;
      'z': fProcTable[I] := @ProcZ;
      'A'..'D','F'..'V','X'..'Z': fProcTable[I] := @ProcIdent;
      #0     : fProcTable[I] := @ProcNull;   //Se lee el caracter de marca de fin de cadena
      #1..#9, #11, #12, #14..#32: fProcTable[I] := @ProcSpace;
      else fProcTable[I] := @ProcUnknown;
    end;
end;
function TResaltTerm.KeyComp(const aKey: String): Boolean;
var
  I: Integer;
  Temp: PChar;
begin
  Temp := fToIdent;
  if Length(aKey) = fStringLen then begin
    Result := True;
    for i := 1 to fStringLen do begin
      if Temp^ <> aKey[i] then begin
        Result := False;
        break;
      end;
      inc(Temp);
    end;
  end else Result := False;
end;
procedure TResaltTerm.ProcComent;
//Procesa el símbolo '#'
begin
  begin
    fTokenID := tkComment;
    inc(PosFin);       //salta a siguiente token
    while not (linAct[PosFin] in [#0, #10, #13]) do Inc(PosFin);
  end;
end;
procedure TResaltTerm.ProcString;
//Procesa el caracter comilla.
begin
  fTokenID := tkString;   //marca como cadena
  Inc(PosFin);
  while (not (linAct[PosFin] in [#0, #10, #13])) do begin
    if linAct[PosFin] = '"' then begin //busca fin de cadena
      Inc(PosFin);
      if (linAct[PosFin] <> '"') then break;  //si no es doble comilla
    end;
    Inc(PosFin);
  end;
end;
procedure TResaltTerm.ProcIdent;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fTokenID := tkIndentif;  //identificador común
end;

procedure TResaltTerm.ProcA;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('lias')     then fTokenID := tkKey else
  if KeyComp('propos')     then fTokenID := tkKey else
  if KeyComp('wk')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcB;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('anner')     then fTokenID := tkKey else
  if KeyComp('reak')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcC;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('al')     then fTokenID := tkKey else
  if KeyComp('aller')     then fTokenID := tkKey else
  if KeyComp('ase')     then fTokenID := tkKey else
  if KeyComp('at')     then fTokenID := tkKey else
  if KeyComp('d')     then fTokenID := tkKey else
  if KeyComp('hgrp')     then fTokenID := tkKey else
  if KeyComp('hmod')     then fTokenID := tkKey else
  if KeyComp('hown')     then fTokenID := tkKey else
  if KeyComp('lear')     then fTokenID := tkKey else
  if KeyComp('mp')     then fTokenID := tkKey else
  if KeyComp('ommand')     then fTokenID := tkKey else
  if KeyComp('ontinue')     then fTokenID := tkKey else
  if KeyComp('p')     then fTokenID := tkKey else
  if KeyComp('rontab')     then fTokenID := tkKey else
  if KeyComp('ut')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcD;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('ate')     then fTokenID := tkKey else
  if KeyComp('eclare')     then fTokenID := tkKey else
  if KeyComp('f')     then fTokenID := tkKey else
  if KeyComp('iff')     then fTokenID := tkKey else
  if KeyComp('ir')     then fTokenID := tkKey else
  if KeyComp('u')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcE;
var
  tok, utok: String;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  tok := GetToken;
  utok := Upcase(GetToken);
  if tok = 'echo'     then fTokenID := tkKey else
  if tok = 'else'     then fTokenID := tkKey else
  if tok = 'env'      then fTokenID := tkKey else
  if utok = 'ERROR'   then fTokenID := tkError else
  if tok = 'eval'     then fTokenID := tkKey else
  if tok = 'exit'     then fTokenID := tkKey else
  if tok = 'export'   then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcF;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('alse')     then fTokenID := tkKey else
  if KeyComp('c')     then fTokenID := tkKey else
  if KeyComp('i')     then fTokenID := tkKey else
  if KeyComp('ile')     then fTokenID := tkKey else
  if KeyComp('ind')     then fTokenID := tkKey else
  if KeyComp('mt')     then fTokenID := tkKey else
  if KeyComp('or')     then fTokenID := tkKey else
  if KeyComp('unction')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcG;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('etopts')     then fTokenID := tkKey else
  if KeyComp('rep')     then fTokenID := tkKey else
  if KeyComp('unzip')     then fTokenID := tkKey else
  if KeyComp('zip')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcH;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('alt')     then fTokenID := tkKey else
  if KeyComp('ash')     then fTokenID := tkKey else
  if KeyComp('ead')     then fTokenID := tkKey else
  if KeyComp('elp')     then fTokenID := tkKey else
  if KeyComp('istory')     then fTokenID := tkKey else
  if KeyComp('ostname')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcI;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('d')     then fTokenID := tkKey else
  if KeyComp('f')     then fTokenID := tkKey else
  if KeyComp('nfo')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcJ;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('obs')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcK;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('ill')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcL;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('dd')     then fTokenID := tkKey else
  if KeyComp('ess')     then fTokenID := tkKey else
  if KeyComp('n')     then fTokenID := tkKey else
  if KeyComp('ocal')     then fTokenID := tkKey else
  if KeyComp('ocate')     then fTokenID := tkKey else
  if KeyComp('ogout')     then fTokenID := tkKey else
  if KeyComp('s')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //sin atributos
end;
procedure TResaltTerm.ProcM;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('ail')     then fTokenID := tkKey else
  if KeyComp('an')     then fTokenID := tkKey else
  if KeyComp('esg')     then fTokenID := tkKey else
  if KeyComp('kdir')     then fTokenID := tkKey else
  if KeyComp('ore')     then fTokenID := tkKey else
  if KeyComp('v')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcP;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('asswd')     then fTokenID := tkKey else
  if KeyComp('r')     then fTokenID := tkKey else
  if KeyComp('rintenv')     then fTokenID := tkKey else
  if KeyComp('rintf')     then fTokenID := tkKey else
  if KeyComp('s')     then fTokenID := tkKey else
  if KeyComp('wd')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcR;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('ead')     then fTokenID := tkKey else
  if KeyComp('eadonly')     then fTokenID := tkKey else
  if KeyComp('eboot')     then fTokenID := tkKey else
  if KeyComp('eset')     then fTokenID := tkKey else
  if KeyComp('eturn')     then fTokenID := tkKey else
  if KeyComp('m')     then fTokenID := tkKey else
  if KeyComp('mdir')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcS;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('ed')     then fTokenID := tkKey else
  if KeyComp('elect')     then fTokenID := tkKey else
  if KeyComp('eq')     then fTokenID := tkKey else
  if KeyComp('et')     then fTokenID := tkKey else
  if KeyComp('h')     then fTokenID := tkKey else
  if KeyComp('hift')     then fTokenID := tkKey else
  if KeyComp('hutdown')     then fTokenID := tkKey else
  if KeyComp('leep')     then fTokenID := tkKey else
  if KeyComp('ort')     then fTokenID := tkKey else
  if KeyComp('pell')     then fTokenID := tkKey else
  if KeyComp('uspend')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcT;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('ac')     then fTokenID := tkKey else
  if KeyComp('ail')     then fTokenID := tkKey else
  if KeyComp('alk')     then fTokenID := tkKey else
  if KeyComp('ar')     then fTokenID := tkKey else
  if KeyComp('est')     then fTokenID := tkKey else
  if KeyComp('hen')     then fTokenID := tkKey else
  if KeyComp('ime')     then fTokenID := tkKey else
  if KeyComp('imes')     then fTokenID := tkKey else
  if KeyComp('ouch')     then fTokenID := tkKey else
  if KeyComp('r')     then fTokenID := tkKey else
  if KeyComp('rap')     then fTokenID := tkKey else
  if KeyComp('rue')     then fTokenID := tkKey else
  if KeyComp('ype')     then fTokenID := tkKey else
  if KeyComp('ypeset')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcU;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('limit')     then fTokenID := tkKey else
  if KeyComp('mask')     then fTokenID := tkKey else
  if KeyComp('nalias')     then fTokenID := tkKey else
  if KeyComp('name')     then fTokenID := tkKey else
  if KeyComp('ncompress')     then fTokenID := tkKey else
  if KeyComp('niq')     then fTokenID := tkKey else
  if KeyComp('nset')     then fTokenID := tkKey else
  if KeyComp('ntil')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcV;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('dir')     then fTokenID := tkKey else
  if KeyComp('i')     then fTokenID := tkKey else
  if KeyComp('im')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcW;
var
  tok, utok: String;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  tok := GetToken;
  utok := Upcase(GetToken);
  if tok = 'wait'     then fTokenID := tkKey else
  if utok = 'WARNING' then fTokenID := tkWarning else
  if tok = 'wc'       then fTokenID := tkKey else
  if tok = 'whatis'   then fTokenID := tkKey else
  if tok = 'wwhence'  then fTokenID := tkKey else
  if tok = 'whereis'  then fTokenID := tkKey else
  if tok = 'which'    then fTokenID := tkKey else
  if tok = 'while'    then fTokenID := tkKey else
  if tok = 'who'      then fTokenID := tkKey else
  if tok = 'whoami'   then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;
procedure TResaltTerm.ProcZ;
begin
  while Identifiers[linAct[posFin]] do inc(posFin);
  fStringLen := posFin - posIni - 1;  //calcula tamaño - 1
  fToIdent := linAct + posIni + 1;  //puntero al identificador + 1
  if KeyComp('cat')     then fTokenID := tkKey else
    fTokenID := tkIndentif;  //identificador común
end;

procedure TResaltTerm.ProcNull;
//Procesa la ocurrencia del caracter #0
begin
  fTokenID := tkNull;   //Solo necesita esto para indicar que se llegó al final de la línae
end;
procedure TResaltTerm.ProcSpace;
//Procesa caracter que es inicio de espacio
begin
  fTokenID := tkSpace;
  repeat
    Inc(posFin);
  until (linAct[posFin] > #32) or (linAct[posFin] in [#0, #10, #13]);
end;
procedure TResaltTerm.ProcUnknown;
begin
  inc(posFin);
  while (linAct[posFin] in [#128..#191]) OR // continued utf8 subcode
   ((linAct[posFin]<>#0) and (fProcTable[linAct[posFin]] = @ProcUnknown)) do inc(posFin);
  fTokenID := tkUnknown;
end;

procedure TResaltTerm.SetLine(const NewValue: String; LineNumber: Integer);
begin
  inherited;
  linAct := PChar(NewValue);  //copia la línea actual
  posFin := 0;                //apunta al primer caracter
  posTok := 0;    //inicia contador de token
  Next;
end;

procedure TResaltTerm.Next;
var
  l: Integer;
begin
  Inc(posTok);  //lleva la cuenta del orden del token
  posIni := PosFin;   //apunta al primer elemento
  //busca prompt en el inicio de la línea
  if (posTok=1) then begin
    //Estamos al inicio
    //verifica si hay prompt
    if TfraTabSession(curSesObj).detecPrompt then begin
      l:= TfraTabSession(curSesObj).ContainsPrompt(linAct);
      if l>0 then begin
        posFin += l;   //pasa a siguiente token
        fTokenID := tkPrompt;  //de tipo prompt
        EndCodeFoldBlock();  //cierra plegado
        StartCodeFoldBlock(nil);  //abre plegado
        exit;
      end;
    end;
    //verifica si es listado detallado de arcchivos "ls -l"
//    tmp := copy(linAct,1,3);
    if length(linAct)>43 then begin //un listado común de archivos tiene al menos este tamaño
      if (linAct[0] = 'd') and
         (linAct[1] in ['r','-']) and (linAct[2] in ['w','-']) then begin
         //es listado detallado de un directorio
         posFin := length(linAct);
         fTokenID := tkDirect;  //de tipo directorio
         exit;
      end;
    end;
  end;
  //caso normal
//  if fRange = rsComment then begin
//     CommentProc
//  end else begin
      fRange := rsUnknown;
      fProcTable[linAct[PosFin]]; //Se ejecuta la función que corresponda.
//  end;
end;

function TResaltTerm.GetEol: Boolean;
{Indica cuando se ha llegado al final de la línea}
begin
  Result := fTokenId = tkNull;
end;

procedure TResaltTerm.GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
{Devuelve información sobre el token actual}
begin
  TokenLength := posFin - posIni;
  TokenStart := linAct + posIni;
end;

function TResaltTerm.GetTokenAttribute: TSynHighlighterAttributes;
//Devuelve información sobre el token actual
begin
  case fTokenID of
    tkIndentif: Result := fAtriIdentif;
    tkComment : Result := fAtriComent;
    tkKey     : Result := fAtriClave;
    tkSpace   : Result := fAtriEspac;
    tkString  : Result := fAtriCadena;
    tkPrompt  : Result := fAtriPrompt;
    tkDirect  : Result := fAtriDirect;
    tkError   : Result := fAtriError;
    tkWarning : Result := fAtriWarning;
    else
      Result := nil;  //tkUnknown, tkNull
  end;
end;
function TResaltTerm.GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
{Este método es llamado por la clase "TSynCustomHighlighter", cuando se accede a alguna de
 sus propiedades:  CommentAttribute, IdentifierAttribute, KeywordAttribute, StringAttribute,
 SymbolAttribute o WhitespaceAttribute.}
begin
  case Index of
    SYN_ATTR_COMMENT   : Result := fAtriComent;
    SYN_ATTR_IDENTIFIER: Result := fAtriIdentif;
    SYN_ATTR_KEYWORD   : Result := fAtriClave;
    SYN_ATTR_WHITESPACE: Result := fAtriEspac;
    SYN_ATTR_STRING    : Result := fAtriCadena;
    else Result := nil;
  end;
end;

{Las siguientes funciones, son usadas por SynEdit para el manejo de las
 llaves, corchetes, parentesis y comillas. No son cruciales para el coloreado
 de tokens, pero deben responder bien.}
function TResaltTerm.GetToken: String;
var
  Len: LongInt;
begin
  Len := posFin - posIni;
  SetString(Result, (linAct + posIni), Len);
end;
function TResaltTerm.GetTokenPos: Integer;
begin
  Result := posIni - 1;
end;
function TResaltTerm.GetTokenKind: integer;
begin
  Result := 0;
end;
procedure TResaltTerm.CommentProc;
begin
  fTokenID := tkComment;
  case linAct[PosFin] of
    #0:
      begin
        ProcNull;
        exit;
      end;
  end;
  while linAct[PosFin] <> #0 do
    case linAct[PosFin] of
      '*':
        if linAct[PosFin + 1] = '/' then
        begin
          inc(PosFin, 2);
          fRange := rsUnknown;
          break;
        end
        else inc(PosFin);
      #10: break;
      #13: break;
    else inc(PosFin);
    end;
end;

///////// Implementación de las funcionalidades de rango //////////
procedure TResaltTerm.ResetRange;
begin
  inherited;
  fRange := rsUnknown;
end;
function TResaltTerm.GetRange: Pointer;
begin
  CodeFoldRange.RangeType := Pointer(PtrInt(fRange));
  Result := inherited;
end;
procedure TResaltTerm.SetRange(Value: Pointer);
begin
  inherited;
  fRange := TRangeState(PtrUInt(CodeFoldRange.RangeType));
end;

initialization
   CreaTablaIdentif;   //Crea la tabla para búsqueda rápida
end.

