Форум программистов, компьютерный форум, киберфорум
Pure Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/35: Рейтинг темы: голосов - 35, средняя оценка - 4.60
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124

Работа с текстовым редактором Scintilla

16.11.2022, 21:30. Показов 9035. Ответов 99
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток ! Тружусь над небольшой программкой, в которой у меня будет редактор кода на основе "Scintilla". Столкнулся с такой задачкой: нужно, чтобы при нахождении ключевого слова, происходила его замена. По типу как в пурике - если пользователь написал ключевое слово в нижнем регистре, редактор его заменил на то, как эти ключевые слова хранятся в программе. К примеру, пользователь прописал "for" -> редактор сменил на "For". При этом, пурик, как известно, подсветку производит непосредственно как только обнаруживает ключевое слово, а замену делает при наборе следующего символа. При этом, символ должен быть либо пробел, либо скобка, либо переход на новую строку и т.п.
Выкладываю свой самый сокращенный вариант для примера. В нём зарезервировано только одно ключевое слово "For", ну этого достаточно для теста. Тут я пытаюсь добиться желаемого, но как-то некорректно это происходит. В строчках 89, 90 как раз пытаюсь прописать эту замену, но почему-то она не работает как нужно.
Подскажите, пожалуйста, в чём ошибка ? Как только не пытался экспериментировать, никак не могу добиться желаемого. Документацию по Scintilla уже раз 40 пересматривал, изучал, но там тоже не так просто разобраться. Она таким тяжелым языком написана, а более понятной и доступной нигде не найти.
В общем, вот мой пример поиска решения, дальше которого я никак не могу продвинуться. Помогите, пожалуйста, если есть кто-то компетентный.

PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
InitScintilla("Scintilla.dll")
 
; Константы для подсветки синтаксиса
Enumeration 0
  #LexerState_Space
  #LexerState_Keyword
  #LexerState_FoldKeyword
EndEnumeration
 
Global ChangeWord$ = "For" ; слово для замены
 
