Author · forum.lazarus.freepascal.org

This one would be truly useful. I remember suggesting it at 2009 or 2010 but it was rejected immediately.
I have a related feature request still open for Codetools :
  http://bugs.freepascal.org/view.php?id=15548

I feel absolutely dummy when I have to count the elements. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ..., 55, 56, 57.

Add the following macro (and refine ,or fix (only tested basics). Place caret between at [0..|] (where the total count should and innvoke the macro.

var
  porigin, p1, p2: TPoint;
  s: string;
  i, c1,c2, b: integer;
  t: boolean;
  a : char;
begin
  porigin := Caller.CaretXy;

  ecIncrementalFind;
  ecChar('(');
  ecLeft;

  i := 1;
  c1 := 0;
  c2 := 0;
  b := 0;
  t := false;
  repeat
    p1 := Caller.CaretXy;
    ecRight;
    s := Caller.LineAtCaret;
    p2 := Caller.CaretXy;
    if (p1.y = p2.y) and (p1.x = p2.x) then break;

    if (p2.x > length(s)) then begin
      t := false; // string ends in line
      ecdown;
      p2 := Caller.CaretXy;
      if (p1.y = p2.y) then break;  // last line
      s := Caller.LineAtCaret;
      while s = '' do begin
        p1 := Caller.CaretXy;
        ecdown;
        p2 := Caller.CaretXy;
        if (p1.y = p2.y) then break;  // last line
        s := Caller.LineAtCaret;
      end;
      if s = '' then break;
      Caller.CaretX := 1;
      p2 := Caller.CaretXy;
    end;

    if copy (s, p2.x, 2) = '//' then begin
      Caller.CaretX := length(s)+1;
      continue;
    end;

    a := s[p2.x];
    if copy (s, p2.x, 2) = '(*' then  a := '<';
    if copy (s, p2.x, 2) = '*)' then  a := '>';
    if (t) and (copy (s, p2.x, 2) = '''''') then begin
      a := ' ';
      ecRight;;
    end;

    case a of
      '{': if (c2 = 0) and (not t) then c1 := c1 + 1;
      '}': if (c2 = 0) and (c1 > 0) and (not t) then c1 := c1 - 1;
      '<': if (c1 = 0) and (not t) then c2 := c2 + 1;
      '>': if (c1 = 0) and (c2 > 0) and (not t) then c2 := c2 - 1;
      '''': if (c1 = 0) and (c2 = 0) then t := not t;
      '(', '[': if (c1 = 0) and (c2 = 0) and (not t) then b := b + 1;
      ')', ']': if (c1 = 0) and (c2 = 0) and (not t) then begin
          b := b - 1;
          if b < 0 then break;
        end;
      ',': if (c1 = 0) and (c2 = 0) and (not t) then  i := i + 1;
    end;

  until false;

  Caller.CaretXy := porigin;
  Caller.InsertTextAtCaret(inttostr(i), scamAdjust )

end.

Edit [2]:

Added dealing with strings.

You may want to limit how far to search if the closing ")" is missing. Or abort when finding a "begin" keyword.

And: It does not deal with comments before the '('. It goes to the firsn "(" that it finds, comment or not.

Read the original on forum.lazarus.freepascal.org ↗