Реализация редактора
От: Praetor  
Дата: 17.09.06 20:54
Оценка:
Необходимо сделать редактор кода скриптового языка. Используемая библиотека — wxWidgets. Будет подстветка, автокомплишн и т п. Вопрос — как лучше реализовать окно редактора? Реализовывать все с нуля (выводить текст с помощью API-функций Windows) или есть какоая-нибудь библиотечка, где реализована редактирование текстовых файлов?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Реализация редактора
От: Аноним  
Дата: 17.09.06 21:01
Оценка: +1
Здравствуйте, Praetor, Вы писали:

P>Необходимо сделать редактор кода скриптового языка. Используемая библиотека — wxWidgets. Будет подстветка, автокомплишн и т п. Вопрос — как лучше реализовать окно редактора? Реализовывать все с нуля (выводить текст с помощью API-функций Windows) или есть какоая-нибудь библиотечка, где реализована редактирование текстовых файлов?


Ричэдит контрол не подойдёт?
Re[2]: Реализация редактора
От: Praetor  
Дата: 17.09.06 21:03
Оценка:
Видимо, нет. Требование — должен быть автокомплишн, а это — всплывающее окно, к ричедиту его не прикрутить.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Реализация редактора
От: denaturat  
Дата: 18.09.06 07:02
Оценка:
Здравствуйте, Praetor, Вы писали:

P>Видимо, нет. Требование — должен быть автокомплишн, а это — всплывающее окно, к ричедиту его не прикрутить.


Я прикручивал прикола ради. Все работало.

Можешь и сцинтиллу использовать.

Если хочешь свой редактор, то могу дать несколько советов:
1. текст хранить надо в массиве строк, а не в сплошном буфере, ибо представь себе realloc после ввода в середину текста одного символа при тексте размером в пару мегабайт. вполне подойдет std::string
2. окошко, естественно, свое, с нуля.
3. для меня удобнее оказалось сделать отдельно окно редактирования + скроллбары + подложка под все это, ибо нельзя ставить твоему редактру стил WS_HSCROLL | WS_VSCROLL, ибо сие только до 32тыс строк работать будет.
4. не рассчитывай на шрифт определенного размера (моноширинный), ориентируйся сразу на пропорциональный.
5. Высоту строк можно вычислять, если принять допущение, что текст только одной высоты.
6. для рисовалки используй MemDC, а не сразу в WM_PAINT.
7. рисуй ТОЛЬКО в WM_PAINT!!! Посмотри на блокнот — он строки отрисовывает не только в WM_PAINT, а где-то еще, поэтому субклассировать для отрисовки его сложновато.
8. Прокрутку по горизонтали привяжи к пикселам (ну не к символам же, если шрифт пропорциональный), а по вертикали — к строкам.
9. функцию подсветки реализуй в виде отдельного элемента, а в член класса твоего окна включи только указатель на нее.
10. делай сразу для уникода, с внутренним преобразованием в ASCII<->Unicode передаваемого буфера (используй MSLU).
11. автокомплит — т.е. окошко — сделай из субклассированного листбокса, который закрываетс япо двойномй клику, Esc и Enter. Пусть при закрытии он посылает сообщение с указателем на буфер, содержащий выбранную строку. Как ты обработаешь эту строку — твое дело, в зависимости от назначения твоего редактора.
11. не встраивай в базовый редактор автокомплит — лучше использовать производный класс.

пока хватит

Все это может занять чуть меньше недели.
Re[4]: Реализация редактора
От: Left2 Украина  
Дата: 18.09.06 08:13
Оценка:
D>Если хочешь свой редактор, то могу дать несколько советов:
D>1. текст хранить надо в массиве строк, а не в сплошном буфере, ибо представь себе realloc после ввода в середину текста одного символа при тексте размером в пару мегабайт. вполне подойдет std::string
Если ты имеешь в виду std::vector<std::string>, то это тоже паршивенькое решение — поскольку переаллокации при вставке, к примеру, строки в начало — будут точно такими же. Из простых решений тут просится присвоение каждой строке своего уникального идентификатора (они потом будут удобны для реализации меток и т.п.), и иметь std::map<UniqID, std::string> для самих строк + массив идентификаторов (это и будут собственно строки). При таком подходе довольно большие куски текста можно мувить практически без переаллокаций.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Реализация редактора
От: denaturat  
Дата: 18.09.06 09:04
Оценка:
Здравствуйте, Left2, Вы писали:

