Customizando o Help Insight no Delphi
Autor: Fabius Lovato | Publicado: 2010-06-08T01:59:00-03:00

Recentemente li um artigo sobre Help Insight que chamou bastante minha atenção.
Acredito que todos saibam o que é ou já tiveram contato com essa funcionalidade, mas para aqueles que não estão acostumado com o nome Help Insight, esse é um recurso do IDE do Delphi que apresenta um popup com uma breve descrição sobre o identificador (classe, método, função, variável, ...) na qual o cursor do mouse está posicionado.
Também é possível invocar o Help Insight através do&nbsp;pressionamento&nbsp;das teclas&nbsp;CTRL + SHIFT + H.
Por padrão é apresentado nesse popup menu as seguintes informações:
Nome do identificador
Categoria do identificador (Campo, variável, método, classe, propriedade, ...)
Localização (nome da unit seguido pelo número da linha e da coluna)
Tipo (Se o identificador é string, integer, ...)

No caso do identificador ser um método, function ou procedure, a descrição é extendida apresentando também o(s) parâmetro(s) e o valor de retorno.

Isso tudo é feito automaticamente pelo IDE em tempo de edição, ou seja, nem necessitar que o código seja compilado.
O que eu não sabia, e é o objetivo desse artigo, é que o conteúdo do popup menu pode ser customizado exibindo informações mais detalhadas a respeito do identificador em questão.
Essa customização deve estar situada imediatamente acima do identificador a qual se deseja trabalhar e tem seu início demarcado através de um comentário coringa (///, três barras) seguido por uma tag XML reconhecida pelo Help Insight viewer.

As tags XML atualmente reconhecida são:
summary
param
returns
permission
remarks
comments
Agora vamos ver um exemplo prático contendo todas essas tags.

/// &lt;summary&gt;&nbsp;&nbsp;&nbsp; Verificar se um determinado componente/field teve ou não seu conteúdo
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; alterado. O método é utilizado dentro do framework para sinalizar os
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; componentes que foram modificados durante uma operação de update.&lt;/summary&gt;
/// &lt;param name="FieldComp"&gt; Registro contendo informações sobre o field/componente. &lt;/param&gt;
/// &lt;param name="Index"&gt;&nbsp;&nbsp;&nbsp; Índice do registro dentro da lista (&lt;c&gt;FFieldList&lt;/c&gt;). &lt;/param&gt;
/// &lt;param name="Modified"&gt;&nbsp; Parâmetro de saída que deve ser setado para True/False, dependendo
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; do status verificado pelo método. Por padrão, o parâmetro vem
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; com o valor True. &lt;/param&gt;
/// &lt;returns&gt;&nbsp;&nbsp;&nbsp; O valor retornado deve significar que o método obteve sucesso ao comparar o
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; valor original com o valor atual do componente/field, ou seja, que o valor
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; do parâmetro Modified é válido.&lt;/returns&gt;
/// &lt;permission&gt; Esse método é utilizado internamente apenas quando o formulário está em estado
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; de alteração de registro. A implementação original trás suporte para os
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; componentes mais comumente utilizados, entretanto, em caso de customização ou
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; extenção do suporte a outros componentes, esse método pode sempre ser
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; reimplementado nos formulários filhos. &lt;/permission&gt;
/// &lt;remarks&gt;&nbsp;&nbsp;&nbsp; Originalmente esse método foi concebido para ser utilizado pelo framework como
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; um serviço. Assim, evite chamá-lo diretamente a menos que saiba com exatidão
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; o que está fazendo. &lt;/remarks&gt;
/// &lt;comments&gt;&nbsp; Caso necessite reimplementar o método, é recomendado que faça uma chamada à
/// &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; implementação da classe pai (Exemplo: Result := inherited;). &lt;/comments&gt;
Observe que foi utilizado também as tags &lt;c&gt; e &lt;/c&gt;. Essas tags delimitam um área de texto que será formatada no estilo de código fonte do Delphi (por padrão, Courier New).
O resultado é:

Convenhamos que se você está navegando pelo código, um help assim é muito, mas muito mais útil do que simplesmente visualizar a assinatura do identificador (padrão do Delphi), certo? Além do mais, você não precisa se deslocar até a definição/implementação/declaração do identificador para obter maiores detalhes, o que quase sempre resulta na interrupção da linha de raciocínio durante alguma investigação.
Uma outra vantagem que notei sobre a utilização do Help Insigh é poder ter dois tipos de documentação a respeito de um método sobre dois pontos de vista.
Deixa eu exemplificar. Observe o código fonte abaixo.

unit Unit1;

interface

uses
&nbsp;&nbsp;Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
&nbsp;&nbsp;Dialogs;

type
&nbsp;&nbsp;TForm1 = class(TForm)
&nbsp;&nbsp;private
&nbsp;&nbsp; &nbsp;{ Private declarations }

&nbsp;&nbsp;protected
&nbsp;&nbsp; &nbsp;function FieldIsModified(var FieldComp: TFieldItem; const Index: Integer; out Modified: Boolean): Boolean; virtual;

&nbsp;&nbsp;public

&nbsp;&nbsp;end;

var
&nbsp;&nbsp;Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

{_/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\
&nbsp;&nbsp;Definition.: Protected &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Strict [ ] &nbsp; &nbsp; Virtual/Override [X] &nbsp; &nbsp; Event [ ]
&nbsp;&nbsp;Ojective...:
&nbsp;&nbsp;Usefulness.:
&nbsp;&nbsp;Parameters.: [ I ] FieldComp =
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [ I ] Index &nbsp; &nbsp; =
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [ O ] Modified &nbsp;=
&nbsp;&nbsp;Result.....:
&nbsp;&nbsp;Comments...:
_/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\__/-\}
function TForm1.FieldIsModified(var FieldComp: TFieldItem; const Index: Integer; out Modified: Boolean): Boolean;
begin
&nbsp;&nbsp;// ...
end;

end. 
Creio que a prática mais comum de documentação de código seja a inclusão de&nbsp;comentários imediatamente acima da implementação dos métodos/funções (como apresentando no exemplo acima), ficando a área de interface da unit com apenas as definições.

O&nbsp;código fonte acima contém a estrutura do bloco de comentário que costumo utilizar para documentar um método ou uma function (removi o texto para ficar mais fácil sua visualização). As informações que acrescento nesse bloco estão relacionadas principalmente com seu funcionamento, com sua dependência perante a solução como um todo e com cuidados que devem ser tomados na sua utilização.
Quando penso no Help Inside, penso em um ponto de vista onde saber como é o funcionamento interno de um método não é tão importante, naquele momento, quanto saber o que o método faz, suas entradas e suas saídas. Assim, quando digo que o Help Insight proporciona um segundo tipo de comentários é justamente a possibilidade de documentar o código fonte sob uma perspectiva mais focada no&nbsp;conceito&nbsp;do que&nbsp;em detalhes intrínsecos ao&nbsp;funcionamento.

Apesar de muito útil, fique um tanto desconfortável com relação a legibilidade (ou melhor, à falta de legibilidade) que a estrutura de definição das tags causa ao layout da classe.
Por exemplo, se você possui um classe com vários métodos e propriedades. Acrescentar um help insigh para cada definição irá dinimuir a visão do todo por exigir constante deslocamento entre as linhas para navegar pela classe (aqui o layout struct do Delphi se mostrou ainda mais útil).
Fiz alguns testes e notei que o IDE aceita a utilização de REGIONS para delimitar a área do Help Insight, o que pareceu uma forma bem razoável para resolver ou, no mínimo, minimizar a área visível ocupada.


Um segundo ponto com relação a legibilidade é que não há uma formatação específica para as tags.
 &nbsp; a) É possível escrever a descrição de uma tag utilizando multi-linhas ou em apenas uma única linha que o conteúdo será apresentado igualmente no popup; 
&nbsp; b) Pode-se acrescentar espaços&nbsp;vários espaços em&nbsp;brancos, mas os excedentes serão ignorados (assim como em HTML);
&nbsp; c) Qualquer quebra de linha será ignorada, o que dá margem para formatar melhor o texto na unit, mas na hora de exibir o popup, as frases serão concatenadas em um único parágrafo.
&nbsp; Isso faz com que não seja possível escrever um pequeno trecho de código, por exemplo.

Em outras palavras, fiquei com a impressão que é mais legível ler as descrições do popup do que diretamente do&nbsp;código fonte.
Caso deseje analisar o código fonte completo da unit criada durante a escrita desse artigo, faça o download nesse link.


A última dica é para aqueles de desejam alterar a saída do popup para um layout mais adequado ou apenas queiram fazer pequenos incrementos. Nesse caso basta editar o arquivo&nbsp;HelpInsight.xsl&nbsp;(sub-diretório&nbsp;ObjRepos&nbsp;do&nbsp;diretório de instalação do RAD Studio, para mim é&nbsp;C:\Program Files\Embarcadero\RAD Studio\7.0\ObjRepos). Lá você encontrará também outras opções não descrita nesse artigo.

Boa sorte.