3

I want to create a simple TeX/LaTeX editor with Lazarus and SynEdit.

The TSynTeXSyn syntax highlighter highlights the TeX syntax pretty well.

Now I'd like some sort of code completion. Tried to use TSynCompletion and TSynAutoComplete components but they seem to stick with Pascal and other standard programming languages that don't count with a non-letter (i. e. backslash) as a part of a word to be completed.

(I plan the auto-complete list to be basically user defined (by collecting commands/macros from the TeX code and pressing a shortcut or by manually editing the command list). It's nearly impossible for me to take the TeX source and re-write it to be able to see all available macros at the insertion point, which would be nice but I'm not going into that.)

I tried to assign a list with all items starting with a backslash to the ItemList property of the TSynAutoComplete component but that gave me one more backslash after completion (not counting the first backslash as a part of the unfinished prefix and adding another as a part of the list item).

I tried to assign a list without backslashes and that works but it would complete the words anywhere in the text, regardless if a backslash precedes or not.

One solution would be to hack the SynEdit code, make a fork and add backslash into letters for the completion purposes. But I'm not sure that's what I want. It would take even two or more following commands and replace them with one single command that the user chose.

I'd like SynEdit to have an option to type "\" so that the autocomplete window pops up but lets the backslash to be written. Then, as the user types, to let it search for the right term. Then, as the user selects the right command, to overwrite the whole word, including the opening backslash but not any following command to the right.

Do you see a path to achieve this? How would this be complicated?

Can the TSynCompletion external events help me?

Cigydd
  • 93
  • 1
  • 8

1 Answers1

3

Why this doesn't work

TSynCompletion tokenizer is not tweakable and it's based on an internal procedure that separates the identifiers according to the ASCII identifier chars (a-z, A-Z, _, so it excludes the problematic backslash that should be took as an identifier character).

The function I talk about is

function IsIdentifierChar(p: PChar): boolean; inline; 

from the unit SynCompletion

Resolution

As you noted in the Q, some events are available and can be used to adjust the result of the completion.

In a first time Assign the OnCodeCompletion event. Goto the empty method generated for the event and type the following code.

procedure TForm1.SynCompletion1CodeCompletion(var Value: string;
  SourceValue: string; var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char;
  Shift: TShiftState);
begin
  if SourceStart.x > 0 then
  begin
    if SynEdit1.Lines[SourceStart.y - 1][SourceStart.x-1] = '\' then
    begin
      SourceStart.x -= 1;
      SourceValue := '\' + SourceValue;
    end;
  end;
end;  

In case this would not be clear:

  • check if there can be something before the identifier located before the cursor.
  • if so, get the character located before the identifier located before the cursor.
  • if this character is a backslash then we modify the variables found by the default tokenizer (add the backslash to the source and decrements the source start position).
  • Once our values patched, the completion works fine:

hit ctrl + space

accept proposal

Community
  • 1
  • 1
Abstract type
  • 1,901
  • 2
  • 15
  • 26
  • Great! I thought that other events need to be involved, especially the `OnExecute` and `OnSearchPosition` events. But the `CurrentString` property can be easily altered by the `OnCodeCompletion` event and the rest comes automatically. – Cigydd Aug 01 '15 at 23:59
  • Double checked that and noticed that there is still an issue with chained commands. If you have, say, `\alpha\beta\ga` and try to complete `\gamma`, then `\alpha` would be selected and you would replace all three commands. Solved that by matching only the last command and changing the Position accordingly in the `OnExecute` and `OnSearchPosition` events. – Cigydd Aug 02 '15 at 00:27
  • 1
    Sorry for the corner case but the fact is i don't know TeX at all. At least you have the base idea about how to proceed. Another way to solve your problem would have been to subclass TSynCompletion but the method that would need to be overriden are unfortunately not virtual... – Abstract type Aug 02 '15 at 00:45
  • 1
    Also note that `OnExecute` is more suited to build/filter the list and to prepare the form. – Abstract type Aug 02 '15 at 00:48