Модераторы: Vitalik
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Исправления и моды SynEdit из пакета SynMix 
:(
    Опции темы
mr.Anderson
Дата 29.7.2007, 19:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


iOS Lead Developer
****


Профиль
Группа: Участник Клуба
Сообщений: 3374
Регистрация: 20.12.2004
Где: далеко

Репутация: 1
Всего: 128



Тему, я думаю, стоит закрепить. И вообще все, что связано с SynEdit из пакета SynMix, надо бы перенести в эту тему, мне кажется.




Итак. Поскольку SynEdit из пакета SynMix мне нужно использовать в своей программе как основной, мне пришлось изрядно перерыть его, чтобы заставить-таки работать, как надо. Привожу здесь мои добавления, произведенные в файле SynEdit.pas, а также обнаруженные и исправленные баги.
Примечание: прошу обратить внимание на то, что номера строк, где происходило добавление, приведены для моего, уже исправленного и дополненного файла SynEdit.pas. В стандартном файле, разумеется, этих добавлений/исправлений нет, и по указанным номерам строк находится совсем другой код.


Фикс №1
Строка 11664: пофиксен баг с отображением скрытого текста. Собственно фикс в том, что я увеличил добавляемые пробелы с пяти до шести.
Код

Lines[FromLine-1] := Lines[FromLine-1] + '      ';

До этого исправления, например, когда мы сворачивали примерно такой блок кода:
Код

begin
 myfunc();
end;

То в подсказке получали следующее:
Код

begi
 myfunc();
end;

Разницу видим? smile Обрезался последний символ первой строки свернутого блока. Такая же ошибка была даже в случае свертки вот такого блока:
Код

{
 code();
}

В подсказке отображалось
Код


 code();
}

Т.е. тоже обрезался последний (и в данном случае единственный) символ открывающейся скобки.



Фикс №2
Строки 4017 и 4021: пофиксен баг с размещением [...]. Раньше было так, что при простом сворачивании блока кода, ограниченного { и }, блок [...] наезжал на переплет, а если блок был ограничен, например, begin и end, то [...] наезжал на слово begin. Теперь все нормально (###фикс - исправлено наезжание [...] на первую строку блока кода).
Код

if Gutter.ShowLineNumbers then
  //FoldRange.HintMarkLeft := ((nTokenPos + nTokenLen) * CharWidth)
  FoldRange.HintMarkLeft := ((nTokenPos + {nTokenLen} - 4) * CharWidth) //###mod pos of [...] to left
    + Gutter.LeftOffset + (GetAutoSizeDigitCount * Gutter.CharWidth) + 35 //###фикс - исправлено наезжание [...] на первую строку блока кода
    + Gutter.RightOffset
  else
    //FoldRange.HintMarkLeft := ((nTokenPos + nTokenLen) * CharWidth)
    FoldRange.HintMarkLeft := ((nTokenPos + {nTokenLen} - 4) * CharWidth) + 35 //###mod pos of [...] to left + ###фикс - исправлено наезжание [...] на первую строку блока кода
      + Gutter.LeftOffset + Gutter.RightOffset;



Фикс №3
В строках 12772 и 12773 добавлен код, предотвращающий ошибку в случае, если выделить первую строку свернутого блока и нажать Ctrl + Backspace (///###mod error with Ctrl+Backspace when SelAvail = True).
Код

if (aKey = VK_BACK ) then //###mod error with Ctrl+Backspace when SelAvail = True
 Exit; //###mod error with Ctrl+Backspace when SelAvail = True



Мод №1
Добавлена общедоступная функция IsLineCollapsed() (в строке 786 - в классе, а в 6798-6801 - реализация). Функция принимает целый параметр - номер строки, с которой начинается блок кода. Функция возвращает True, если этот блок свернут, и False, если нет. Код крайне прост и занимает всего одну строчку.
Код

//объявление - строка 786
function IsLineCollapsed( CurrentLine: Integer ): Boolean; // ###mod IsLineCollapsed() function
//...

//реализация - строки 6798-6801
function TCustomSynEdit.IsLineCollapsed( CurrentLine: Integer ): Boolean; // ###mod IsLineCollapsed() function
begin
 Result := ( CurrentLine+1 <> Self.GetRealLineNumber( CurrentLine+1 ) );
end; // ###end mod IsLineCollapsed() function



Обнаруженный и грубовато исправленный баг
Вынес это исправление в отдельную "категорию". Смысл таков: в SynEdit из пакета SynMix НЕ РАБОТАЕТ клавиша Delete! Я вообще был в шоке от этого. Жму Delete - ноль эмоций! Но зато если выделить часть текста и нажать Delete - все нормально. Поскольку я не смог поймать нажатие Delete в классе TCustomSynEdit (читайте ниже, почему), пришлось исправлять баг грубыми методами. О них - в модах №2 и №3.


Мод №2
Добавлена общедоступная процедура Del() (строка 788 - объявление, 6808-6811 - реализация).
Код

//объявление - строка 788
procedure Del; // ###mod-fix "Del" Pressing
//...

//реализация - строки 6808-6811
procedure TCustomSynEdit.Del; // ###mod-fix "Del" Pressing
begin
 SendMessage( Self.Handle, WM_KEYDOWN, VK_DELETE, 0 );
end; // ###end mod-fix "Del" Pressing

По сути, эта процедура - грубая замена нажатия клавиши Delete в SynEdit, создана для облегчения пользования этой неработающей клавишей. Для ее активации придется в программе переопределять метод AppMsg или WndProc, ловить там нажатие Delete и использовать эту функцию. Например, это может быть такой код:
Код

//...
//в классе формы
public
  procedure AppMsg( var Msg: TMsg; var Handle: Boolean ); override;
//...

//...
//в функции FormCreate или FormShow
procedure TForm1.FormCreate( Sender: TObject );
begin
 Application.OnMessage := AppMsg;
end;
//...

//...
//переопределяем функцию
procedure TForm1.AppMsg( var Msg: TMsg; var Handle: Boolean );
begin
 //ловим нажатие Delete
 if( Msg.Msg = WM_KEYDOWN ) and ( Msg.wParam = VK_DELETE ) and ( SynEdit1.Focused() ) then
  SynEdit1.Del();
end;
//...



Мод №3
Добавлена общедоступная процедура DeleteSelText() (строка 787 - объявление, 6803-6806 - реализация). По сути своей это просто синоним вышеописанной процедуры Del(), но может быть более привычно и удобно использовать понятную по своему действию процедуру DeleteSelText(), чем просто Del().
Код

//объявление - строка 787
procedure DeleteSelText; // ###mod DeleteSelText() procedure
//...

//реализация - строки 6803-6806
procedure TCustomSynEdit.DeleteSelText; // ###mod DeleteSelText() procedure
begin
 Self.Del();
end; // ###end mod DeleteSelText() procedure



Обнаруженный и НЕ исправленный баг
Если свернутую строку кода выделить и нажать Delete, то строка удаляется. Однако попытки отменить это (SynEdit.Undo()) ни к чему не приводят - отмены удаления не происходит. Я, кстати, вообще не смог отловить нажатие Delete. Ставил бряки на TCustomSynEdit.KeyPressTCustomSynEdit.KeyDownTCustomSynEdit.KeyUp, даже на TCustomSynEdit.WndProc() - бесполезно. Ловятся все клавиши, кроме Delete. Именно поэтому я и не смог отловить данный баг. В своей программе мне пришлось искусственно запретить срабатывание любых клавиш на строке, где находится свернутый блок (кроме Enter, клавиш вверх-вниз-влево-вправо, Home и End - это сделано для того, чтобы юзер не думал, что это еще один глюк).



Объемный мод №4
В класс TCustomSynEdit добавлено свойство только для чтения CurrentHL. Это свойство нового перечислимого типа TCurrentHL, содержит словесный и числовой эквиваленты текущей подсветки. Иногда бывает нужно (мне вот понадобилось) узнать, какая сейчас в редакторе подсветка. Как это узнать обычными методами? А никак. Свойство Highlighter у TCustomSynEdit имеет тип TSynCustomHighlighter, а конкретный тип, например, TSynPasSyn, я не смогу узнать никакими методами. Поэтому я и добавил такую возможность в виде вышеназванного свойства.

Теперь собственно о том, какой код был добавлен. Все, связанное с этим модом, помечено как
Код

// ###mod Current Highlighter
  //код мода
// ###end mod Current Highlighter

Повторю, все изменения производились в файле SynEdit.pas.

Первое. В строках 216-224 добавлен тип TCurrentHL. Он содержит имена всех типов подсветки из пакета SynMix (например, TSynPasSynTSynVBScriptSyn и так далее). С компонентом UniHighlighter этот тип никак не связан и с ним использовать данный мод бесполезно.
Код

TCurrentHL = ( lngCpp, lngEiffel, lngFortran, lngGeneral, lngJava,
  lngM3, lngPascal, lngVisualBasic, lngCobol, lngCSharp, lngCSS,
  lngHTML, lngJScript, lngPHP, lngVBScript, lngXML, lngVrml97, lngAWK,
  lngBat, lngKix, lngPerl, lngPython, lngTclTk, lngGWScript, lngRuby,
  lngUNIXShellScript, lngCAC, lngCache, lngFoxpro, lngSQL, lngSDD,
  lngADSP21xx, lngAsm, lngHC11, lngHP48, lngST, lngDml, lngModelica,
  lngSML, lngDfm, lngIni, lngInno, lngBaan, lngGalaxy, lngProgress,
  lngMsg, lngIdl, lngUnreal, lngCPM, lngTeX, lngHaskell, lngLDR,
  lngURI, lngDOT, lngRC, lngNone );

Тип, разумеется, общедоступный и может использоваться в основной программе, где размещен компонент SynEdit.

Второе. В строке 430 добавлена переменная fCurrentHL типа TCurrentHL. Эта переменная и содержит имя текущей подсветки.
Код

fCurrentHL: TCurrentHL;

Третье. В строке 737 объявлена процедура UpdateCurrentHL(). Она вводит в переменную fCurrentHL имя текущей подсветки (тип TCurrentHL).
Код

procedure UpdateCurrentHL;

Четвертое. В строке 935 прописано свойство CurrentHL (только для чтения, повторюсь).
Код

property CurrentHL: TCurrentHL read fCurrentHL;

Пятое. В строке 1550 (это код конструктора класса TCustomSynEdit) добавлена, по моему мнению, упущенная инициализация свойства Highlighter. Это даже к моду не относится, в принципе, это скорее фикс.
А вот в строчке 1551 добавлен вызов вышеназванной процедуры UpdateCurrentHL(), которая, как мы увидим дальше по ее коду, в данном случае проинициализирует переменную fCurrentHL как lngNone (это одно из имен типа TCurrentHL, означающее, что текущей подсветки нет, т.к. свойство Highlighter равно nil).
Код

fHighlighter := nil;
UpdateCurrentHL();

Шестое. В строках 7266-7323 находится реализация процедуры UpdateCurrentHL().
Код

procedure TCustomSynEdit.UpdateCurrentHL;
var
 Value : TSynCustomHighlighter;
begin
 Value := Self.Highlighter;

 if( not Assigned( Value ) ) then fCurrentHL := lngNone

 else if( Value.ClassNameIs( 'TSynUNIXShellScriptSyn' ) ) then
  fCurrentHL := lngUNIXShellScript

 else if( Value.ClassNameIs( 'TSynCppSyn'      ) ) then fCurrentHL := lngCpp
 else if( Value.ClassNameIs( 'TSynEiffelSyn'   ) ) then fCurrentHL := lngEiffel
 else if( Value.ClassNameIs( 'TSynFortranSyn'  ) ) then fCurrentHL := lngFortran
 else if( Value.ClassNameIs( 'TSynGeneralSyn'  ) ) then fCurrentHL := lngGeneral
 else if( Value.ClassNameIs( 'TSynJavaSyn'     ) ) then fCurrentHL := lngJava
 else if( Value.ClassNameIs( 'TSynM3Syn'       ) ) then fCurrentHL := lngM3
 else if( Value.ClassNameIs( 'TSynPasSyn'      ) ) then fCurrentHL := lngPascal
 else if( Value.ClassNameIs( 'TSynVBSyn'       ) ) then fCurrentHL := lngVisualBasic
 else if( Value.ClassNameIs( 'TSynCobolSyn'    ) ) then fCurrentHL := lngCobol
 else if( Value.ClassNameIs( 'TSynCSSyn'       ) ) then fCurrentHL := lngCSharp
 else if( Value.ClassNameIs( 'TSynCSSSyn'      ) ) then fCurrentHL := lngCSS
 else if( Value.ClassNameIs( 'TSynHTMLSyn'     ) ) then fCurrentHL := lngHTML
 else if( Value.ClassNameIs( 'TSynJScriptSyn'  ) ) then fCurrentHL := lngJScript
 else if( Value.ClassNameIs( 'TSynPHPSyn'      ) ) then fCurrentHL := lngPHP
 else if( Value.ClassNameIs( 'TSynVBScriptSyn' ) ) then fCurrentHL := lngVBScript
 else if( Value.ClassNameIs( 'TSynXMLSyn'      ) ) then fCurrentHL := lngXML
 else if( Value.ClassNameIs( 'TSynVrml97Syn'   ) ) then fCurrentHL := lngVrml97
 else if( Value.ClassNameIs( 'TSynAWKSyn'      ) ) then fCurrentHL := lngAWK
 else if( Value.ClassNameIs( 'TSynBatSyn'      ) ) then fCurrentHL := lngBat
 else if( Value.ClassNameIs( 'TSynKixSyn'      ) ) then fCurrentHL := lngKix
 else if( Value.ClassNameIs( 'TSynPerlSyn'     ) ) then fCurrentHL := lngPerl
 else if( Value.ClassNameIs( 'TSynPythonSyn'   ) ) then fCurrentHL := lngPython
 else if( Value.ClassNameIs( 'TSynTclTkSyn'    ) ) then fCurrentHL := lngTclTk
 else if( Value.ClassNameIs( 'TSynGWScriptSyn' ) ) then fCurrentHL := lngGWScript
 else if( Value.ClassNameIs( 'TSynRubySyn'     ) ) then fCurrentHL := lngRuby
 else if( Value.ClassNameIs( 'TSynCACSyn'      ) ) then fCurrentHL := lngCAC
 else if( Value.ClassNameIs( 'TSynCacheSyn'    ) ) then fCurrentHL := lngCache
 else if( Value.ClassNameIs( 'TSynFoxproSyn'   ) ) then fCurrentHL := lngFoxpro
 else if( Value.ClassNameIs( 'TSynSQLSyn'      ) ) then fCurrentHL := lngSQL
 else if( Value.ClassNameIs( 'TSynSDDSyn'      ) ) then fCurrentHL := lngSDD
 else if( Value.ClassNameIs( 'TSynADSP21xxSyn' ) ) then fCurrentHL := lngADSP21xx
 else if( Value.ClassNameIs( 'TSynAsmSyn'      ) ) then fCurrentHL := lngAsm
 else if( Value.ClassNameIs( 'TSynHC11Syn'     ) ) then fCurrentHL := lngHC11
 else if( Value.ClassNameIs( 'TSynBaanSyn'     ) ) then fCurrentHL := lngBaan
 else if( Value.ClassNameIs( 'TSynGalaxySyn'   ) ) then fCurrentHL := lngGalaxy
 else if( Value.ClassNameIs( 'TSynProgressSyn' ) ) then fCurrentHL := lngProgress
 else if( Value.ClassNameIs( 'TSynMsgSyn'      ) ) then fCurrentHL := lngMsg
 else if( Value.ClassNameIs( 'TSynIdlSyn'      ) ) then fCurrentHL := lngIdl
 else if( Value.ClassNameIs( 'TSynUnrealSyn'   ) ) then fCurrentHL := lngUnreal
 else if( Value.ClassNameIs( 'TSynCPMSyn'      ) ) then fCurrentHL := lngCPM
 else if( Value.ClassNameIs( 'TSynTeXSyn'      ) ) then fCurrentHL := lngTeX
 else if( Value.ClassNameIs( 'TSynHaskellSyn'  ) ) then fCurrentHL := lngHaskell
 else if( Value.ClassNameIs( 'TSynLDRSyn'      ) ) then fCurrentHL := lngLDR
 else if( Value.ClassNameIs( 'TSynURISyn'      ) ) then fCurrentHL := lngURI
 else if( Value.ClassNameIs( 'TSynDOTSyn'      ) ) then fCurrentHL := lngDOT
 else if( Value.ClassNameIs( 'TSynRCSyn'       ) ) then fCurrentHL := lngRC
end;

И последняя часть кода, относящаяся к данному моду - это строчка 7348. В этой строке добавлен вызов UpdateCurrentHL(). Вызов находится в коде функции SetHighlighter() класса TCustomSynEdit, которая, как можно догадаться, изменяет свойство Highlighter. Поэтому вызов процедуры обновления переменной текущей подсветки находится именно в этом месте кода.
Код

procedure TCustomSynEdit.SetHighlighter(const Value: TSynCustomHighlighter);
begin
  if Value <> fHighlighter then
  begin
    if Assigned(fHighlighter) then
    begin
      fHighlighter.UnhookAttrChangeEvent(HighlighterAttrChanged);
{$IFDEF SYN_COMPILER_5_UP}
      fHighlighter.RemoveFreeNotification(Self);
{$ENDIF}
    end;
    if Assigned(Value) then
    begin
      Value.HookAttrChangeEvent(HighlighterAttrChanged);
      Value.FreeNotification(Self);
    end;
    fHighlighter := Value;
    if not( csDestroying in ComponentState ) then
      HighlighterAttrChanged( fHighlighter );
  end;

  // ###mod Current Highlighter
  UpdateCurrentHL();
  // ###end mod Current Highlighter
end;

Теперь в любом месте вашей программы вы можете узнать текущую подсветку, проанализировав свойство CurrentHL компонента SynEdit. Например, так:
Код

case SynEdit1.CurrentHL of
 //не забываем, что тип этого свойства - TCurrentHL
 lngNone   : ShowMessage( 'Нет подсветки!' );
 lngPascal : ShowMessage( 'Текущая подсветка - Паскаль!' );
 lngPython : ShowMessage( 'Текущая подсветка - Python!' );
end;


Это сообщение отредактировал(а) mr.Anderson - 29.7.2007, 19:40


--------------------
user posted image

user posted image
PM MAIL ICQ Skype   Вверх
winsoft
Дата 10.8.2007, 23:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Президент WINsoft



Профиль
Группа: Участник
Сообщений: 49
Регистрация: 14.11.2005

Репутация: нет
Всего: нет



mr.Anderson, пока еще не проверил, как все работает, но заранее большое спасибо за проделанную работу!  smile 
PM MAIL WWW ICQ   Вверх
mr.Anderson
Дата 14.8.2007, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


iOS Lead Developer
****


Профиль
Группа: Участник Клуба
Сообщений: 3374
Регистрация: 20.12.2004
Где: далеко

Репутация: 1
Всего: 128



Не за что. smile Проверяйте, может, что неверно исправлено. Хотя в моей программе я свои исправления использую очень активно (особенно CurrentHL), пока все работает отлично.

Отпишитесь плз, как у вас успехи с проверкой исправлений.


--------------------
user posted image

user posted image
PM MAIL ICQ Skype   Вверх
iddqd2
Дата 14.1.2008, 18:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 13.1.2008

Репутация: 1
Всего: 1



По поводу бага с несрабатыванием клавиши Delete
Происходит это из-за того, что клавиша Delete вызывает только событие KeyUp а не KeyDown, в то время как в SynEdit обработка событий стандартных клавиш происходит в KeyDown. Все необходимое для отработки нажатия Delete там есть.
Так что делаем так: 


Код

procedure TCustomSynEdit.KeyUp(var Key: Word; Shift: TShiftState);
...
begin
...
  If Key = 46 Then Begin
    ExecuteCommand(502, #0, Nil);
  End;
end;


PM MAIL   Вверх
mr.Anderson
Дата 15.1.2008, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


iOS Lead Developer
****


Профиль
Группа: Участник Клуба
Сообщений: 3374
Регистрация: 20.12.2004
Где: далеко

Репутация: 1
Всего: 128



iddqd2, супер smile


--------------------
user posted image

user posted image
PM MAIL ICQ Skype   Вверх
BenderM
  Дата 12.6.2009, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 11.6.2009

Репутация: нет
Всего: нет



mr.Anderson
Про выявление имени хайлайтера вы конечно перемудрили

Добавлено через 4 минуты и 51 секунду
Думаю этот код пригодился бы Вам полтора года назад

Код

function GetLangName(AHighlighter: TSynCustomHighlighter): string;
begin
  if AHighlighter <> nil then
  begin
    if AHighlighter is TSynMultiSyn then
      Result := (AHighlighter as TSynMultiSyn).DefaultLanguageName
    else
      Result := AHighlighter.GetLanguageName;
  end
  else
    Result := '';
end;


 smile 
PM MAIL   Вверх
K0T9I
Дата 20.10.2010, 15:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 20.11.2009

Репутация: нет
Всего: 2



Цитата(iddqd2 @ 14.1.2008,  18:33)
По поводу бага с несрабатыванием клавиши Delete
Происходит это из-за того, что клавиша Delete вызывает только событие KeyUp а не KeyDown, в то время как в SynEdit обработка событий стандартных клавиш происходит в KeyDown. Все необходимое для отработки нажатия Delete там есть.
Так что делаем так: 


Код

procedure TCustomSynEdit.KeyUp(var Key: Word; Shift: TShiftState);
...
begin
...
  If Key = 46 Then Begin
    ExecuteCommand(502, #0, Nil);
  End;
end;

когда делаем так, то удаление клавишей Delete возможно только при нажатии/отпускании клавиши по 1 символу за раз, при удерживании удаляется тоже 1 символ. если тоже самое, что подсказал iddqd2 вставить в KeyDown, все начинает работать как надо
Код

procedure TCustomSynEdit.KeyDown(var Key: Word; Shift: TShiftState);
...
begin
...
  If Key = 46 Then Begin
    ExecuteCommand(502, #0, Nil);
  End;
end;

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | SynUniHighlighter и SynEdit | Следующая тема »


 




[ Время генерации скрипта: 0.1480 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.