D>>Если хочешь свой редактор, то могу дать несколько советов:

D>>1. текст хранить надо в массиве строк, а не в сплошном буфере, ибо представь себе realloc после ввода в середину текста одного символа при тексте размером в пару мегабайт. вполне подойдет std::string
L>Если ты имеешь в виду std::vector<std::string>, то это тоже паршивенькое решение — поскольку переаллокации при вставке, к примеру, строки в начало — будут точно такими же. Из простых решений тут просится присвоение каждой строке своего уникального идентификатора (они потом будут удобны для реализации меток и т.п.), и иметь std::map<UniqID, std::string> для самих строк + массив идентификаторов (это и будут собственно строки). При таком подходе довольно большие куски текста можно мувить практически без переаллокаций.

особых тормозов не замечал, но если твое решение лучше — то будем знать
Re[4]: Реализация редактора
От: Praetor  
Дата: 18.09.06 17:39
Оценка:
denaturat, спасибо за советы, учту. По поводу хранения символов — конечно, я не буду использовать единый буфер, это ведь плохо не только из-за того, что происходит сплошное перелопаичвание при вставке символа, от этого страдает в первую очередь дизайн программы. А при отрисовке символов (с двойной буферизацией) придется пользоваться напрямую апи функциями, т к wxWidgets, который я использую, я почти не знаю (третий день с ним).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Реализация редактора
От: Praetor  
Дата: 18.09.06 17:51
Оценка: :))
Здравствуйте, Left2, Вы писали:

D>>Если хочешь свой редактор, то могу дать несколько советов:

D>>1. текст хранить надо в массиве строк, а не в сплошном буфере, ибо представь себе realloc после ввода в середину текста одного символа при тексте размером в пару мегабайт. вполне подойдет std::string
L>Если ты имеешь в виду std::vector<std::string>, то это тоже паршивенькое решение — поскольку переаллокации при вставке, к примеру, строки в начало — будут точно такими же. Из простых решений тут просится присвоение каждой строке своего уникального идентификатора (они потом будут удобны для реализации меток и т.п.), и иметь std::map<UniqID, std::string> для самих строк + массив идентификаторов (это и будут собственно строки). При таком подходе довольно большие куски текста можно мувить практически без переаллокаций.

Почему же, если использовать не вектор строк, а вектор указателей на строки, то таких переалллокаций быть не должно, точнее, переаллокации конечно будут, ведь это вектор, но там будут колбасится уже указатели на строки, а не сами строки. Современные процы перемолотят это дело с такой скоростью что не заметишь. С точки зрения уменьшения таких переаллокаций подойдет любой список указателей, не обязательно даже хешированный, просто мапы, как ты говоришь, удобно использовать для создания меток и пр. идентификации строк.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Реализация редактора
От: denaturat  
Дата: 19.09.06 06:11
Оценка:
Здравствуйте, Praetor, Вы писали:

[]
(для Wimdows)
Есть небольшая тонкость при определении длины строк. Как везде пишут, для этого используется GetTextExtentPoint32. Но есть маленькое но. Если у тебя текст прокручен по горизонтали, то она может не совсем верно определять длину строки, если есть символы табуляции (они же почти всегда занимают разную ширину). Для верного определения ширины строки я использовал такую комбинацию:
создавал CMemDC, совместимую с той, куда выводится текст.
Выводил туда текст с помощью TabbedTextOut, а она возвращает размер выведенной строки.
Найденную ширину и возвращал.
Зачем? — Для позиционирования каретки.
Это не самое лучшее решение, но работало без проблем с вычислением размеров.
Может, кто найдет решение получше, ибо это — самое слабое место, сильно грузящее проц. случай с GetTextExtentPoint32 особого выигрыша не дает.
Для моноширинных шрифтов можно упростить вычисления, и выводить всю строку, тогда как в случае пропорциональных строку надо выводить частями.

Алгоритм подсветки могу подарить

Создаем массив состояний (тип unsigned char, например). Состояния — по вкусу: PLAINTEXT, COMMENTSTART, COMMENTEND...
Сколько строк, столько и элементов.
Каждый элемент этого массива хранит состояние, которым закончилась предудущая строка.
При загрузке текста вс эти элементы устанавливаются в неопределенное состояние.
При окраске первоначально парсится только тот текст, который от первой строки до последней видимой.
Затем, если, например, мы крутим текст вниз, скроллируем окно и парсим следующую вылезшую строку, одновременно рисуя ее.
Запоминаем в следующем элементе массива состояний то, которое было последним.
Если мы правим строку, то мы чистим весь массив состояний (или часть) вниз от той строки, которую исправили, включая ее саму.
Пишем функцию (то, что я уже говорил) такого вида

unsigned char MyLexer(TCHAR* lpszInputBuffer, unsigned char lastState, long* pOutTokenLength);


она принимает входной буфер (ту строку, которую мы хотим вывести), последнее состояние (ну, например, до этого вызова было состояние COMMENTSTART) и указатель на длину выходного токена.
Возвращает она то состояние, которое было вычислено при этом вызове, и длину пропарсенного буфера.

Вызывающая функция (OnPaint, к примеру) ищет параметры (цвет, шрифт ...) полученного состояния и выводит буфер указанной длины. Если строка не закончилась, то снова вызывается лексический анализатор, а если закончилась — в следующем элементе массива состояний запоминается последнее найденное состояние, и другая строка начинает парситься начиная с этого состояния.

По такому принципу можно сделать редактор, запихнуть его в dll, а лексические анализаторы писать отдельно.
Re[6]: Реализация редактора
От: Praetor  
Дата: 19.09.06 18:34
Оценка:
Здравствуйте, denaturat, Вы писали:

D>Здравствуйте, Praetor, Вы писали:


D>[]

D>(для Wimdows)
D>Есть небольшая тонкость при определении длины строк. Как везде пишут, для этого используется GetTextExtentPoint32. Но есть маленькое но. Если у тебя текст прокручен по горизонтали, то она может не совсем верно определять длину строки, если есть символы табуляции (они же почти всегда занимают разную ширину). Для верного определения ширины строки я использовал такую комбинацию:
D>создавал CMemDC, совместимую с той, куда выводится текст.
D>Выводил туда текст с помощью TabbedTextOut, а она возвращает размер выведенной строки.
D>Найденную ширину и возвращал.
D>Зачем? — Для позиционирования каретки.
D>Это не самое лучшее решение, но работало без проблем с вычислением размеров.
D>Может, кто найдет решение получше, ибо это — самое слабое место, сильно грузящее проц. случай с GetTextExtentPoint32 особого выигрыша не дает.
D>Для моноширинных шрифтов можно упростить вычисления, и выводить всю строку, тогда как в случае пропорциональных строку надо выводить частями.

D>Алгоритм подсветки могу подарить


D>Создаем массив состояний (тип unsigned char, например). Состояния — по вкусу: PLAINTEXT, COMMENTSTART, COMMENTEND...

D>Сколько строк, столько и элементов.
D>Каждый элемент этого массива хранит состояние, которым закончилась предудущая строка.
D>При загрузке текста вс эти элементы устанавливаются в неопределенное состояние.
D>При окраске первоначально парсится только тот текст, который от первой строки до последней видимой.
D>Затем, если, например, мы крутим текст вниз, скроллируем окно и парсим следующую вылезшую строку, одновременно рисуя ее.
D>Запоминаем в следующем элементе массива состояний то, которое было последним.
D>Если мы правим строку, то мы чистим весь массив состояний (или часть) вниз от той строки, которую исправили, включая ее саму.
D>Пишем функцию (то, что я уже говорил) такого вида

D>
D>unsigned char MyLexer(TCHAR* lpszInputBuffer, unsigned char lastState, long* pOutTokenLength);
D>


D>она принимает входной буфер (ту строку, которую мы хотим вывести), последнее состояние (ну, например, до этого вызова было состояние COMMENTSTART) и указатель на длину выходного токена.

D>Возвращает она то состояние, которое было вычислено при этом вызове, и длину пропарсенного буфера.

D>Вызывающая функция (OnPaint, к примеру) ищет параметры (цвет, шрифт ...) полученного состояния и выводит буфер указанной длины. Если строка не закончилась, то снова вызывается лексический анализатор, а если закончилась — в следующем элементе массива состояний запоминается последнее найденное состояние, и другая строка начинает парситься начиная с этого состояния.


D>По такому принципу можно сделать редактор, запихнуть его в dll, а лексические анализаторы писать отдельно.



Спасибо за советы, denaturat. Я вообще-то планировал рендерить весь текст во вторичном буфере, а потом копировать по ширине окна. Хотя и всамом деле, невидимы текст нет смысла выводить, но тогда не нужно будет вычислять высоту строки. Надо будет тут еще подумать...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: Реализация редактора
От: denaturat  
Дата: 20.09.06 07:01
Оценка:
Здравствуйте, Praetor, Вы писали:


P>Я вообще-то планировал рендерить весь текст во вторичном буфере, а потом копировать по ширине окна.


Так, в общем-то и делается, к примеру, на WTL можно так:

// ... где-то в OnPaint
CPainDC paint_dc(m_hWnd);
CMemDC dc(paint_dc);
// а тут рисуем все в объекте dc
// перед выходом из функции содержимое dc (в деструкторе CMemDC) 
// копируется в нужный квадрат paint_dc


Заодно избавишься от моргания при отрисовке. еще — обрабатывай WM_ERASEBKGND, чтобы процедура по умолчанию не перерисовывала цветом фона окно, т.к. это тоже приводит к мерцанию картинки.
Re[4]: Реализация редактора
От: 0rc Украина  
Дата: 20.09.06 07:52
Оценка:
Здравствуйте, denaturat, Вы писали:

Пару уточнений и замечаний

D>1. текст хранить надо в массиве строк, а не в сплошном буфере, ибо представь себе realloc после ввода в середину текста одного символа при тексте размером в пару мегабайт. вполне подойдет std::string


Это решение ненамного лучше сплошного буфера. Правильное решение хранить либо в виде списка строк (простой вариант), либо в виде дерева объектов (этот вариант зачастую используется в более сложных вариантах)

D>3. для меня удобнее оказалось сделать отдельно окно редактирования + скроллбары + подложка под все это, ибо нельзя ставить твоему редактру стил WS_HSCROLL | WS_VSCROLL, ибо сие только до 32тыс строк работать будет.


Неправда, нет такого ограничения.

D>4. не рассчитывай на шрифт определенного размера (моноширинный), ориентируйся сразу на пропорциональный.

D>5. Высоту строк можно вычислять, если принять допущение, что текст только одной высоты.

ИМХО всегда нужно вычислять высоту строки и длину. Это даст выигрыш в масштабируемости в будущем.

D>6. для рисовалки используй MemDC, а не сразу в WM_PAINT.


Если есть ограничение по памяти этот вариант не подойдет. А вот вариант с "правильным клиппингом" подойдет.

D>7. рисуй ТОЛЬКО в WM_PAINT!!! Посмотри на блокнот — он строки отрисовывает не только в WM_PAINT, а где-то еще, поэтому субклассировать для отрисовки его сложновато.


Если посмотреть действительно на блокнот, то там кроме компонента Edit со стилем ES_MULTILINE ничего нет. Могу предположить, что в блокноте вообще нет перехвата WS_PAINT.

D>8. Прокрутку по горизонтали привяжи к пикселам (ну не к символам же, если шрифт пропорциональный), а по вертикали — к строкам.


Снова сомнительное допущение и совет. Если редактор служит не только как набиратель букв, но и подразумевается в будущем вывод букв на печать — привязыватся следует к логическим единицам. А, при больших объемах текста следует отрисовывать только когда пользователь отжал левую кнопку мыши. Т.е. вообще совершенно другой тип привязки.

D>Все это может занять чуть меньше недели.


Сколько, сколько? Да при таких темпах мы давно бы жили на Марсе!
Re[5]: Попорядку - WS_xSCROLL
От: denaturat  
Дата: 20.09.06 09:12
Оценка:
Здравствуйте, 0rc, Вы писали:

D>>3. для меня удобнее оказалось сделать отдельно окно редактирования + скроллбары + подложка под все это, ибо нельзя ставить твоему редактру стил WS_HSCROLL | WS_VSCROLL, ибо сие только до 32тыс строк работать будет.


0rc>Неправда, нет такого ограничения.


Имелось в виду это:

WM_HSCROLL Notification
........................................................
Remarks

The SB_THUMBTRACK request code is typically used by applications that provide feedback as the user drags the scroll box.

If an application scrolls the content of the window, it must also reset the position of the scroll box by using the SetScrollPos function.

Note that the WM_HSCROLL message carries only 16 bits of scroll box position data. Thus, applications that rely solely on WM_HSCROLL (and WM_VSCROLL) for scroll position data have a practical maximum position value of 65,535.

However, because the SetScrollInfo, SetScrollPos, SetScrollRange, GetScrollInfo, GetScrollPos, and GetScrollRange functions support 32-bit scroll bar position data, there is a way to circumvent the 16-bit barrier of the WM_HSCROLL and WM_VSCROLL messages. See GetScrollInfo for a description of the technique.


дабы не вздумать использовать wParam в WM_xSCROLL, так что поправлюсь.

Сам попробуй — после этого предела наступает фигня с прокруткой. Не возражаю и против установки стиле WS_xSCROLL, но это было удобнее мне. Глянь и на редактор в VS — там контрол редактирования не использует эти стили.
Re[5]: По порядку - std::string
От: denaturat  
Дата: 20.09.06 09:15
Оценка:
Здравствуйте, 0rc, Вы писали:


D>>1. текст хранить надо в массиве строк, а не в сплошном буфере, ибо представь себе realloc после ввода в середину текста одного символа при тексте размером в пару мегабайт. вполне подойдет std::string


0rc>Это решение ненамного лучше сплошного буфера. Правильное решение хранить либо в виде списка строк (простой вариант), либо в виде дерева объектов (этот вариант зачастую используется в более сложных вариантах)


Предлагаете то же самое, только вместо массива — список. Может, std::list и лучше std::vector, но принципиальной разницы не вижу
Re[5]: По порядку - остальное
От: denaturat  
Дата: 20.09.06 09:27
Оценка:
Здравствуйте, 0rc, Вы писали:

D>>6. для рисовалки используй MemDC, а не сразу в WM_PAINT.


0rc>Если есть ограничение по памяти этот вариант не подойдет. А вот вариант с "правильным клиппингом" подойдет.


Речи о памяти не шло. Но предложение поддерживаю

0rc>Если посмотреть действительно на блокнот, то там кроме компонента Edit со стилем ES_MULTILINE ничего нет. Могу предположить, что в блокноте вообще нет перехвата WS_PAINT.


да, он рисует когда и где захочет, точнее, когда изменилось выделение или ввели символ, причем рисует всю строку

D>>8. Прокрутку по горизонтали привяжи к пикселам (ну не к символам же, если шрифт пропорциональный), а по вертикали — к строкам.


0rc>Снова сомнительное допущение и совет. Если редактор служит не только как набиратель букв, но и подразумевается в будущем вывод букв на печать — привязыватся следует к логическим единицам. А, при больших объемах текста следует отрисовывать только когда пользователь отжал левую кнопку мыши. Т.е. вообще совершенно другой тип привязки.


Кому чего. Про печать я вообще ничего не говорил и про масштабируемость.
А вообще, народ, часто ли вы печатаете из редактора кода свои программки? (Человек хочет сделать это) Я как-то попытался из VC++6 пару лет назад загнать на принтер кое-чего, так бумагу жалко стало из-за нечитаемости русских букв.

D>>Все это может занять чуть меньше недели.

Если учесть, что до этого было две попытки написать редактор — на чистом API и NET, то опыт есть и срок реален.
0rc>Сколько, сколько? Да при таких темпах мы давно бы жили на Марсе!
Да! Я живу в одной жопе и работаю в другой жопе, тратя каждый день по 60 рублей на поездку из одной жопы в другую. Ни в одной из этих жоп нет нормального места, где можно проявить свои мозги. Вот и пишу все подряд, чтобы мозги не скисли и не думать, что тебе уже 26 и помирать скоро.
Re[6]: По порядку - std::string
От: 0rc Украина  
Дата: 20.09.06 09:32
Оценка:
Здравствуйте, denaturat, Вы писали:

D>Предлагаете то же самое, только вместо массива — список. Может, std::list и лучше std::vector, но принципиальной разницы не вижу


Я предлагаю не одно и тоже, я предлагаю использовать list вместо(!) vector. Посколько именно функциональность list подразумевает частую вставку и удаление.
Re[7]: По порядку - std::string
От: denaturat  
Дата: 20.09.06 09:46
Оценка: :)
Здравствуйте, 0rc, Вы писали:

0rc>Я предлагаю не одно и тоже, я предлагаю использовать list вместо(!) vector. Посколько именно функциональность list подразумевает частую вставку и удаление.


Тут согласен.
Только речь изначально шла о замене сплошного текстового буфера на совокупность строк, а принципиального различия не вижу — ибо и то и другое — есть совокупность.
То что list быстрее — это вопросы оптимизации, о которой речи вроде, не было.
ЗЫ. Об оптимизации думаю только после решения вопроса: а ее надо. Если да — то начинаю оптимизировать. Для начала стараюсь быть проще.
Re[5]: Реализация редактора
От: eaglus Россия  
Дата: 20.09.06 12:55
Оценка: 17 (2) +2
Здравствуйте, Praetor, Вы писали:

P>denaturat, спасибо за советы, учту. По поводу хранения символов — конечно, я не буду использовать единый буфер, это ведь плохо не только из-за того, что происходит сплошное перелопаичвание при вставке символа, от этого страдает в первую очередь дизайн программы.



Буфер с дыркой (gap-ом) рулит! Он лежит одним блоком, оверхедов по памяти никаких (как в случае массива строчек), переаллокации редки при вставках-удалениях в одном месте, а если в разных местах, то они часто заменяются копированием блоков внутри буфера при перемещении "дырки".
Вот книжка про Емакс, и его внутреннее устройство
Уж на скорость Емакса-то вряд ли кто пожалуется. Это классика.
А вот про буфер с дыркой в Емаксе

Точно так же сделан буфер в Сцинтилле, Джедите, и Эклипсе.
Я это специально копал.

А вот про буфер для очень больших текстов:
An Efficient Data Structure For A Hex Editor
Там файл разбивается на блоки-странички, при просмотре ты работаешь прямо с файлом, память не тратится, а когда редактируешь какое-то место, то соответствующая страничка загружается.
На закрытии файла все странички сливаются во временный, потом исходный заменяется.
В Виме примерно так сделано.
Правда, если кто-то другой изменит твой файл, пока ты его редактируешь... Опаньки.
Вим шибко ругается на одновременное редактирование файлов.
Но это особый случай, для мегафайлов, так что можно файл просто залочить, и не давать другим его трогать, пока ты его меняешь.

P>А при отрисовке символов (с двойной буферизацией) придется пользоваться напрямую апи функциями, т к wxWidgets, который я использую, я почти не знаю (третий день с ним).


А чего там знать? Документация — лучше только у QT. Рисование текста везде примерно одинаковое...
Зато кроссплатформенность будет, да и API у wxWin проще маздайного.

Ну и вот ещё статеек до кучи:

Вот хорошая:
Data Structures in the Andrew Text Editor

Эта так себе:
Text Editors: Algorithms and Architectures
Re[6]: Реализация редактора
От: eaglus Россия  
Дата: 20.09.06 12:59
Оценка:
Здравствуйте, eaglus, Вы писали:

E>Здравствуйте, Praetor, Вы писали:


P>>denaturat, спасибо за советы, учту. По поводу хранения символов — конечно, я не буду использовать единый буфер, это ведь плохо не только из-за того, что происходит сплошное перелопаичвание при вставке символа, от этого страдает в первую очередь дизайн программы.



E>Буфер с дыркой (gap-ом) рулит! Он лежит одним блоком, оверхедов по памяти никаких (как в случае массива строчек), переаллокации редки при вставках-удалениях в одном месте, а если в разных местах, то они часто заменяются копированием блоков внутри буфера при перемещении "дырки".

E>Вот книжка про Емакс, и его внутреннее устройство
E>Уж на скорость Емакса-то вряд ли кто пожалуется. Это классика.
E>А вот про буфер с дыркой в Емаксе

E>Точно так же сделан буфер в Сцинтилле, Джедите, и Эклипсе.

E>Я это специально копал.

Да, вот ещё: строчки в этом способе хранятся просто в векторе интов (их концы).
При изменениях в буфере вектор концов строчек корректируется..
Это вообще просто.
Re[7]: Реализация редактора
От: eaglus Россия  
Дата: 20.09.06 13:02
Оценка:
E>Да, вот ещё: строчки в этом способе хранятся просто в векторе интов (их концы).
E>При изменениях в буфере вектор концов строчек корректируется..
E>Это вообще просто.

И с закладками (метками) такая же фигня.
Причём, метку можно делать не на строчку, а именно как пару: смещение в тексте — длина.
То есть, метка может пересекать границы строчек.
Такие метки удобны для подсветки найденного текста, да и вообще, зело универсальны.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.