Procedure MyLexerInit()
  ; Шрифт
  ScintillaSendMessage(0, #SCI_STYLESETFONT, #STYLE_DEFAULT, @"Lucida Console")
  ; Размер шрифта
  ScintillaSendMessage(0, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 10)
  ScintillaSendMessage(0, #SCI_STYLECLEARALL)
  
  ; Цвет активной строки
  ScintillaSendMessage(0, #SCI_SETCARETLINEBACK, RGB(254, 252, 202))
  ; Разрешаем отмачать активную строку
  ScintillaSendMessage(0, #SCI_SETCARETLINEVISIBLE, #True)
  
  ; Цвета подсветки синтаксиса
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #LexerState_Keyword, 0)  ; Обычный текст
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #LexerState_FoldKeyword, $FF) ; Ключевые слова
  
  ; Поля 
  ScintillaSendMessage(0, #SCI_SETMARGINTYPEN, 0, #SC_MARGIN_NUMBER) ; Поле автонумирации
  ScintillaSendMessage(0, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)  ; Поле свертки и маркеров
  ScintillaSendMessage(0, #SCI_SETMARGINWIDTHN, 0, 20)               ; Ширина поля автонумирации
  ScintillaSendMessage(0, #SCI_SETMARGINWIDTHN, 2, 20)               ; Ширина поля свертки и маркеров
  ScintillaSendMessage(0, #SCI_SETMARGINSENSITIVEN, 2, #True)
EndProcedure
 
Procedure SCI_EVENT(Gadget, *scinotify.SCNotification) ; Обработка событий от редактора
  code=             *scinotify.SCNotification\nmhdr\code
  pos=              *scinotify.SCNotification\Position
  ch=               *scinotify.SCNotification\ch
  modificationType= *scinotify.SCNotification\modifiers
  text=             *scinotify.SCNotification\text
  Length=           *scinotify.SCNotification\length
  linesAdded=       *scinotify.SCNotification\linesAdded
  message=          *scinotify.SCNotification\message
  wParam=           *scinotify.SCNotification\wParam
  lParam=           *scinotify.SCNotification\lParam
  line=             *scinotify.SCNotification\line
  foldLevelNow=     *scinotify.SCNotification\foldLevelNow
  foldLevelPrev=    *scinotify.SCNotification\foldLevelPrev
  margin=           *scinotify.SCNotification\margin
  listType=         *scinotify.SCNotification\listType
  x=                *scinotify.SCNotification\x
  y=                *scinotify.SCNotification\y
  
  
  Select code
    Case #SCN_STYLENEEDED
      EndPos = pos
      EndStyledPos = ScintillaSendMessage(0, #SCI_GETENDSTYLED)
      linenumber = ScintillaSendMessage(0, #SCI_LINEFROMPOSITION, EndStyledPos)
      
      ; Текуцая позиция курсора
      CurrentPos.l = ScintillaSendMessage(0, #SCI_POSITIONFROMLINE, linenumber)
      ; Подготовка к стилистической правке
      ScintillaSendMessage(0, #SCI_STARTSTYLING, CurrentPos)
      State = #LexerState_Space
      KeywordStartPos = CurrentPos
      keyword.s = ""
      
      While CurrentPos <= EndPos
        OldState = State
        
        Char.l = ScintillaSendMessage(0, #SCI_GETCHARAT, CurrentPos) ; Получаем символ из текущей позиции 
        If Char = 10 Or Char = 13 Or Char = 9 Or Char = ' '
          State = #LexerState_Space
        Else
          State = #LexerState_Keyword
          keyword + Chr(Char)
        EndIf
        
        If OldState <> State Or CurrentPos = EndPos
          If OldState = #LexerState_Keyword
            lkeyword.s = LCase(keyword)
            If lkeyword = "for"
              LenKeyword = Len(lkeyword)
              *Kwd = AllocateMemory(LenKeyword)
              PokeS(*Kwd, ChangeWord$, LenKeyword, #PB_UTF8)
              
              ScintillaSendMessage(0, #SCI_DELETERANGE, pos - LenKeyword, LenKeyword)
              ScintillaSendMessage(0, #SCI_INSERTTEXT, -1, *Kwd)
              ScintillaSendMessage(0, #SCI_GOTOPOS, pos)
              FreeMemory(*Kwd)
              
              OldState = #LexerState_FoldKeyword
            EndIf
            keyword = ""
          EndIf
          ScintillaSendMessage(0, #SCI_SETSTYLING, CurrentPos - KeywordStartPos, OldState) ; Подсветка синтаксиса
          KeywordStartPos = CurrentPos
        EndIf
        CurrentPos + 1
      Wend
      
  EndSelect
EndProcedure
 
If OpenWindow(0, 450, 200, 402, 402, "Scintilla Example", #PB_Window_SystemMenu |#PB_Window_ScreenCentered)
  ScintillaGadget(0, 2, 2, 398, 398, @SCI_EVENT())
  MyLexerInit()
  
  Repeat
    Event = WaitWindowEvent()
    
  Until Event = #PB_Event_CloseWindow
EndIf
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.11.2022, 21:30
Ответы с готовыми решениями:

Работа с текстовым редактором
Доброе время суток!!! Помогите! пишу текстовый редактор, на основе ActionManager использовал стандартную кнопку Undo (вернуть, назад),...

Работа с текстовым редактором
Помогите пожалуйста доделать задание. Не понимаю как дальше сделать. Только начал изучать win form

Помогите с текстовым редактором!
Пишу текстовый редактор для курсовой, почти все сделал, только препод сказал чтоб редактор был многостраничным, с использованием...

99
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
25.11.2022, 15:26  [ТС]
Студворк — интернет-сервис помощи студентам
locm, потому что, совпадение с ключевым словом на этапе набора самого слова, ещё не значит, что это оно и есть, это пока ещё только первоначальное сходство. Дальше может пойти символ слова и это уже не будет ключевым словом, а замена уже произведена. Так вот, чтоб такого не происходило, нужно, чтобы лексер, следующий за пока ещё только намечающимся ключевым словом, был отличным от лексера простого слова. Только тогда мы со 100%-ной уверенностью можем сказать, что тут действительно имелось ввиду ключевое слово, и делать замену.

Добавлено через 14 минут
Кстати, в отправленном Вами последнем куске части кода, мне тоже непонятен один момент. Ведь код перебирает строку посимвольно и сравнивает текущий символ с предыдущим. Если State текущего символа отличается от предыдущего (OldState), только тогда выполняется какое-то изменение в подсветке. Условие:
PureBasic
1
If OldState <> State
Но ведь в процессе набора символов, у нас State и OldState остаются одинаковыми. Как же так происходит, что лексер текущего и предыдущего символа одинаковы, а он уже подсвечивает предположительное ключевое слово ? Почему это происходит в нарушение условия ?
0
Эксперт по электронике
6872 / 3295 / 340
Регистрация: 28.10.2011
Сообщений: 12,913
Записей в блоге: 7
25.11.2022, 15:37
Тогда нужно проверять чтобы после ключевого слова был еще какой-то символ (пробел или другой, который не встречается в ключевых словах).

Может этот код чем-то поможет https://github.com/fantaisie-s... ighting.pb

Цитата Сообщение от antro735 Посмотреть сообщение
Но ведь в процессе набора символов, у нас State и OldState остаются одинаковыми.
Добавьте эту строку после условия и увидите чему равны перемеренные.
PureBasic
1
Debug "State="+State+"  OldState="+OldState
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
25.11.2022, 19:27  [ТС]
...

Добавлено через 4 минуты
Благодарю, locm, к сожалению, у меня почему-то не запускается этот код. Жалуется с первой же строки на необъявленные константы.

Сообщение от locm
Тогда нужно проверять чтобы после ключевого слова был еще какой-то символ
Но ведь когда после слова мы набираем пробел - это и является символом, с лексером, отличающимся от лексеров простого слова и ключевого слова.

Добавлено через 12 минут
Однако, если, к примеру, тот же самый пробел предварительно уже имеется после ключевого слова, то реакция нормальная, а если его ещё нет, и мы его только что ввели, то ракция совсем другая. Но ведь по сути, он появился, и обработка строки производится с уже имеющимся пробелом. Почему же ракция совсем другая ? Хотя, в редакторе пурика это срабатывает нормально. Вот, мне и непонятно, то ли Scintilla по-разному обрабатывает строку, то ли я чего-то не понимаю. решение однозначно какое-то должно быть - пурик наглядный пример, но моих остатков мозгов что-то не хватает разобраться в столь странном поведении сцинтиллы.

Добавлено через 7 минут
Может этот код чем-то поможет
А-а-а-а, у него там просто коллекция процедур для работы с редактором.

Добавлено через 17 минут
Сообщение от locm

Добавьте эту строку после условия и увидите чему равны перемеренные.
Я уже это проделывал. На этапе набора символов они одинаковы. Однако, как только набранные символы совпадают с ключевым словом, происходит подсветка, хотя, лексеры пока ещё по-прежнему имеют одинаковое значение. Тоже странное поведение.
Делал вот так:
PureBasic
1
2
3
Debug Str(OldState) + "   " + State
        
        If OldState <> State Or CurrentPos = pos
Добавлено через 45 минут
Сообщение от locm
Добавьте эту строку после условия и увидите чему равны перемеренные.
Всё, дошло - при подсветке при наборе символов выполняется вторая часть условия
PureBasic
1
If OldState <> State Or CurrentPos = pos
То есть, достижение последнего подсвечиваемого символа. Разобрался. А, вот, с заменой ключевого слова пока не могу.

Добавлено через 2 часа 9 минут
Да, locm, есть у него в коллекции по ссылке на гитхабе, который Вы высылали мне, процедура замены слова. Нашёл её, сделал перевод. Кстати, он там в комментариях тоже пишет об этой проблеме. Мне только в ней немного непонятно, на что указывают указатели *HighlightBuffer , *StringStart.Ascii, *Color . Я в указателях ещё не очень силён. Не могли бы пояснить, что это за указатели, и как их правильно определить ?

Вот эта процедура с переведёнными комментариями:
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
; Нужно поделиться началом буфера, чтобы правильно получить позицию
Global *HighlightBuffer, HighlightOffset, HighlightGadget, NoUserChange
 
Procedure HighlightCallback(*StringStart.Ascii, Length, *Color, IsBold, TextChanged)
  
  ; заменяйте текст только в том случае, если он был изменен механизмом выделения (исправление регистра)
  If TextChanged
    ; Очень странно: если последняя строка пуста, а в предыдущей есть ключевое слово (исправление регистра) в конце
    ; обычно новая строка заменяется словом. Это, однако, заставляет сцинтиллу вести себя как сумасшедшая, когда
    ; прокрутка до последней строки. Таким образом, мы фактически заменяем только само слово, а не какие-либо пробелы / новую строку за ним
    ; это, по-видимому, исправляет это : |
    ;
    ChangeLength = Length
    While ChangeLength > 1 And ValidCharacters(PeekA(*StringStart + ChangeLength - 1)) = 0
      ChangeLength - 1
    Wend
    
    ; обратите внимание, что это изменение отображается в буфере отмены, но это нельзя
    ; изменить, потому что если вы отключите буфер обмена, вы также очистите его!
    ScintillaSendMessage(HighlightGadget, #SCI_SETTARGETSTART, *StringStart - *HighlightBuffer + HighlightOffset, 0)
    ScintillaSendMessage(HighlightGadget, #SCI_SETTARGETEND, *StringStart - *HighlightBuffer + HighlightOffset + ChangeLength, 0)
    ScintillaSendMessage(HighlightGadget, #SCI_REPLACETARGET, ChangeLength, *StringStart)
  EndIf
  
  ; Используется только хороший цветовой стиль (быстрее в соответствии с документацией)
  If EnableColoring
    ScintillaSendMessage(HighlightGadget, #SCI_SETSTYLING, Length, *Color)
  EndIf
EndProcedure
0
Эксперт по электронике
6872 / 3295 / 340
Регистрация: 28.10.2011
Сообщений: 12,913
Записей в блоге: 7
25.11.2022, 20:11
Цитата Сообщение от antro735 Посмотреть сообщение
к сожалению, у меня почему-то не запускается этот код.
Это один из файлов. Весь проект https://github.com/fantaisie-s... reBasicIDE

Цитата Сообщение от antro735 Посмотреть сообщение
пурик наглядный пример
Можно попытаться разобраться в исходниках его IDE.

Можно проверять чтобы курсор был не в конце ключевого слова.
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
Procedure SCI_Callback(Gadget, *scinotify.SCNotification) 
  ; Переписываем данные из структуры в переменные 
  code             = *scinotify.SCNotification\nmhdr\code 
  pos              = *scinotify.SCNotification\Position 
  ch               = *scinotify.SCNotification\ch 
  modificationType = *scinotify.SCNotification\modifiers 
  text             = *scinotify.SCNotification\text 
  Length           = *scinotify.SCNotification\length 
  linesAdded       = *scinotify.SCNotification\linesAdded 
  message          = *scinotify.SCNotification\message 
  wParam           = *scinotify.SCNotification\wParam 
  lParam           = *scinotify.SCNotification\lParam 
  LINE             = *scinotify.SCNotification\LINE 
  foldLevelNow     = *scinotify.SCNotification\foldLevelNow 
  foldLevelPrev    = *scinotify.SCNotification\foldLevelPrev 
  margin           = *scinotify.SCNotification\margin 
  listType         = *scinotify.SCNotification\listType 
  x                = *scinotify.SCNotification\x 
  y                = *scinotify.SCNotification\y
  
  Protected CheckWord.s
  
  Select code
    Case #SCN_STYLENEEDED
      ; Узнаём до какой позиции следует подсвечивать синтаксис в редакторе.
      EndStyledPos = ScintillaSendMessage(#Scintilla_Gadget, #SCI_GETENDSTYLED)
      
      ; Узнаём номер строки, до которой следует подсвечивать синтаксис.
      linenumber = ScintillaSendMessage(#Scintilla_Gadget, #SCI_LINEFROMPOSITION, EndStyledPos)
      
      CaretPos = ScintillaSendMessage(#Scintilla_Gadget, #SCI_GETCURRENTPOS)
      
      ; Узнаём позицию первого символа в строке, заданной в "linenumber".
      CurrentPos.l = ScintillaSendMessage(#Scintilla_Gadget, #SCI_POSITIONFROMLINE, linenumber)
      ; Подготовка к стилистической правке (подсветке синтаксиса). 
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_STARTSTYLING, CurrentPos, $1F | #INDICS_MASK)
      
      State = #LexerState_Space
      
      KeywordStartPos = CurrentPos
      keyword.s = "" 
      
      While CurrentPos <= pos
        OldState = State 
        
        ; Получаем символ из текущей позиции курсора.
        Char.l = ScintillaSendMessage(#Scintilla_Gadget, #SCI_GETCHARAT, CurrentPos)
        
        If State <> #LexerState_Comment
          ; Находим комментарии
          If Char = ';'
            ; если это не текст между двойными кавычками
            If CountQuota = 0
              ; Отмечаем текущий текст как комментарий
              State = #LexerState_Comment
            EndIf
          ElseIf Char = '"'
            ; Считаем парность двойных кавычек
            CountQuota + 1
            If CountQuota < 2
              State = #LexerState_String
            Else
              ; сбрасываем счетчик двойных кавычек
              CountQuota = 0
            EndIf
            ; Отмечаем символы "возврата каретки" и "перевода строки" как пробелы.
          ElseIf Char = 10 Or Char = 13
            State = #LexerState_Space
            CountQuota = 0
            ; Если текущий текст НЕ комментарий, отмечаем символы
            ; "Tab" "Пробел" и "Точка" как пробелы.
          ElseIf Char = 9 Or Char = ' '
            If CountQuota = 0
              State = #LexerState_Space
            EndIf
          ElseIf FindString(#SINGLE_SYMB, Chr(Char))
            If CountQuota = 0
              state = #LexerState_Symb
            EndIf
          Else
            If CountQuota = 0
              ; Если совпадения нет, тогда отмечаем как обычный текст
              State = #LexerState_Word
              ; В переменной "keyword" сохраняется текст для поиска ключевых слов
              keyword + Chr(Char)
            EndIf
          EndIf 
        EndIf
        
        If OldState <> State Or CurrentPos = pos
          
          If State = #LexerState_Word
            StartKeyword = CurrentPos
          EndIf
          If OldState = #LexerState_Word
            EndKeyword = CurrentPos
          EndIf
          
          If OldState = #LexerState_Word
            ; Сравниваем текущее слово с ключевыми словами из массива Key()
            For i = 0 To ArraySize(Key())
              ; если в нижних регистрах слова одинаковы
              If LCase(keyword) = LCase(Key(i))
                ; подготавливаем к подсветке как ключевое слово
                oldstate = #LexerState_Keyword
                ; а если в разных регистрах при этом отличаются
                If keyword <> Key(i) And CurrentPos < CaretPos
                  CheckWord = Key(i)
                  
                  *Kwd = UTF8(CheckWord)
                  If *Kwd
                    Len = StringByteLength(CheckWord, #PB_UTF8)
                    ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETTARGETSTART, EndKeyword - Len)
                    ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETTARGETEND, EndKeyword)
                    ScintillaSendMessage(#Scintilla_Gadget, #SCI_REPLACETARGET, Len, *Kwd)
                    FreeMemory(*Kwd)
                  EndIf
                  
                EndIf
                Break
              EndIf
            Next
            keyword = ""
          EndIf
          ; Подсветка ключевых слов
          ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETSTYLING, CurrentPos - KeywordStartPos, OldState)
          KeywordStartPos = CurrentPos
        EndIf 
        
        CurrentPos + 1
      Wend
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETANCHOR, CaretPos) ; Устанавливаем каретку
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETCURRENTPOS, CaretPos) ; Устанавливаем каретку
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETSAVEPOINT)
  EndSelect
EndProcedure
1
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
25.11.2022, 20:57  [ТС]
Обалдеть ! Так быстро найти решение !!! Я больше недели бьюсь над реализацией этого эффекта, а тут буквально молниеносно (сравниваю со своим временным промежутком поиска решения) такое гениальное элегантное решение !!! Интересно, сколько понадобится времени усердной работы над составлениями алгоритмов и кодинга, чтобы хотя бы приблизиться к такому уровню !?

Немного добавил в условие, чтоб он окончательно делал то, чего я добивался:
PureBasic
1
If keyword <> Key(i) And (CurrentPos < CaretPos Or state <> OldState)
И всё же, я так и не могу пока понять, в чём всё же была моя ошибка ? Почему у меня появлялись такие баги ?
0
Эксперт по электронике
6872 / 3295 / 340
Регистрация: 28.10.2011
Сообщений: 12,913
Записей в блоге: 7
25.11.2022, 21:06
Лучший ответ Сообщение было отмечено antro735 как решение

Решение

Цитата Сообщение от antro735 Посмотреть сообщение
Почему у меня появлялись такие баги ?
Потому что замена производилась при следующем вызове процедуры, когда в переменных были другие значения.
Сохранив переменную EndKeyword можно добиться более или менее нормальной работы.
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
Procedure SCI_Callback(Gadget, *scinotify.SCNotification) 
  ; Переписываем данные из структуры в переменные 
  code             = *scinotify.SCNotification\nmhdr\code 
  pos              = *scinotify.SCNotification\Position 
  ch               = *scinotify.SCNotification\ch 
  modificationType = *scinotify.SCNotification\modifiers 
  text             = *scinotify.SCNotification\text 
  Length           = *scinotify.SCNotification\length 
  linesAdded       = *scinotify.SCNotification\linesAdded 
  message          = *scinotify.SCNotification\message 
  wParam           = *scinotify.SCNotification\wParam 
  lParam           = *scinotify.SCNotification\lParam 
  LINE             = *scinotify.SCNotification\LINE 
  foldLevelNow     = *scinotify.SCNotification\foldLevelNow 
  foldLevelPrev    = *scinotify.SCNotification\foldLevelPrev 
  margin           = *scinotify.SCNotification\margin 
  listType         = *scinotify.SCNotification\listType 
  x                = *scinotify.SCNotification\x 
  y                = *scinotify.SCNotification\y
  
  Static CheckWord.s, OldEndKeyword
  
  Select code
    Case #SCN_STYLENEEDED
      ; Узнаём до какой позиции следует подсвечивать синтаксис в редакторе.
      EndStyledPos = ScintillaSendMessage(#Scintilla_Gadget, #SCI_GETENDSTYLED)
      
      ; Узнаём номер строки, до которой следует подсвечивать синтаксис.
      linenumber = ScintillaSendMessage(#Scintilla_Gadget, #SCI_LINEFROMPOSITION, EndStyledPos)
      
      CaretPos = ScintillaSendMessage(#Scintilla_Gadget, #SCI_GETCURRENTPOS)
      
      ; Узнаём позицию первого символа в строке, заданной в "linenumber".
      CurrentPos.l = ScintillaSendMessage(#Scintilla_Gadget, #SCI_POSITIONFROMLINE, linenumber)
      ; Подготовка к стилистической правке (подсветке синтаксиса). 
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_STARTSTYLING, CurrentPos, $1F | #INDICS_MASK)
      
      State = #LexerState_Space
      
      KeywordStartPos = CurrentPos
      keyword.s = "" 
      
      While CurrentPos <= pos
        OldState = State 
        
        ; Получаем символ из текущей позиции курсора.
        Char.l = ScintillaSendMessage(#Scintilla_Gadget, #SCI_GETCHARAT, CurrentPos)
        
        If State <> #LexerState_Comment
          ; Находим комментарии
          If Char = ';'
            ; если это не текст между двойными кавычками
            If CountQuota = 0
              ; Отмечаем текущий текст как комментарий
              State = #LexerState_Comment
            EndIf
          ElseIf Char = '"'
            ; Считаем парность двойных кавычек
            CountQuota + 1
            If CountQuota < 2
              State = #LexerState_String
            Else
              ; сбрасываем счетчик двойных кавычек
              CountQuota = 0
            EndIf
            ; Отмечаем символы "возврата каретки" и "перевода строки" как пробелы.
          ElseIf Char = 10 Or Char = 13
            State = #LexerState_Space
            CountQuota = 0
            ; Если текущий текст НЕ комментарий, отмечаем символы
            ; "Tab" "Пробел" и "Точка" как пробелы.
          ElseIf Char = 9 Or Char = ' '
            If CountQuota = 0
              State = #LexerState_Space
            EndIf
          ElseIf FindString(#SINGLE_SYMB, Chr(Char))
            If CountQuota = 0
              state = #LexerState_Symb
            EndIf
          Else
            If CountQuota = 0
              ; Если совпадения нет, тогда отмечаем как обычный текст
              State = #LexerState_Word
              ; В переменной "keyword" сохраняется текст для поиска ключевых слов
              keyword + Chr(Char)
            EndIf
          EndIf 
        EndIf
        
        If OldState <> State Or CurrentPos = pos
          
          If State = #LexerState_Word
            StartKeyword = CurrentPos
          EndIf
          If OldState = #LexerState_Word
            EndKeyword = CurrentPos
          EndIf
          
          If CheckWord
            ; Меняем вид ключевого слова
            ;----------------------------
            ; Сохраняем адрес строки с ключевым словом
            *Kwd = UTF8(CheckWord)
            Len = StringByteLength(Key(i), #PB_UTF8)
            
            ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETTARGETSTART, OldEndKeyword - Len)
            ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETTARGETEND, OldEndKeyword)
            ScintillaSendMessage(#Scintilla_Gadget, #SCI_REPLACETARGET, Len, *Kwd)
            
            ;ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETANCHOR, CaretPos) ; Устанавливаем каретку
            ;ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETCURRENTPOS, CaretPos) ; Устанавливаем каретку
            
            FreeMemory(*Kwd)
            OldState = #LexerState_Keyword
            CheckWord = ""
          EndIf
          
          If OldState = #LexerState_Word
            ; Сравниваем текущее слово с ключевыми словами из массива Key()
            For i = 0 To ArraySize(Key())
              ; если в нижних регистрах слова одинаковы
              If LCase(keyword) = LCase(Key(i))
                ; подготавливаем к подсветке как ключевое слово
                oldstate = #LexerState_Keyword
                ; а если в разных регистрах при этом отличаются
                If keyword <> Key(i)
                  CheckWord = Key(i)
                  OldEndKeyword=EndKeyword
                EndIf
                Break
              EndIf
            Next
            keyword = ""
          EndIf
          ; Подсветка ключевых слов
          ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETSTYLING, CurrentPos - KeywordStartPos, OldState)
          
          KeywordStartPos = CurrentPos
        EndIf 
        
        CurrentPos + 1
      Wend
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETANCHOR, CaretPos) ; Устанавливаем каретку
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETCURRENTPOS, CaretPos) ; Устанавливаем каретку
      ScintillaSendMessage(#Scintilla_Gadget, #SCI_SETSAVEPOINT)
  EndSelect
EndProcedure
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
25.11.2022, 21:24  [ТС]
Дошло. Да, при следующем вызове процедуры значения уже другие. Кстати, добавленное мной условие немного не то делает, но я над этим сейчас подумаю, чтоб добиться всё-таки чего я хочу окончательно.
Благодарю, locm !!! Замечательное решение и объяснение !!!!
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
26.11.2022, 03:11
locm, я попробовал последний вариант, endif после пробела заменяется на EnEnd.
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
26.11.2022, 04:13  [ТС]
AZJIO, у меня без багов работает. Сейчас, вот, подумаю как проработать, чтоб если пробел или символ с другим лексером уже присутствует после ключевого слова, значит, можно сразу же как только слово появилось, вместе с подсветкой тут же делать и замену. В принципе, я такой вариант сделал, но тут оказалось, что если ниже есть пусть даже пустая строка, символы перехода на следующую строку и возврата каретки сразу же создают условие для замены ключевого слова. Нужно, чтобы последний символ до которого работает подсветка строки был как раз перед этими двумя неотображаемыми символами. Ну, тут, думаю, справлюсь с этим.
А почему у тебя некорректно происходит замена, интересно... У меня отрабатывает без нареканий.
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
28.11.2022, 04:35
locm, пробовал ранее #SCI_GETENDSTYLED, у меня всегда возвращает 0. И мне было не понятно "GET END STYLED", а где же "GET START STYLED"? Это работает от начала текста? С позиции 0? Если от начала строки, то как будет обрабатываться вставка многострочного текста.
Пока тестировал используя Debug для #SCI_GETENDSTYLED, обнаружил, что у меня события #SCN_STYLENEEDED высылаются каждую секунду вне зависимости ввожу я текст или нет. Проверил ваш код выше и этого не было, событие 1 раз после ввода символа, как положено. Естественно я начал искать проблему в своём коде и самое интересное я комментирую все функции оставляя только #SCN_STYLENEEDED и Debug и это не исправляет ситуацию, закомментировал все функции установки параметров после ScintillaGadget(), не помогает. В общем совершенно ничего не помогает, попробовал все варианты, которые я мог представить.
Также проверил свою прогу "Grub2-generator", #SCN_STYLENEEDED там тоже высылает каждую секунду событие, но там вместо #SCN_STYLENEEDED я использовал #SCN_CHARADDED и #SC_MOD_INSERTTEXT, то есть движок не досит гаджет. Есть идеи?
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
28.11.2022, 05:09  [ТС]
Если я правильно понимаю, после того как происходит событие SCN_STYLENEEDED, то есть, какое-то изменение текста в редакторе, побуждающее стилировать строку, запускается команда подготовки к стилированию SCI_STARTSTYLING. Если перерисовка, которую выполняет SCI_SETSTYLING не произошла, запрос SCN_STYLENEEDED так и будет постоянно отправляться пока не будет произведена перерисовка. Возможно, я ошибаюсь, но по-моему это здесь так работает.
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
28.11.2022, 07:08
Проверил, если ввёл код, который требует раскраски, то есть срабатывает SCI_SETSTYLING, то прекращается повторные уведомления SCN_STYLENEEDED, если же ввёл иной текст, который не требует раскраски, то уведомление SCN_STYLENEEDED приходит каждую секунду. Может я чего не понимаю, но если не сработал SCI_SETSTYLING то есть нечего подкрашивать и я не ввожу текст, то как я понимаю SCN_STYLENEEDED должен прекратиться. На данный момент так как SCI_GETENDSTYLED у меня возвращает 0 то использование его ни к чему не приводит, диапазон от нуля до нуля ничего не подкрасит в тексте, поэтому я подкрашиваю весь текст. Естественно не хочется чтобы файл размером 200 кб каждую секунду пытался подкрашиваться 16-надцатью регулярными выражениями.
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
28.11.2022, 07:31  [ТС]
Тогда, вероятно, нужно создавать условие для строки:
PureBasic
1
ScintillaSendMessage(#Scintilla_Gadget, #SCI_STARTSTYLING, CurrentPos, $1F | #INDICS_MASK)
Она-то как раз и отправляет запрос в каких случаях делать стилизацию, а в каких нет. Если для этой строки не прописано никаких условий, она будет запрашивать стилизацию для каждого вновь вводимого или удаляемого символа. Не знаю, может быть, есть способ и более элегантный, но это первое что приходит в голову.
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
28.11.2022, 08:02
antro735,
SCI_STARTSTYLING задаёт начальную позицию для подкрашивания. А SCI_SETSTYLING задаёт длину слова и подкрашивает. Второй параметр SCI_STARTSTYLING не используется - unused)
SCI_STARTSTYLING(position start, int unused)
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
28.11.2022, 08:34  [ТС]
Ну, да, в документации написано, что в SCI_STARTSTYLING(position start, int unused) второй параметр устарел и сейчас не используется. Однако, в любом случае, какую-то стартовую позицию он будет задавать, и будет ждать, когда произойдёт перерисовка. То есть, он отправляет запрос на подготовку к стилической правке и ждать эту самую правку, пока она будет выполнена. Чтоб избежать правки, нужно, чтоб эта строка не отправляла запрос. Значит, нужны условия, когда запрос будет отправлен, а когда нет.
То есть, если текущий символ, к примеру, "$", то полностью исключить исполнение SCN_STYLENEEDED

Добавлено через 10 минут
Другими словами, что-то вроде вот этого:

PureBasic
1
2
3
4
5
Case #SCN_STYLENEEDED
  If Char <> ',' And Char <> '$'
    ; тут реализация стилистики
  EndIf
EndSelect
Хотя, в документации написано, что он всегда обрабатывает целую строку полностью. Вряд ли он исключает из стилизации какие-то фрагменты строки
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
28.11.2022, 08:44
Ты же говорил SCN_STYLENEEDED требует SCI_SETSTYLING, а теперь говоришь что мешает SCI_STARTSTYLING.
SCI_SEARCHINTARGET возвращает -1 если не найден искомый элемент для подсветки. Если не найден, то никакие функции SCI_STARTSTYLING/SCI_SETSTYLING не выполняются.
Сейчас попробовал ProcedureReturn #True / #False так как в уведомлениях листвью и "перетащить и бросить" есть способы отмены операций выпрыгивая с помощью возврата #True или #False, не помогло.
Заметил, открыл большой файл grub.cfg и функционал не досил уведомлениями. Если открываю пустой и ввожу Enter (перенос строки) и посыпались уведомления. Здесь же пример выше аналогично пустой элемент, Enter и ничего не происходит (Debug вставлен)

По поводу примера, я же говорил, после SCN_STYLENEEDED я всё закомментировал, нет никаких условий и команд, только отлов событий SCN_STYLENEEDED, а ну Debug только для проверки сколько уведомлений приходит.
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
28.11.2022, 08:58  [ТС]
Я сейчас начал прорабатывать индикаторную подсветку для множественного выделения текста, чтоб как в пурике - выделил слово, и по всему коду везде где есть это слово, оно во всём коде подсвечивается. Тут тоже покубатурить придётся, вернее, не придётся, а уже это происходит )))

Ты же говорил SCN_STYLENEEDED требует SCI_SETSTYLING
Тут смысл такой - SCN_STYLENEEDED в любом случае при вводе каждого символа или его удалении будет активирован, но за подготовку к стилизации отвечает SCI_STARTSTYLING. Именно SCI_STARTSTYLING отдаёт команду к стилической правке и потом ждёт выполнения этой правки. Если SCI_STARTSTYLING не отправит запрос на стилизацию, то и ожидать этой правки не будет. Однако, может быть, я и не прав, если документация утверждает, что Scintilla ВСЕГДА стилизует строку полностью, и, возможно, не удастся пропустить даже один символ без стилизации. Просто, для каждого символа будет свой стиль, или для группы символов - это уже как ты сам создашь условия стилизации. Сейчас попробую проэкспериментировать, будет ли он пропускать какие-либо символы без стилизации...
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
28.11.2022, 09:22
antro735, ну это же выдумки, в документации нет того что ты пишешь. Тебе кажется что так работает, но это не обязательно так. Ты можешь только доказывать реальным поведением движка используя примеры. Зачем SCI_STARTSTYLING что-то там активировать? Попробуй думать как разработчики. Им нужно подсветить слово. Значит должно быть слово или позиции откуда докуда подсвечивать. Используя SCI_SEARCHINTARGET я получаю позицию слова для подсветки, позицию конца я могу вычислить прибавив к позиции длину слова. Итак позиции есть, смотрим что нам предоставляет движок Scintilla, а предоставляет он возможность задать начало подсветки SCI_STARTSTYLING, а SCI_SETSTYLING задаёт длину подсветки и подсвечивает. Внимание вопрос, зачем к этим функциям привязывать ещё какие-то действия? Тебе надо подсветить, ты подсветил, с чего SCI_STARTSTYLING должен там что-то запустить то после чего гаджет Scintilla поломается? И так все функции, если SCI_POSITIONFROMLINE возвращает позицию начала, то это просто возвращает число, а не запускает какой-то движок после которого если что-то там не выполнишь то Scintilla упадёт, совсем нет, вот так просто это работает.
0
1 / 1 / 0
Регистрация: 28.07.2018
Сообщений: 124
28.11.2022, 09:30  [ТС]
Задуманный эксперимент не представляется возможным, там ведь распознание символов происходит уже после того как отправляется команда SCI_STARTSTYLING. И окончание стилизации происходит по условию
PureBasic
1
While CurrentPos <= pos
Pos, как я выяснил, это текущая строка, и ещё пару строк ниже, если они, конечно, есть, и выдернуть хотя бы один символ из этого потока символов в строке без стилирования, по-видимому не удастся. То есть, каждый символ имеет либо стиль по умолчанию (чёрный цвет), либо принимает стиль одного из имеющихся лексеров. Я так понимаю, что без стиля не остаётся ни один символ. Хотя бы по умолчанию, но стиль будет.
Вот что написано в документации:

SCI_GETENDSTYLED → position
Scintilla хранит запись последнего символа, который, вероятно, будет создан правильно. Это перемещается вперед, когда символы после этого стилизованы и перемещаются назад, если перед текстом документа внесены изменения. Перед рисованием текста эта позиция проверяется, если требуется какой-либо стиль и, если это так, сообщение уведомления SCN_STYLENEEDED отправляется в контейнер. Контейнер может отправить SCI_GETENDSTYLED для разработки, где ему нужно начать стилизацию. Scintilla всегда будет запрашивать стиль целых строк.

Но тут такой мутный перевод, что толком понять его как-то не очень легко. Вообще, SCI_GETENDSTYLED - даже по названию - до какой позиции производится стилизация, а из документации складывается впечатление, что SCI_GETENDSTYLED зто начало стилизации.
0
63 / 61 / 3
Регистрация: 06.11.2010
Сообщений: 186
Записей в блоге: 1
28.11.2022, 09:56
там есть внутренние лексеры, ты же не знаешь точно о каком лексере говорится. Фактически любое изменение (ввод символа, удаление символа/текста, вставка текста из буфера, замена одно другим) требует пересмотра, отсюда и необходимость подсвечивания. Но я то ранее начал речь о том что ничего не происходит, какого либо изменения и происходит прилёт уведомлений. На счёт всё должно быть в стилях, по сути стиль не привязывается к тексту ни как, у буквы есть поле, как структура, как будто буква многоэтажный дом, на первом этаже буква, на втором этаже цвет буквы, на третьем ещё что-нибудь. Движок Scintilla подкрашивает каждую букву исходя из данных находящихся на втором этаже, в общем данные привязанные к этой букве. В отличии от индикаторов стиль в моём блокноте подкрашивается в несколько проходов регулярными выражениями и может последний рег.выр. перекрасить то что было покрашено первым рег.выром. Индикаторы действуют по-другому, если покрасил букву регвыром, то второй регвыр не может перекрасить её, вернее поиск для покраски просто игнорирует покрашеные, точнее он ищет первую непокрашенную букву, потом находит после нею покрашенную и это диапазон для возможной покраски, потом ищет с помощью регулярного выражения внутри непокрашенного диапазона и если находит то красит его и это диапазон тоже становится неприступным. Чтобы сделать опять доступным надо очистить индикаторы. То есть создание рег.выр немного по-иному, сначала подкрашиваются те, которые точно являются гарантированными элементами кода, а уж потом между них ищутся например операторы, со стилем наоборот сначала операторы, потом другие элементы, иначе операторы подсветят внутри других элементов.

Покраска целых строк, потому что если ту удались символ внутри слова, то ты не можешь его подкрасить от начала слова до курсора, так как оно будет составлять часть ключевого слова. А перенос строк является разделителем, поэтому перекрашивая строку будет правильно подкрашиваться.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.11.2022, 09:56
Помогаю со студенческими работами здесь

С текстовым редактором C++ Builder
Всем привет, нужна ваша помощь. Делаю текстовый редактор, окно сохранить, открыть файл уже готовы. Вопрос следующий. Как сделать так,...

Помощь с текстовым редактором
ребят нужна помощь!) нужно в текстовом редакторе сделать правописание жи-ши , т.е. пишим ЖЫ или Шы он должен подчекнуть и исправить по...

Ввод и вывод массива с текстовым редактором
Ребят помогите срочно нужно сделать так чтобы считывался массив с in.txt и отправлялся полученный результат в out.txt {$R+} uses crt; ...

Обработка больших файлов текстовым редактором
У меня задание написать текстовый редактор, в целом всё ясно, за исключение пункта: &quot;возможность обработки больших файлов&quot;. Я не...

Сценарий PowerShell для работы с текстовым редактором
Доброго времени суток!!! Очень нуждаюсь в вашей помощи! Начали изучать в университете новый предмет, лекции читают про то как работают ОС,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер. Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром. возможно получится прикрутить интерпретатор питон для кастомизации игровой логики. что есть на текущий момент:. . .
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2. Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru